openid4java ConsumerManager request/thread safe? - web-services

I am using openid4java in servlets. I have two servlets - one which performs first step (redirects user to login/accept application access) and second, which processes resulting information
In the documentation, there is written, that org.openid4java.consumer.ConsumerManager class must be the same instance in both steps. Can I create singleton for that? Is it thread and request safe?
Thanks for your replies!

In the consumer servlet from official openid4java sample it seems that ConsumerManager is thread safe - they use single ConsumerManager instance for all sessions. I use it this way too and have not noticed any strange behaviour yet. But a javadoc statement about thread-safety from the developers would be great...

//Currently only working with google only
// Try this - this is all ine one..
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//import org.jboss.web.tomcat.security.login.WebAuthentication;
import org.openid4java.OpenIDException;
import org.openid4java.consumer.ConsumerException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.AuthSuccess;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.AxMessage;
import org.openid4java.message.ax.FetchRequest;
import org.openid4java.message.ax.FetchResponse;
public class OpenAuth extends javax.servlet.http.HttpServlet {
final static String YAHOO_ENDPOINT = "https://me.yahoo.com";
final static String GOOGLE_ENDPOINT = "https://www.google.com/
accounts/o8/id";
//Updated version of example code from :
https://crisdev.wordpress.com/2011/03/23/openid4java-login-example/
//Add your servlet script path here - so if auth fails or
succeeds it will carry out actions - check below in doGet
public String scr="/servlets/MyServlet";
private ServletContext context;
private ConsumerManager manager;
private ConsumerManager mag;
//Code updated by Vahid Hedayati http://pro.org.uk
//Removed config init - moved post to doGet - since previous code
required it to be a post but also to include identifier as part of
url
//identifier was also the same variable used for Identifier code -
//cleaned up to make different variable and less confusion
//doGet identifer changed to openid_identifier and it also now looks
for openid_username which are the default variables returned from
openid-selector
//http://groups.google.com/group/openid4java/browse_thread/thread/
5e8f24f51f54dc2c
//After reading above post - store the manager in the session object
and failing with Yahoo authentication I changed code for the manager
//manage
public void doPost(HttpServletRequest req,HttpServletResponse
response) throws ServletException,IOException {
doGet(req, response);
}
protected void doGet(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
//New variable
String ouser=(String)req.getParameter("openid_username");
if (ouser==null) { ouser="";}
//Mage is the session value of openid_consumer_manager if it is
null it will generate it once
//And where ever manager is called within code it first returns
managers value by looking up session value
mag=(ConsumerManager)req.getSession().getAttribute("open_id_consumer_manager");
if (mag==null) {
this.manager = new ConsumerManager();
req.getSession().setAttribute("open_id_consumer_manager", manager);
}
String identify=(String)req.getParameter("openid_identifier");
if (identify==null) { identify="";}
if (!identify.equals("")) {
this.authRequest(identify,ouser, req, resp);
}else{
//If they have succeeded it will return them to welcome
//welcome looks up if NEWUSER = yes in the session value below
and if so
//scr now has the ip city/country/postcode so it finalises
user additiion by adding users ip country/city/ip as their sign up
// if not new well they are already logged in from the
relevant session values this code has put in so updats records and
returns they my accoount
//if authentication here failed or they rejected sharing their
email then login page is returned
Identifier identifier = this.verifyResponse(req);
if (identifier != null) {
resp.sendRedirect(scr+"?act=welcome");
} else {
resp.sendRedirect(scr+"?act=login");
}
}
}
// --- placing the authentication request ---
public String authRequest(String userSuppliedString,String Ouser,
HttpServletRequest httpReq, HttpServletResponse httpResp) throws
IOException {
try {
// configure the return_to URL where your application will
receive
// the authentication responses from the OpenID provider
String returnToUrl = httpReq.getRequestURL().toString();
// --- Forward proxy setup (only if needed) ---
// ProxyProperties proxyProps = new ProxyProperties();
// proxyProps.setProxyName("proxy.example.com");
// proxyProps.setProxyPort(8080);
// HttpClientFactory.setProxyProperties(proxyProps);
// perform discovery on the user-supplied identifier
//Modified - Look up manager value from session
manager = (ConsumerManager)
httpReq.getSession().getAttribute("open_id_consumer_manager");
List discoveries = manager.discover(userSuppliedString);
// attempt to associate with the OpenID provider
// and retrieve one service endpoint for authentication
DiscoveryInformation discovered =
manager.associate(discoveries);
// store the discovery information in the user's session
httpReq.getSession().setAttribute("openid-disc", discovered);
// obtain a AuthRequest message to be sent to the OpenID
provider
AuthRequest authReq = manager.authenticate(discovered,
returnToUrl);
FetchRequest fetch = FetchRequest.createFetchRequest();
if (userSuppliedString.startsWith(GOOGLE_ENDPOINT)) {
fetch.addAttribute("email", "http://axschema.org/
contact/email", true);
fetch.addAttribute("firstName", "http://axschema.org/
namePerson/first", true);
fetch.addAttribute("lastName", "http://axschema.org/
namePerson/last", true);
} else if (userSuppliedString.startsWith(YAHOO_ENDPOINT)) {
fetch.addAttribute("email", "http://axschema.org/
contact/email", true);
fetch.addAttribute("fullname", "http://axschema.org/
namePerson", true);
} else {
// works for myOpenID
fetch.addAttribute("fullname", "http://
schema.openid.net/namePerson", true);
fetch.addAttribute("email", "http://schema.openid.net/
contact/email", true);
}
httpReq.getSession().setAttribute("Ouser",Ouser);
// attach the extension to the authentication request
authReq.addExtension(fetch);
httpResp.sendRedirect(authReq.getDestinationUrl(true));
} catch (OpenIDException e) {
// present error to the user
}
return null;
}
// --- processing the authentication response ---
public Identifier verifyResponse(HttpServletRequest httpReq) {
try {
// extract the parameters from the authentication response
// (which comes in as a HTTP request from the OpenID provider)
ParameterList response = new
ParameterList(httpReq.getParameterMap());
// retrieve the previously stored discovery information
DiscoveryInformation discovered = (DiscoveryInformation)
httpReq.getSession().getAttribute("openid-disc");
// extract the receiving URL from the HTTP request
StringBuffer receivingURL = httpReq.getRequestURL();
String queryString = httpReq.getQueryString();
if (queryString != null && queryString.length() > 0)
receivingURL.append("?").append(httpReq.getQueryString());
// verify the response; ConsumerManager needs to be the same
// (static) instance used to place the authentication request
//Modified - look up session value before running verification
result
manager = (ConsumerManager)
httpReq.getSession().getAttribute("open_id_consumer_manager");
VerificationResult verification =
manager.verify(receivingURL.toString(), response, discovered);
// examine the verification result and extract the verified
// identifier
Identifier verified = verification.getVerifiedId();
String id=verified.getIdentifier();
if (verified != null) {
AuthSuccess authSuccess = (AuthSuccess)
verification.getAuthResponse();
if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)) {
FetchResponse fetchResp = (FetchResponse)
authSuccess.getExtension(AxMessage.OPENID_NS_AX);
List emails =
fetchResp.getAttributeValues("email");
String email = (String) emails.get(0);
////////////////////////////////////////////////////////////////////////////////
//Custom bit each person needs to implement to
interact with their application:
//Authenticate the user, send email verify if
user exists on local system
//If it does {
//
httpReq.getSession().setAttribute("USERNAME",usern);
httpReq.getSession().setAttribute("LOGGEDIN", "on");
//}else{
String firstName =
fetchResp.getAttributeValue("firstName");
String lastName =
fetchResp.getAttributeValue("lastName");
String
fullname=fetchResp.getAttributeValue("fullname");
if (fullname==null)
{fullname="";}
if (firstName==null)
{ firstName="";}
if (lastName==null) { lastName="";}
if (!fullname.equals("")) {
if (fullname.indexOf(",")>-1)
{
firstName=fullname.substring(0,fullname.indexOf(","));
lastName=fullname.substring(fullname.indexOf(","),fullname.length());
}else if (fullname.indexOf("
")>-1){
firstName=fullname.substring(0,fullname.indexOf(" "));
lastName=fullname.substring(fullname.indexOf(" "),fullname.length());
}
}
//This is username returned
from the various services that ask for a username - it is returned as
openid_username
//When using openid-selector it uses
openid_identifier and openid_username - which is what this program now
looks for
String
ouser=(String)httpReq.getSession().getValue("Ouser");
if (ouser==null) {ouser="";}
//Adduser -- pass email address and
ouser
//In Adduser class - if ouser is blank
split email from 0 to substring.indexOf("#")
// generate a random number - look up
current user - if exist add random number to end
//and add user with email and new
username
//return bac the newuser and log in
like above.
httpReq.getSession().setAttribute("NEWUSER","YES");
//
httpReq.getSession().setAttribute("USERNAME",usern);
httpReq.getSession().setAttribute("LOGGEDIN", "on");
//}
return verified; // success
}
}
} catch (OpenIDException e) {
// present error to the user
}
return null;
}

Related

Creating Internal Accounts in SAS Metadata Server by programm on SAS Base

I'm trying to create Internal Accounts programmaticaly by using proc metadata.
The code section below creates person with External Login.
put"<Person Name=%str(%')&&PersonName&i.%str(%')>";
put"<Logins>";
put"<Login Name=%str(%')Login.&&PersonName&i.%str(%') Password=%str(%')&&word&i.%str(%')/>";
put"</Logins>";
put"</Person>";
To create ExternalLogin we can set attribute Password, and in SAS Metadata it will be encrypted automaticaly.
But to create InternalLogin type of object it is necessary to make the hash value of the password and the salt. I know that the standard sas002 encryption method, but in the case of using proc pwencode how to obtain the value of salt?
Is it possible create InternalLogin by using SAS Base?
Thanx.
So on. I found an article that can tell us how to create Stored Process for this problem. My answer is addition to the article.
The approach is base on execute java methods from sas programm.
1. Prerare setPasswd.java class
I've modified class from article. Separate code to connect to metadata server and create InternalLogin
import java.rmi.RemoteException;
import com.sas.metadata.remote.AssociationList;
import com.sas.metadata.remote.CMetadata;
import com.sas.metadata.remote.Person;
import com.sas.metadata.remote.MdException;
import com.sas.metadata.remote.MdFactory;
import com.sas.metadata.remote.MdFactoryImpl;
import com.sas.metadata.remote.MdOMIUtil;
import com.sas.metadata.remote.MdOMRConnection;
import com.sas.metadata.remote.MdObjectStore;
import com.sas.metadata.remote.MetadataObjects;
import com.sas.metadata.remote.PrimaryType;
import com.sas.metadata.remote.Tree;
import com.sas.meta.SASOMI.ISecurity_1_1;
import com.sas.iom.SASIOMDefs.VariableArray2dOfStringHolder;
public class setPasswd {
String serverName = null;
String serverPort = null;
String serverUser = null;
String serverPass = null;
MdOMRConnection connection = null;
MdFactoryImpl _factory = null;
ISecurity_1_1 iSecurity = null;
MdObjectStore objectStore = null;
Person person = null;
public int connectToMetadata(String name, String port, String user, String pass){
try {
serverName = name;
serverPort = port;
serverUser = user;
serverPass = pass;
_factory = new MdFactoryImpl(false);
connection = _factory.getConnection();
connection.makeOMRConnection(serverName, serverPort, serverUser, serverPass);
iSecurity = connection.MakeISecurityConnection();
return 0;
}catch(Exception e){
return 1;
}
}
public setPasswd(){};
public int changePasswd(String IdentityName, String IdentityPassword) {
try
{
//
// This block obtains the person metadata ID that is needed to change the password
//
// Defines the GetIdentityInfo 'ReturnUnrestrictedSource' option.
final String[][] options ={{"ReturnUnrestrictedSource",""}};
// Defines a stringholder for the info output parameter.
VariableArray2dOfStringHolder info = new VariableArray2dOfStringHolder();
// Issues the GetInfo method for the provided iSecurity connection user.
iSecurity.GetInfo("GetIdentityInfo","Person:"+IdentityName, options, info);
String[][] returnArray = info.value;
String personMetaID = new String();
for (int i=0; i< returnArray.length; i++ )
{
System.out.println(returnArray[i][0] + "=" + returnArray[i][1]);
if (returnArray[i][0].compareTo("IdentityObjectID") == 0) {
personMetaID = returnArray[i][1];
}
}
objectStore = _factory.createObjectStore();
person = (Person) _factory.createComplexMetadataObject(objectStore, IdentityName, MetadataObjects.PERSON, personMetaID);
iSecurity.SetInternalPassword(IdentityName, IdentityPassword);
person.updateMetadataAll();
System.out.println("Password has been changed.");
return 0; // success
}
catch (MdException e)
{
Throwable t = e.getCause();
if (t != null)
{
String ErrorType = e.getSASMessageSeverity();
String ErrorMsg = e.getSASMessage();
if (ErrorType == null)
{
// If there is no SAS server message, write a Java/CORBA message.
}
else
{
// If there is a message from the server:
System.out.println(ErrorType + ": " + ErrorMsg);
}
if (t instanceof org.omg.CORBA.COMM_FAILURE)
{
// If there is an invalid port number or host name:
System.out.println(e.getLocalizedMessage());
}
else if (t instanceof org.omg.CORBA.NO_PERMISSION)
{
// If there is an invalid user ID or password:
System.out.println(e.getLocalizedMessage());
}
}
else
{
// If we cannot find a nested exception, get message and print.
System.out.println(e.getLocalizedMessage());
}
// If there is an error, print the entire stack trace.
e.printStackTrace();
}
catch (RemoteException e)
{
// Unknown exception.
e.printStackTrace();
}
catch (Exception e)
{
// Unknown exception.
e.printStackTrace();
}
System.out.println("Failure: Password has NOT been changed.");
return 1; // failure
}
}
2. Resolve depends
Pay attention to imports in class. To enable execute the code below necessary set CLASSPATH enironment variable.
On linux you can add the next command in %SASConfig%/Lev1/level_env_usermods.sh:
export CLASSPATH=$CLASSPATH:%pathToJar%
On Windows you can add/change environment variable by Advanced system settings
So where should you search jar files? They are in folder:
%SASHome%/SASVersionedJarRepository/eclipse/plugins/
Which files i should include in path?
I've include all that used in OMI(Open Metadata Interface).Also I've added log4j.jar (not working without this jar. Your promts will be helpful):
sas.oma.joma.jar
sas.oma.joma.rmt.jar
sas.oma.omi.jar
sas.svc.connection.jar
sas.core.jar
sas.entities.jar
sas.security.sspi.jar
log4j.jar
setPasswd.jar (YOUR JAR FROM THE NEXT STEP!)
Choose files from nearest release. Example:
Here I'm set file from v940m3f (fix release).
Other ways is here.
3. Compile setPasswd.jar
I'm tried use internal javac.exe into SAS, but it's not worked properly. So ou need to download JDK to compile jars. I've create Bat-file:
"C:\Program Files\Java\jdk1.8.0_121\bin\javac.exe" -source 1.7 -target 1.7 setPasswd.java
"C:\Program Files\Java\jdk1.8.0_121\bin\jar" -cf setPasswd.jar setPasswd.class
Paramethers -source and -target will helpful if your version of JDK is upper, that usses in SAS. Version of "sas"-java you can see by:
PROC javainfo all;
run;
Search the next string in log:
java.vm.specification.version = 1.7
4. Finally. SAS Base call
Now we can call Java code by this method (All methods available here):
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "%SERVER%", "%PORT%", "%ADMIN%", "%{SAS002}HASHPASSORPASS%", rc1);
j.callIntMethod("changePasswd", "testPassLogin", "pass1", rc2);
j.delete();
run;
In log:
UserClass=Normal
AuthenticatedUserid=Unknown
IdentityName=testPass
IdentityType=Person
IdentityObjectID=A56RQPC2.AP00000I
Password has been changed.
Now time to test. Create new user with no passwords.
Execute code:
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "&server.", "&port.", "&adm", "&pass", rc1);
j.callIntMethod("changePasswd", "TestUserForStack", "Overflow", rc2);
j.delete();
run;
Now our user has InternalLogin object.
Thanx.

Unable to use http connector

I'm trying to use the http connector that is provided with the standard Camunda implementation with no luck. Every single time that I run my workflow the instance simply freeze on that activity. I'm using this class in an execution listnener and the code that I'm using is this:
import org.apache.ibatis.logging.LogFactory;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.Expression;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.camunda.bpm.engine.impl.util.json.JSONObject;
import org.camunda.connect.Connectors;
import org.camunda.connect.ConnectorException;
import org.camunda.connect.httpclient.HttpConnector;
import org.camunda.connect.httpclient.HttpResponse;
import org.camunda.connect.httpclient.impl.HttpConnectorImpl;
import org.camunda.connect.impl.DebugRequestInterceptor;
public class APIAudit implements JavaDelegate {
static {
LogFactory.useSlf4jLogging(); // MyBatis
}
private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(Thread.currentThread().getStackTrace()[0].getClassName());
private Expression tokenField;
private Expression apiServerField;
private Expression questionIDField;
private Expression subjectField;
private Expression bodyField;
public void execute(DelegateExecution arg0) throws Exception {
String tokenValue = (String) tokenField.getValue(arg0);
String apiServerValue = (String) apiServerField.getValue(arg0);
String questionIDValue = (String) questionIDField.getValue(arg0);
String subjectValue = (String) subjectField.getValue(arg0);
String bodyValue = (String) bodyField.getValue(arg0);
if (apiServerValue != null) {
String url = "http://" + apiServerValue + "/v1.0/announcement";
LOGGER.info("token: " + tokenValue);
LOGGER.info("apiServer: " + apiServerValue);
LOGGER.info("questionID: " + questionIDValue);
LOGGER.info("subject: " + subjectValue);
LOGGER.info("body: " + bodyValue);
LOGGER.info("url: " + url);
JSONObject jsonBody = new JSONObject();
jsonBody.put("access_token", tokenValue);
jsonBody.put("source", "SYSTEM");
jsonBody.put("target", "AUDIT");
jsonBody.put("tType", "system");
jsonBody.put("aType", "auditLog");
jsonBody.put("affectedItem", questionIDValue);
jsonBody.put("subject", subjectValue);
jsonBody.put("body", bodyValue);
jsonBody.put("language", "EN");
try {
LOGGER.info("Generating connection");
HttpConnector http = Connectors.getConnector(HttpConnector.ID);
LOGGER.info(http.toString());
DebugRequestInterceptor interceptor = new DebugRequestInterceptor(false);
http.addRequestInterceptor(interceptor);
LOGGER.info("JSON Body: " + jsonBody.toString());
HttpResponse response = http.createRequest()
.post()
.url(url)
.contentType("application/json")
.payload(jsonBody.toString())
.execute();
Integer responseCode = response.getStatusCode();
String responseBody = response.getResponse();
response.close();
LOGGER.info("[" + responseCode + "]: " + responseBody);
} catch (ConnectorException e) {
LOGGER.severe(e.getMessage());
}
} else {
LOGGER.info("No APISERVER provided");
}
LOGGER.info("Exiting");
}
}
I'm sure that the fields injection works correctly since the class prints the correct values. I also used the http-connector in javascript in the same activity with no problem.
I'm using this approach since I need to make two different calls to external REST services in the same task, so any advice will be very welcome.
You need to enable Connect process engine plugin in process engine configuration. Not sure how you configured the process engine, make sure to add this plugin org.camunda.connect.plugin.impl.ConnectProcessEnginePlugin
Also check the following in dependencies
Do not add both dependencies - connectors-all and http-connector.
Make sure to check the error logs and see whether you have any class loading problem related to httpclient classes
I am pretty sure there is a class loading issue with http client library. make sure to include the correct version of connectors-all dependency

How to test Web.API method with RestSharp passing in ClaimsPrincipal

I'm having a bit of trouble with a specific implementation of testing out my Web.API methods using RestSharp. I have been very successful in performing POSTS and GETS in my open (non-secured) methods. However, when I have to send in a token to determine access I have problems.
Here is the implementation:
I am using OWIN middleware for my Web.API. The client must post to a token service in order to get the given Token that contains their claims. All of this has been working fine.
In my test my Initializer has the following code that posts to the token service and gets back the token. This works wonderfully - returns back the token as advertised:
[TestInitialize]
public void SetupTest()
{
_verificationErrors = new StringBuilder();
_client = new RestClient
{
BaseUrl = new Uri(ConfigurationManager.AppSettings["ServicesBaseUrl"])
};
_serviceRequestPrepender = ConfigurationManager.AppSettings["ServiceRequestPrepender"];
// Initialize this by getting the user token put back for all of the tests to use.
var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, ConfigurationManager.AppSettings["TokenEndpointPath"]), Method.POST);
// Add header stuff
request.AddParameter("Content-Type", "application/x-www-form-urlencoded", ParameterType.HttpHeader);
request.AddParameter("Accept", "application/json", ParameterType.HttpHeader);
// Add request body
_userName = "{test student name}";
_password = "{test student password}";
_userGuid = "{this is a guid value!!}";
_clientIdentifier = ConfigurationManager.AppSettings["ClientIdentifier"];
_applicationId = ConfigurationManager.AppSettings["ApplicationId"];
string encodedBody = string.Format("grant_type=password&username={0}&password={1}&scope={2} {3} {4} {0}"
, _userName, _password, _clientIdentifier, _userGuid, _applicationId);
request.AddParameter("application/x-www-form-urlencoded", encodedBody, ParameterType.RequestBody);
// execute the request
IRestResponse response = _client.Execute(request);
// Make sure everything is working as promised.
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsTrue(response.ContentLength > 0);
_token = new JavaScriptSerializer().Deserialize<Token>(response.Content).access_token;
}
Next is the following code that calls a Web.API method which passes the given token along to another Web.API method where I'm performing a GET to extract some information from my service.
[TestMethod]
public void GetUserProfileTest()
{
// Arrange
var request = new RestRequest(string.Format("{0}{1}", _serviceRequestPrepender, "api/UserProfiles/UserProfiles/Get/{appId}/{userId}/{username}"), Method.GET);
// Add header stuff
request.AddParameter("Content-Type", "application/json", ParameterType.HttpHeader);
request.AddParameter("Accept", "/application/json", ParameterType.HttpHeader);
request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token));
request.AddUrlSegment("appId", "1");
request.AddUrlSegment("userId", _userGuid);
request.AddUrlSegment("username", _userName);
// execute the request
IRestResponse response = _client.Execute(request);
// Make sure everything is working as promised.
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsTrue(response.ContentLength > 0); // do more when working
}
Next, the service is called, but I have decorated the Web.API method with a custom access security check. This is a VERY simple security check in that it only checks to see if the token is valid and not expired. Here is the IsAuthorized method of that attribute:
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// Custom Code here
return ValidityChecker.IsTokenValid(actionContext);
}
The ValidityChecker is a simple class that only checks to see if the token is valid:
public class TokenValidityChecker
{
public ClaimsPrincipal PrincipalWithClaims { get; private set; }
/// <summary>
/// Extracts out the ability to perform token checking since all Token checking attributes will need t his.
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
public bool IsTokenValid(System.Web.Http.Controllers.HttpActionContext actionContext)
{
bool result = false;
var principal = actionContext.RequestContext.Principal;
if (principal.GetType() == typeof(ClaimsPrincipal))
{
PrincipalWithClaims = (ClaimsPrincipal)principal;
result = PrincipalWithClaims.Identity.IsAuthenticated;
}
// Custom Code here
return result;
}
}
So, with the background in place - here is the question. As you can see, normally, when the service is called the ValidityChecker will receive an HttpActionContext. Along with that, the RequestContext.Principal of that HttpActionContext will normally be of type ClaimsPrincipal.
However, when running from a unit test and using RestSharp it is, of course, a WindowsPrincipal.
Is there a way using RestSharp to make that a ClaimsPrincipal? I've tried to ensure the token is included in the header using the Authorization parameter, but have not had any luck.
Well - If I would simply read the details of my own code I could have completed this long ago.
The answer was VERY simple. The code in the question adds the token to the parameters, but does not annotate it as HttpHeader. I forgot to put that into the method call. Here is the line that fixed it:
request.AddParameter("Authorization", string.Format("{0} {1}", "Bearer", _token), ParameterType.HttpHeader);
The "ParameterType.HttpHeader" in the method call did the trick.

WSO2 MessageBroker:Throwing org.wso2.andes.AMQTimeoutException error when creating durable subscriber

I have a code that acts as my subscriber. I have created durable subscriber. So due to this i am getting exception as
Exception in thread "main" javax.jms.JMSException: Error registering consumer: org.wso2.andes.AMQTimeoutException: Server did not respond in a timely fashion [error code 408: Request Timeout]
at org.wso2.andes.client.AMQSession$4.execute(AMQSession.java:2054)
at org.wso2.andes.client.AMQSession$4.execute(AMQSession.java:1997)
at org.wso2.andes.client.AMQConnectionDelegate_8_0.executeRetrySupport(AMQConnectionDelegate_8_0.java:305)
at org.wso2.andes.client.AMQConnection.executeRetrySupport(AMQConnection.java:621)
at org.wso2.andes.client.failover.FailoverRetrySupport.execute(FailoverRetrySupport.java:102)
at org.wso2.andes.client.AMQSession.createConsumerImpl(AMQSession.java:1995)
at org.wso2.andes.client.AMQSession.createConsumer(AMQSession.java:993)
at org.wso2.andes.client.AMQSession.createDurableSubscriber(AMQSession.java:1142)
at org.wso2.andes.client.AMQSession.createDurableSubscriber(AMQSession.java:1042)
at org.wso2.andes.client.AMQTopicSessionAdaptor.createDurableSubscriber(AMQTopicSessionAdaptor.java:73)
at xml.parser.Parser.subscribe(Parser.java:62)
at xml.parser.Parser.main(Parser.java:34)
But instead od durable when i create normal Subscriber, My code run good and there is no error. Why i am getting this error?
And one more question-How can i unsubscribe from the topic?
My code for Subscriber is:
package xml.parser;
import org.w3c.dom.*;
import javax.xml.xpath.*;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.*;
import java.io.IOException;
import org.xml.sax.SAXException;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;
public class Parser {
public static final String QPID_ICF = "org.wso2.andes.jndi.PropertiesFileInitialContextFactory";
private static final String CF_NAME_PREFIX = "connectionfactory.";
private static final String CF_NAME = "qpidConnectionfactory";
String userName = "admin";
String password = "admin";
private static String CARBON_CLIENT_ID = "carbon";
private static String CARBON_VIRTUAL_HOST_NAME = "carbon";
private static String CARBON_DEFAULT_HOSTNAME = "localhost";
private static String CARBON_BROKER_PORT = "5673";
String topicName = "myTopic";
public static void main(String[] args) throws NamingException,
JMSException, XPathExpressionException,
ParserConfigurationException, SAXException, IOException {
Parser queueReceiver = new Parser();
String message = queueReceiver.subscribe();
System.out.println("Got message from Queue ==> " + message);
}
public String subscribe() throws NamingException, JMSException {
String messageContent = "";
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, QPID_ICF);
properties.put(CF_NAME_PREFIX + CF_NAME,
getTCPConnectionURL(userName, password));
properties.put("topic." + topicName, topicName);
System.out.println("getTCPConnectionURL(userName,password) = "
+ getTCPConnectionURL(userName, password));
InitialContext ctx = new InitialContext(properties);
// Lookup connection factory
TopicConnectionFactory connFactory = (TopicConnectionFactory) ctx
.lookup(CF_NAME);
TopicConnection topicConnection = connFactory.createTopicConnection();
topicConnection.start();
TopicSession topicSession = topicConnection.createTopicSession(false,
QueueSession.AUTO_ACKNOWLEDGE);
// Send message
// Topic topic = topicSession.createTopic(topicName);
Topic topic = (Topic) ctx.lookup(topicName);
javax.jms.TopicSubscriber topicSubscriber = topicSession
.createDurableSubscriber(topic,"topicQueue");
Message message = topicSubscriber.receive();
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("textMessage.getText() = "
+ textMessage.getText());
messageContent = textMessage.getText();
}
topicSubscriber.close();
topicSession.close();
topicConnection.stop();
topicConnection.close();
return messageContent;
}
public String getTCPConnectionURL(String username, String password) {
return new StringBuffer().append("amqp://").append(username)
.append(":").append(password).append("#")
.append(CARBON_CLIENT_ID).append("/")
.append(CARBON_VIRTUAL_HOST_NAME).append("?brokerlist='tcp://")
.append(CARBON_DEFAULT_HOSTNAME).append(":")
.append(CARBON_BROKER_PORT).append("'").toString();
}
}
This is an issue in the MB 2.0.1 distribution with the durable subscribers. The reason for this is when the Parser class first runs, receives a message, and the subscriber is stopped, then when you start the Parser for the second time, it fails to starts the subscription back as the previous 'subscriber' entry is still there, and you will see the following in the terminal.The client will be timed out after few tries which is why you get the error log.
[2013-04-22 12:12:52,617] INFO {org.wso2.andes.server.protocol.AMQProtocolEngine} - Closing channel due to: Cannot subscribe to queue carbon:topicQueue as it already has an existing exclusive consumer
[2013-04-22 12:12:52,621] INFO {org.wso2.andes.server.protocol.AMQProtocolEngine} - Channel[1] awaiting closure - processing close-ok
[2013-04-22 12:12:52,621] INFO {org.wso2.andes.server.handler.ChannelCloseOkHandler} - Received channel-close-ok for channel-id 1
This issue has been fixed in MB 2.1.0 release which is expected to be out in the coming weeks. If you need please try your sample subscriber with MB 2.1.0 - Alpha version from here. This should work fine with that pack.
About unsubscribing from a topic add the following line into your Parser code and run back when you need to unsubscribe.
topicSubscriber.close();
**topicSession.unsubscribe("topicQueue"); // add the name used to identify the subscription in the place of "topicQueue"**
topicSession.close();
topicConnection.stop();
topicConnection.close();

How to send additional fields to soap handler along with soapMessage?

I am logging RequestXML for a webservice client using SoapHandler as follows
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean)
smc.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
out.println("\nOutbound message:");
} else {
out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
message.writeTo(out);
out.println("");
} catch (Exception e) {
out.println("Exception in handler: " + e);
}
}
Got a new requirenment to add this xml to DB along with some extra values(which are not present in the xml). Is there any way I can pass few additional fields to above soap handler (in handleMessage method)?
Please note that changing the xml/WSDL or adding this to SOAP message header is not an option for me as it is owned by other interface. Any other solution?
Thanks!
You can cast your service class to a class of type "BindingProvider". In this form you can use it to assign it objects which you can access later from your SOAPHandler. Another useful usage is that you also can change the endPoint URL this way.
Before calling the service you do:
MySoapServicePortType service = new MySoapService().getMySoapServicePort();
BindingProvider bp = (BindingProvider)service;
MyTransferObject t = new MyTransferObject();
bp.getRequestContext().put("myTransferObject", t);
TypeResponse response = service.doRequest();
SOAPMessage message = t.getRequestMessage(message);
From your logging function you do:
private void logToSystemOut(SOAPMessageContext smc) {
...
MyTransferObject t = (MyTransferObject) messageContext.get("myTransferObject");
if (outboundProperty.booleanValue())
t.setRequestMessage(message);
else
t.setResponseMessage(message);
...
}