1. Differentiating between SOAP Versions by Looking at a SOAP Message
2. What's New in SOAP 1.2?
<service name="SimpleService" scope="application">
<operation name="echo">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<!-- parameter name="ServiceClass" locked="false">org.apache.ws.axis2.SimpleService</parameter -->
<parameter name="ServiceObjectSupplier" locked="false">org.apache.ws.axis2.SimpleServiceSupplier</parameter>
</service>
package org.apache.ws.axis2;
import org.apache.axis2.description.AxisService;
public class SimpleServiceSupplier {
public static SimpleService getServiceObject(AxisService service) {
return new SimpleService();
}
}
<service name="SimpleService" class="org.apache.ws.axis2.SimpleService" scope="application">
<operation name="echo">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<parameter name="ServiceClass" locked="false">org.apache.ws.axis2.SimpleService</parameter>
</service>
package org.apache.ws.axis2;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.engine.ServiceLifeCycle;
import org.apache.axis2.service.Lifecycle;
/**
* The service implementation class
*/
public class SimpleService implements ServiceLifeCycle, Lifecycle {
/**
* This is called when a new instance of the implementing class has been created.
* This occurs in sync with session/ServiceContext creation. This method gives classes
* a chance to do any setup work (grab resources, establish connections, etc) before
* they are invoked by a service request.
*/
public void init(ServiceContext serviceContext) throws AxisFault {
System.out.println("Lifecycle:::init()");
}
/**
* This is called when Axis2 decides that it is finished with a particular instance
* of the back-end service class. It allows classes to clean up resources.
*/
public void destroy(ServiceContext serviceContext) {
System.out.println("Lifecycle:::destroy()");
}
/**
* This will be called during the deployment time of the service.
* Irrespective of the service scope this method will be called
*/
public void startUp(ConfigurationContext configctx, AxisService service) {
System.out.println("ServiceLifeCycle:::startUp()");
}
/**
* This will be called during the system shut down time. Irrespective
* of the service scope this method will be called
*/
public void shutDown(ConfigurationContext configctx, AxisService service) {
System.out.println("ServiceLifeCycle:::shutDown()");
}
/**
* The echo method which will be exposed as the echo operation of the web
* service
*/
public String echo(String value) {
return value;
}
}
import java.net.URL;
import java.security.cert.Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public static Certificate readSSLCertFromUrl(String url) throws Exception {
URL hostURL = null;
String hostname = null;
int port;
SSLSocketFactory factory = null;
SSLSocket socket = null;
try {
hostURL = new URL(url);
hostname = hostURL.getHost();
// Check whether the url has a port stated explicitly. If its not present default to 443
port = hostURL.getPort();
if (port == -1) {
port = 443;
}
// Gets the default static SSLSocketFactory that is inherited by new instances of this
// class.
// The socket factories are used when creating sockets for secure https URL connections.
factory = HttpsURLConnection.getDefaultSSLSocketFactory();
// Creates a socket and connects it to the specified remote host at the specified remote
// port. This socket is configured using the socket options established for this
// factory.
socket = (SSLSocket) factory.createSocket(hostname, port);
// Starts an SSL handshake on this connection. Common reasons include a need to use new
// encryption keys, to change cipher suites, or to initiate a new session. To force
// complete reauthentication, the current session could be invalidated before starting
// this handshake.
socket.startHandshake();
// Retrieve the server's certificate chain
Certificate[] serverCerts = socket.getSession().getPeerCertificates();
// The local certificate first followed by any certificate authorities.
if (serverCerts != null && serverCerts.length > 0) {
return serverCerts[0];
} else {
return null;
}
} finally {
// Close the socket
if (socket != null) {
socket.close();
}
}
}
# These must match the allowed values for auth-method as defined by the spec BASIC=org.apache.catalina.authenticator.BasicAuthenticator CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator DIGEST=org.apache.catalina.authenticator.DigestAuthenticator FORM=org.apache.catalina.authenticator.FormAuthenticator NONE=org.apache.catalina.authenticator.NonLoginAuthenticator OPENID=org.wso2.OpenIDAuthenticatorNow we need to re-pack the extracted jar with our change to catalina.jar and keep it in it's original location.
<web-app> <security-constraint> <web-resource-collection> <web-resource-name>secured resources</web-resource-name> <url-pattern>/web/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>OPENID</auth-method> <form-login-config> <form-login-page>/openid-login.jsp</form-login-page> <form-error-page>/denied.jsp</form-error-page> </form-login-config> </login-config> </web-app>Here, the openid-login.jsp and denied.jsp pages are not application specific - so can be reused across.
package org.wso2;
import java.io.IOException;
import java.security.Principal;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.LoginConfig;
import org.wso2.solutions.identity.relyingparty.RelyingPartyException;
import org.wso2.solutions.identity.relyingparty.TokenVerifierConstants;
import org.wso2.solutions.identity.relyingparty.openid.OpenIDAuthenticationRequest;
import org.wso2.solutions.identity.relyingparty.openid.OpenIDConsumer;
import org.wso2.solutions.identity.relyingparty.openid.OpenIDRequestType;
import org.wso2.solutions.identity.relyingparty.openid.OpenIDUtil;
/**
* This extends the functionality of FormAuthenticator to facilitate OpenID logins.
*
* @author Prabath Siriwardena @ WSO2
* http://www.wso2.org
* http://blog.facilelogin.com
*
*/
public class OpenIDAuthenticator extends FormAuthenticator {
/**
* {@inheritDoc}
*/
public boolean authenticate(Request request, Response response, LoginConfig config) {
Principal principal = null;
boolean loginAction = false;
boolean isAuthenticated = false;
String requestURI = null;
Realm realm = null;
String openID = null;
// References to objects we will need later
Session session = null;
principal = request.getUserPrincipal();
if (principal != null) {
// We are here because we have being authenticated successfully, before.
return true;
}
// Check whether this is a re-submit of the original request URI after successful
// authentication? If so, forward the *original* request instead.
if (matchRequest(request)) {
return matchRequest(request, response, config);
}
// This should be the OpenID return to url.
requestURI = request.getDecodedRequestURI();
// This request came from the login page - let me login - here are my credentials.
loginAction = (request.getParameter("login") != null);
if (!loginAction) {
// This can be the initial request for the protected resource or being redirected back
// by the OpenID Provider.
if (OpenIDUtil.isOpenIDAuthetication(request)) {
// This is an OpenID response - follow the OpenID protocol
String auth = null;
try {
OpenIDConsumer.getInstance().setSessionAttributes(request);
auth = (String) request.getAttribute(TokenVerifierConstants.SERVLET_ATTR_STATE);
if (auth != null && TokenVerifierConstants.STATE_SUCCESS.equals(auth)) {
isAuthenticated = true;
} else {
forwardToErrorPage(request, response, config);
return (false);
}
} catch (RelyingPartyException e) {
forwardToErrorPage(request, response, config);
return (false);
}
} else {
try {
session = request.getSessionInternal(true);
saveRequest(request, session);
} catch (IOException ioe) {
return (false);
}
request.getSession().setAttribute("requestURI", requestURI);
forwardToLoginPage(request, response, config);
return (false);
}
}
// You are here, because you came here directly from the openid-login page or you are
// authenticated at OP and redircted back.
if (!isAuthenticated) {
// Let's build the OpenID authentication request.
try {
doOpenIDAuthentication(request, response);
return false;
} catch (RelyingPartyException e) {
forwardToErrorPage(request, response, config);
return (false);
}
}
realm = context.getRealm();
session = request.getSessionInternal(false);
if (!(realm instanceof OpenIDRealm)) {
realm = new OpenIDRealm();
context.setRealm(realm);
}
openID = (String) request.getAttribute("openid_identifier");
principal = realm.authenticate(openID, "");
if (principal == null) {
forwardToErrorPage(request, response, config);
return (false);
}
// Save the authenticated Principal in our session
session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
// Save the OpenID
session.setNote(Constants.SESS_USERNAME_NOTE, openID);
// We have no password for OpenID
session.setNote(Constants.SESS_PASSWORD_NOTE, "");
// Redirect the user to the original request URI (which will cause
// the original request to be restored)
requestURI = savedRequestURL(session);
try {
response.sendRedirect(response.encodeRedirectURL(requestURI));
} catch (IOException e) {
return (false);
}
return (false);
}
/**
* Performs OpenID authentication
*
* @param request Request we are processing
* @param response Response we are creating
* @throws RelyingPartyException
*/
protected void doOpenIDAuthentication(Request request, Response response)
throws RelyingPartyException {
OpenIDAuthenticationRequest openIDAuthRequest = null;
openIDAuthRequest = new OpenIDAuthenticationRequest(request, response);
openIDAuthRequest.setOpenIDUrl((String) request.getParameter("openIdUrl"));
openIDAuthRequest.addRequestType(OpenIDRequestType.SIMPLE_REGISTRATION);
if (request.getProtocol().equals("HTTP/1.1")) {
openIDAuthRequest.setReturnUrl("http://" + request.getLocalName() + ":"
+ request.getLocalPort() + request.getSession().getAttribute("requestURI"));
} else {
openIDAuthRequest.setReturnUrl("https://" + request.getLocalName() + ":"
+ request.getLocalPort() + request.getSession().getAttribute("requestURI"));
}
OpenIDConsumer.getInstance().doOpenIDAuthentication(openIDAuthRequest);
}
/**
* Check whether this is a re-submit of the original request URI after successful
* authentication? If so, forward the *original* request instead.
*
* @param request Request we are processing
* @param response Response we are creating
* @param config Login configuration describing how authentication should be performed
*/
private boolean matchRequest(Request request, Response response, LoginConfig config) {
Session session = null;
Principal principal = null;
session = request.getSessionInternal(true);
principal = (Principal) session.getNote(Constants.FORM_PRINCIPAL_NOTE);
register(request, response, principal, Constants.FORM_METHOD, (String) session
.getNote(Constants.SESS_USERNAME_NOTE), (String) session
.getNote(Constants.SESS_PASSWORD_NOTE));
// If we're caching principals we no longer need the username
// and password in the session, so remove them
if (cache) {
session.removeNote(Constants.SESS_USERNAME_NOTE);
session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
try {
if (restoreRequest(request, session)) {
return (true);
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return (false);
}
} catch (IOException e) {
forwardToErrorPage(request, response, config);
return (false);
}
}
}
package org.wso2;
import java.security.Principal;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.deploy.SecurityConstraint;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.realm.RealmBase;
/**
* This extends the functionality of RealmBase to facilitate OpenID logins.
*
* @author Prabath Siriwardena @ WSO2
* http://www.wso2.org
* http://blog.facilelogin.com
*
*/
public class OpenIDRealm extends RealmBase {
/**
* No passwords for OpenID
*/
protected String getPassword(String openID) {
return "";
}
/**
* {@inheritDoc}
*/
protected Principal getPrincipal(String OpenID) {
return new GenericPrincipal(this, OpenID, "", null, null);
}
/**
* We have no roles associated.
*/
public boolean hasRole(Principal principal, String role) {
return false;
}
/**
* Give this realm required permissions.
*/
public boolean hasResourcePermission(Request request, Response response,
SecurityConstraint[] constraints, Context context) {
return true;
}
/**
* Realm name
*/
protected String getName() {
return "OpenIDRealm";
}
}
Lets start with the most inner part.
<service name="SimpleService">
<module ref="rampart" />
<operation name="echo">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<parameter name="ServiceClass" locked="false">org.apache.ws.axis2.SimpleService/>
<wsp:Policy wsu:Id="UTOverTransport"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:passwordCallbackClassvorg.apache.ws.axis2.PWCBHandler</ramp:passwordCallbackClass>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</service>
The above requests to include username/password credentials in all the messages sent from initiator to recipient.
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
Supporting tokens are included in the security header and in our case UsernameToken will be expected in the header.
<sp:SupportingTokens
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
</sp:SupportingTokens>
This is not policy specific - but Rampart specific - it simply says Rampart to where to find the password callback class at the service end to verify client credentials.
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:passwordCallbackClass>org.apache.ws.axis2.PWCBHandler</ramp:passwordCallbackClass>
</ramp:RampartConfig>
wsdl2java -uri http://localhost:8080/axis2/services/SimpleService?wsdl -ns2p http://axis2.ws.apache.org=org.apache.ws.axis2 -uw
package org.apache.ws.axis2;
import java.rmi.RemoteException;
import org.apache.axis2.client.Options;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
public class Client {
private static final String SERVICE_EPR = "http://localhost:8080/axis2/services/SimpleService";
public static void main(String[] args) throws RemoteException {
SimpleServiceStub service = null;
Options options = null;
ConfigurationContext configContext = null;
configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo", null);
service = new SimpleServiceStub(configContext, SERVICE_EPR);
// engage rampart module
service._getServiceClient().engageModule("rampart");
options = service._getServiceClient().getOptions();
// add username/password credentials
options.setUserName("bob");
options.setPassword("bobPW");
System.out.println(service.echo("Hi"));
}
}
With this, we have asked Axis2 to load the module rampart.
<axisconfig name="AxisJava2.0">
<!-- engaging rampart module -->
< module ref="rampart" />
</axisconfig>
In this case axis2.xml will be loaded from path_to_axis2_xml and the corresponding modules will be loaded from path_to_repo/modules directory. So in our case you need to have the rampart module inside path_to_repo/modules directory.
ConfigurationContext configContext = null;
configContext= ConfigurationContextFactory.createConfigurationContextFromFileSystem("path_to_repo","path_to_axis2_xml");
Here we pass null for path_to_axis2_xml.
ConfigurationContext configContext = null;
configContext= ConfigurationContextFactory.createConfigurationContextFromFileSystem("path_to_repo",null);
All set and we are done with the first option.
SimpleServiceStub service = null;
service = new SimpleServiceStub(configContext, SERVICE_EPR);
Even in this case, if you only set the AXIS2_REPO property then the axis2.xml will be read from directly under path_to_repo location.
import org.apache.axis2.Constants;
System.setProperty(Constants.AXIS2_CONF, "path_to_axis2_xml");
System.setProperty(Constants.AXIS2_REPO, "path_to_repo");
Let's move to the next option - that is engaging modules programmatically.
SimpleServiceStub service = null;
//service = new SimpleServiceStub(configContext, SERVICE_EPR);
service = new SimpleServiceStub(SERVICE_EPR);
Here we do not need to tell Axis2, where to find the axis2.xml - but still we need to tell where to locate the module - that is the path_to_repo.
SimpleServiceStub service = null;
service = new SimpleServiceStub(SERVICE_EPR);
service._getServiceClient().engageModule("rampart");
OR we can create a ConfigurationContext with path_to_repo and pass it to the service stub.
System.setProperty(Constants.AXIS2_REPO, "path_to_repo");
That's it - and we are done with the second option as well.
SimpleServiceStub service = null;
ConfigurationContext configContext = null;
configContext= ConfigurationContextFactory.createConfigurationContextFromFileSystem("path_to_repo",null);
//service = new SimpleServiceStub(SERVICE_EPR);
service = new SimpleServiceStub(configContext, SERVICE_EPR);
Let's look at the code now. It's self-explanatory with the attached comments.
C:\>keytool -genkey -keystore wso2.jks -storepass wso2123 -keypass wso2123 -alias wso2
The above will output the private key in a binary format - let's see how we could convert it to Base64 with OpenSSL.
package org.wso2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
public class KeyExplorer {
private final static String KEY_STORE_FILE = "c:\\wso2.jks";
private final static String KEY_STORE_PASSWORD = "wso2123";
private final static String PRIVATE_KEY_PASSWORD = "wso2123";
private final static String KEY_ALIAS = "wso2";
private final static String KEY_STORE_TYPE = "jks";
private final static String OUT_PUT_FILE = "c:\\wso2.key";
public static void main(String[] args) {
KeyStore keystore = null;
Key privateKey = null;
FileOutputStream outFile = null;
try {
keystore = KeyStore.getInstance(KEY_STORE_TYPE);
keystore.load(new FileInputStream(KEY_STORE_FILE), KEY_STORE_PASSWORD.toCharArray());
if (keystore.containsAlias(KEY_ALIAS)) {
privateKey = keystore.getKey(KEY_ALIAS, PRIVATE_KEY_PASSWORD.toCharArray());
} else {
return;
}
// Returns true if the entry identified by the given alias was
// created by a call to setKeyEntry, or created by a call to
// setEntry with a PrivateKeyEntry or a SecretKeyEntry.
if (keystore.isKeyEntry(KEY_ALIAS)) {
System.out.println("PrivateKeyEntry");
}
// Returns the standard algorithm name for this key. For example,
// "DSA" would indicate that this key is a DSA key.
System.out.println("Algorithm: " + privateKey.getAlgorithm());
// Returns the name of the primary encoding format of this key, or
// null if this key does not support encoding. The primary encoding
// format is named in terms of the appropriate ASN.1 data format, if
// an ASN.1 specification for this key exists. For example, the name
// of the ASN.1 data format for public keys is SubjectPublicKeyInfo,
// as defined by the X.509 standard; in this case, the returned
// format is "X.509". Similarly, the name of the ASN.1 data format
// for private keys is PrivateKeyInfo, as defined by the PKCS #8
// standard; in this case, the returned format is "PKCS#8".
System.out.println("Key format: " + privateKey.getFormat());
outFile = new FileOutputStream(OUT_PUT_FILE);
outFile.write(privateKey.getEncoded());
outFile.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outFile != null) {
try {
outFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
The "enc" command does various types of encryptions and encodings and "-a" is for Base64 - just type "openssl enc -help" - you'll see all available options.
openssl enc -in wso2.key -out wso2-txt.key -a
:\>keytool import -alias webapp -file webapp.cer -keystore [JAVA_HOME]\jre\lib\security\cacertsNext step is to tell the WSO2 Identity Solution, that you trust 'Company B'.
The above will create a keystore with the name keystore.jks in side [CATALINA_HOME].
[CATALINA_HOME]>keytool -genkey -alias webapp -keyalg RSA -keystore keystore.jks
All set, hit the url, https://webapp:8443 - now broswer will give you a warning saying that your certificate is not trusted.
<Service name="Catalina">
<!-- Add the following -->
<!-- 'tomcat' is the password you gave while creating keystore.jks -->
<!-- Make sure keystore.jks is inside [CATALINA_HOME] -->
<Connector port="8443"
maxHttpHeaderSize="8192"
maxThreads="150"
minSpareThreads="25"
maxSpareThreads="75"
enableLookups="false"
disableUploadTimeout="true"
acceptCount="100"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="keystore.jks"
keystorePass="tomcat"/>
</Service>
Now lets look at the ADAuthenticator - which actually does the authentication against the AD - user base.
package org.apache.ws.axis2;
import java.io.IOException;
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
public class PWCBHandler implements CallbackHandler {
private static String SECURITY_PRINCIPAL = "cn=tomcat,cn=users,dc=home,dc=com";
private static String SECURITY_CREDENTIALS = "1qaz2wsx@";
private static String PROVIDER_URL = "ldap://192.168.1.2:389";
private static String USER_PATTERN = "cn={0},cn=Users,dc=home,dc=com";
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
ADAuthenticator authenticator = null;
authenticator = new ADAuthenticator(SECURITY_PRINCIPAL, SECURITY_CREDENTIALS, PROVIDER_URL,USER_PATTERN);
for (int i = 0; i < callbacks.length; i++) {
// When the server side need to authenticate the user
WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[i];
// Usage value is set to USERNAME_TOKEN_UNKNOWN when the Rampart
// Engine wants the password callback handler to validate the
// username and password in the Username Token
if (pwcb.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {
if (authenticator.authenticate(pwcb.getIdentifer(), pwcb.getPassword())) {
return;
} else {
throw new UnsupportedCallbackException(callbacks[i], "check failed");
}
}
}
}
}
package org.apache.ws.axis2;
import java.text.MessageFormat;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
public class ADAuthenticator {
/**
* Holds the name of the environment property for specifying the initial
* context factory to use. The value of the property should be the fully
* qualified class name of the factory class that will create an initial
* context.
*/
private static String INITIAL_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private DirContext context = null;
private String userPattern = null;
/**
*
* @param conName
* Holds the name of the environment property for specifying the
* identity of the principal for authenticating the caller to the
* service.
* @param conPassword
* Holds the name of the environment property for specifying the
* credentials of the principal for authenticating the caller to
* the service.
* @param connectionUrl
* Holds the name of the environment property for specifying
* configuration information for the service provider to use.
* @param userPattern
* Search pattern.
*/
public ADAuthenticator(String conName, String conPassword, String connectionUrl,
String userPattern) {
Hashtableenvironment = null;
try {
environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
environment.put(Context.SECURITY_PRINCIPAL, conName);
environment.put(Context.SECURITY_CREDENTIALS, conPassword);
environment.put(Context.PROVIDER_URL, connectionUrl);
this.userPattern = userPattern;
context = new InitialDirContext(environment);
} catch (NamingException ex) {
throw new RuntimeException();
}
}
/**
* Authenticates a given user against Active Directory user store.
*
* @param userName
* User to be authenticated.
* @param password
* Password of the user.
* @return true if authenticated.
*/
public boolean authenticate(String userName, String password) {
String dn = null;
try {
dn = MessageFormat.format(userPattern, new String[] { userName });
return this.bindAsUser(this.context, dn, (String) password);
} catch (NamingException ex) {
return false;
}
}
private boolean bindAsUser(DirContext context, String dn, String credentials)
throws NamingException {
if (credentials == null || dn == null)
return false;
context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials);
context.getAttributes("", null);
return true;
}
}
[SAMPLE]\>keytool -genkey -alias wso2wsas -keyalg RSA -keystore wso2wsas.jks [SAMPLE]\>keytool -certreq -keystore wso2wsas.jks -alias wso2wsas -file wso2wsas.cert.reqThe above will generate the CSR - wso2wsas.cert.req, which we can submit to the CA which we just created, to get it signed.
<!-- You need to add new configurations inside this tag -->
<Engine name="Catalina" defaultHost="localhost">
<!-- Make sure you comment out this line from your current configuration -->
<!-- Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/ -->
<!-- Add following new configuration -->
<!-- Compare the values with the Active Directory image shown above -->
<!-- I am running my AD on 192.168.1.3 -->
<Realm className="org.apache.catalina.realm.JNDIRealm"
connectionName="cn=tomcat,cn=users,dc=home,dc=com"
connectionPassword="1qaz2wsx@"
connectionURL="ldap://192.168.1.3:389"
userRoleName="member"
userBase="cn=Users,dc=home,dc=com"
userPattern="cn={0},cn=Users,dc=home,dc=com"
roleBase="cn=Users,dc=home,dc=com"
roleName="cn"
roleSearch="(member={0})"
roleSubtress="false"
userSubtree="true"
/>
</Engine>
Once this is done - let's open the file [CATALINA_HOME]\webapps\axis2\WEB-INF\web.xml and edit to add the following.<web-app> <security-constraint> <web-resource-collection> <web-resource-name>secured services <url-pattern>/services/* </web-resource-collection> <auth-constraint> <!-- This is mapped to the 'facilelogin' group in AD --> <role-name>facilelogin </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC <realm-name>facilelogin </login-config> </web-app>All set - let's restart Tomcat.
package org.apache.ws.axis2;
import java.util.Properties;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;
public class Client {
public static void main(String[] args) throws Exception {
ServiceClient client = null;
Options options = null;
OMElement response = null;
HttpTransportProperties.Authenticator authenticator = null;
Properties properties = null;
client = new ServiceClient();
options = new Options();
options.setAction("urn:getVersion");
options.setTo(new EndpointReference("http://localhost:8080/axis2/services/Version"));
authenticator = new HttpTransportProperties.Authenticator();
// Add user creadentials to the transport header
// This user belongs to the 'facilelogin' group in AD
authenticator.setUsername("administrator");
authenticator.setPassword("prabath");
authenticator.setRealm("facilelogin");
properties = new Properties();
properties.put(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperties(properties);
client.setOptions(options);
response = client.sendReceive(getPayload());
System.out.println(response);
}
private static OMElement getPayload() {
OMFactory factory = null;
OMNamespace ns = null;
OMElement elem = null;
factory = OMAbstractFactory.getOMFactory();
ns = factory.createOMNamespace("http://axisversion.sample", "ns1");
elem = factory.createOMElement("getVersion", ns);
return elem;
}
}
Now let's restricts access to all our web services to the above defined role.
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="facilelogin"/>
<user username="prabath" password="prabath" roles="facilelogin"/>
</tomcat-users>
All set - let's restart Tomcat.
<web-app>
<security-constraint>
<web-resource-collection>
<web-resource-name>secured services</web-resource-name>
<url-pattern>/services/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>facilelogin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>facilelogin</realm-name>
</login-config>
</web-app>
package org.apache.ws.axis2;
import java.util.Properties;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;
public class Client {
public static void main(String[] args) throws Exception {
ServiceClient client = null;
Options options = null;
OMElement response = null;
HttpTransportProperties.Authenticator authenticator = null;
Properties properties = null;
client = new ServiceClient();
options = new Options();
options.setAction("urn:getVersion");
options.setTo(new EndpointReference("http://localhost:8080/axis2/services/Version"));
authenticator = new HttpTransportProperties.Authenticator();
// Add user creadentials to the transport header
authenticator.setUsername("prabath");
authenticator.setPassword("prabath");
authenticator.setRealm("facilelogin");
properties = new Properties();
properties.put(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperties(properties);
client.setOptions(options);
response = client.sendReceive(getPayload());
System.out.println(response);
}
private static OMElement getPayload() {
OMFactory factory = null;
OMNamespace ns = null;
OMElement elem = null;
factory = OMAbstractFactory.getOMFactory();
ns = factory.createOMNamespace("http://axisversion.sample", "ns1");
elem = factory.createOMElement("getVersion", ns);
return elem;
}
}
POST /axis2/services/Version HTTP/1.1
Content-Type: text/xml; charset=UTF-8
SOAPAction: "urn:getVersion"
User-Agent: Axis2
Transfer-Encoding: chunked
Authorization: Basic cHJhYmF0aDpwcmFiYXRo
Host: localhost:8080
Now, we need to configure the listener in [AXIS2_HOME]\conf\axis2.xml.
import java.util.ArrayList;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.AxisServiceGroup;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.AxisEvent;
import org.apache.axis2.engine.AxisObserver;
public class ServiceInterceptor implements AxisObserver {
public void init(AxisConfiguration arg0) {
}
public void moduleUpdate(AxisEvent arg0, AxisModule arg1) {
}
public void serviceGroupUpdate(AxisEvent arg0, AxisServiceGroup arg1) {
}
public void serviceUpdate(AxisEvent event, AxisService service) {
int eventType;
String serviceName = null;
eventType = event.getEventType();
serviceName = service.getName();
if (eventType == AxisEvent.SERVICE_DEPLOY) {
} else if (eventType == AxisEvent.SERVICE_START) {
if ("MyService".equals(serviceName)) {
}
} else if (eventType == AxisEvent.SERVICE_STOP) {
} else if (eventType == AxisEvent.SERVICE_REMOVE) {
}
}
public void addParameter(Parameter arg0) throws AxisFault {
}
public void deserializeParameters(OMElement arg0) throws AxisFault {
}
public Parameter getParameter(String arg0) {
return null;
}
public ArrayList getParameters() {
return null;
}
public boolean isParameterLocked(String arg0) {
return false;
}
public void removeParameter(Parameter arg0) throws AxisFault {
}
}
<listener class="ServiceInterceptor"/>
And, replace it with the following.
"%_JAVACMD%" %JAVA_OPTS% -cp "!AXIS2_CLASS_PATH!"
org.apache.axis2.transport.SimpleAxis2Server %AXIS2_CMD_LINE_ARGS%
"%_JAVACMD%" %JAVA_OPTS% -cp "!AXIS2_CLASS_PATH!"-Xdebug -Xnoagent
-Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
org.apache.axis2.transport.SimpleAxis2Server %AXIS2_CMD_LINE_ARGS%
<!--[StockQuoteService]\app.config --> <service name="wso2.org.stockquotes.StockQuoteService" behaviorConfiguration="stockquotebehaviour"> <endpoint address="http://localhost/stocks" binding="basicHttpBinding" contract="wso2.org.stockquotes.StockQuoteService" /> <endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service>
<!--[StockQuoteClient]\app.config --> <client> <endpoint address="http://localhost/stocks" binding="basicHttpBinding" contract="StockQuoteServiceProxy.StockQuoteService" /> </client>Now to enable logging, add following to the [StockQuoteService]\app.config.
<system.diagnostics> <sources> <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing"> <listeners> <add type="System.Diagnostics.DefaultTraceListener" name="Default"> <filter type="" /> </add> <add name="ServiceModelMessageLoggingListener"> <filter type="" /> </add> </listeners> </source> </sources> <sharedListeners> <add initializeData="c:\messages.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp"> <filter type="" /> </add> </sharedListeners> </system.diagnostics> <system.serviceModel> <diagnostics> <messageLogging logEntireMessage="true" logMessagesAtTransportLevel="true" /> </diagnostics> </system.serviceModel>Now lets start both the service and the client.
<s:Envelope xmlns:s="..." xmlns:a="..."> <s:Header> <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action> <a:MessageID>urn:uuid:d55bd2a7-bae8-4751-a010-07e95fd82ee2</a:MessageID> <a:ReplyTo> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="1">http://localhost/stocks</a:To> </s:Header> <s:Body> <t:RequestSecurityToken Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"> <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType> <t:KeySize>256</t:KeySize> <t:BinaryExchange ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"> TlRMTVNTUAABAAAAt7IY4gQABAA0AAAADAAMACgAAAAFAs4OAAAAD1BSQUJBVEgtSE9NRUhPTUU= </t:BinaryExchange> </t:RequestSecurityToken> </s:Body> </s:Envelope>Now the service will create a RequestSecurityTokenResponse[RSTR] and will send it back to the client.
<s:Envelope xmlns:s="..." xmlns:a="..."> <s:Header> <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue <a:RelatesTo>urn:uuid:d55bd2a7-bae8-4751-a010-07e95fd82ee2</a:RelatesTo> </s:Header> <s:Body> <t:RequestSecurityTokenResponse Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <t:BinaryExchange ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"> TlRMTVNTUAACAAAACAAIADgAAAA1wpnipKbRWTHfQGhYyuMAAAAAAIIAggBAAAAABQLODgAAAA9 IAE8ATQBFAAIACABIAE8ATQBFAAEAGABQAFIAQQBCAEEAVABIAC0ASABPAE0ARQAEABAAaABvAG0 AZQAuAGMAbwBtAAMAKgBwAHIAYQBiAGEAdABoAC0AaABvAG0AZQAuAGgAbwBtAGUALgBjAG8 AbQAFABAAaABvAG0AZQAuAGMAbwBtAAAAAAA= </t:BinaryExchange> </t:RequestSecurityTokenResponse> </s:Body> </s:Envelope>To complete the initial handshaking process client once again sends an RSTR.
<s:Envelope xmlns:s="..." xmlns:a=""> <s:Header> <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue <a:MessageID>urn:uuid:da46b6f3-b168-4aae-95fb-b9412cecf177</a:MessageID> <a:ReplyTo> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="1">http://localhost/stocks</a:To> </s:Header> <s:Body> <t:RequestSecurityTokenResponse Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1" xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <t:BinaryExchange ValueType="http://schemas.xmlsoap.org/ws/2005/02/trust/spnego" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"> TlRMTVNTUAADAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAAAAAA </t:BinaryExchange> </t:RequestSecurityTokenResponse> </s:Body> </s:Envelope>
<s:Envelope xmlns:s="..." xmlns:a="..."> <s:Header> <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue</a:Action> <a:RelatesTo>urn:uuid:da46b6f3-b168-4aae-95fb-b9412cecf177</a:RelatesTo> </s:Header> <s:Body> <t:RequestSecurityTokenResponseCollection xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust"> <t:RequestSecurityTokenResponse Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType> <t:RequestedSecurityToken> <c:SecurityContextToken u:Id="uuid-06c81281-3c66-4122-b7ef-07744a68756e-1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <c:Identifier> urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858 </c:Identifier> </c:SecurityContextToken> </t:RequestedSecurityToken> <t:RequestedAttachedReference> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1"> </o:Reference> </o:SecurityTokenReference> </t:RequestedAttachedReference> <t:RequestedUnattachedReference> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"> </o:Reference> </o:SecurityTokenReference> </t:RequestedUnattachedReference> <t:RequestedProofToken> <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://schemas.xmlsoap.org/2005/02/trust/spnego#GSS_Wrap"> </e:EncryptionMethod> <e:CipherData> <e:CipherValue> AQAAAMaisligvVhlAAAAAINLoPtv3Zq34T52WXoXBI1YaL+V8cNjc+BxdMVKu </e:CipherValue> </e:CipherData> </e:EncryptedKey> </t:RequestedProofToken> <t:Lifetime> <u:Created>2008-11-03T10:11:04.437Z</u:Created> <u:Expires>2008-11-03T10:26:04.437Z</u:Expires> </t:Lifetime> <t:KeySize>256</t:KeySize> </t:RequestSecurityTokenResponse> <t:RequestSecurityTokenResponse Context="uuid-f422503c-7974-42ab-9b8a-c330727290e9-1" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <t:Authenticator> <t:CombinedHash>Zc9/3FeaG8b6/cs7jeTsHpZC8JlPjCgeun5I/4RRbd0=</t:CombinedHash> </t:Authenticator> </t:RequestSecurityTokenResponse> </t:RequestSecurityTokenResponseCollection> </s:Body> </s:Envelope>
<s:Envelope xmlns:s="..." xmlns:a="..." xmlns:u="..."> <s:Header> <a:Action s:mustUnderstand="1" u:Id="_4">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action> <a:MessageID u:Id="_5">urn:uuid:b534d3de-1bcc-42fb-81b6-e472c797281f</a:MessageID> <a:ReplyTo u:Id="_6"> <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address> </a:ReplyTo> <a:To s:mustUnderstand="1" u:Id="_7">http://localhost/stocks</a:To> <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <u:Timestamp u:Id="uuid-f422503c-7974-42ab-9b8a-c330727290e9-5"> <u:Created>2008-11-03T10:11:04.453Z</u:Created> <u:Expires>2008-11-03T10:16:04.453Z</u:Expires> </u:Timestamp> <c:SecurityContextToken u:Id="uuid-06c81281-3c66-4122-b7ef-07744a68756e-1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <c:Identifier>urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858</c:Identifier> </c:SecurityContextToken> <c:DerivedKeyToken u:Id="_0" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <o:SecurityTokenReference> <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1"></o:Reference> </o:SecurityTokenReference> <c:Offset>0</c:Offset> <c:Length>24</c:Length> <c:Nonce> <!-- Removed--> </c:Nonce> </c:DerivedKeyToken> <c:DerivedKeyToken u:Id="_1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <o:SecurityTokenReference> <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" URI="#uuid-06c81281-3c66-4122-b7ef-07744a68756e-1"> </o:SecurityTokenReference> <c:Nonce> <!-- Removed--> </c:Nonce> </c:DerivedKeyToken> <e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:DataReference URI="#_3"> <e:DataReference URI="#_8"> </e:ReferenceList> <e:EncryptedData Id="_8" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <o:SecurityTokenReference> <o:Reference URI="#_1"> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>..... </e:CipherData> </e:EncryptedData> </o:Security> </s:Header> <s:Body u:Id="_2"> <e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <o:Reference URI="#_1"></o:Reference> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>...</e:CipherValue> </e:CipherData> </e:EncryptedData> </s:Body> </s:Envelope>Finally the service will repond with the following.
<s:Envelope xmlns:s="..." xmlns:a="..." xmlns:u="..."> <s:Header> <a:Action s:mustUnderstand="1" u:Id="_4">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT <a:RelatesTo u:Id="_5">urn:uuid:b534d3de-1bcc-42fb-81b6-e472c797281f</a:RelatesTo> <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <u:Timestamp u:Id="uuid-06c81281-3c66-4122-b7ef-07744a68756e-6"> <u:Created>2008-11-03T10:11:04.468Z</u:Created> <u:Expires>2008-11-03T10:16:04.468Z</u:Expires> </u:Timestamp> <c:DerivedKeyToken u:Id="_0" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <o:SecurityTokenReference> <o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"> </o:SecurityTokenReference> <c:Offset>0</c:Offset> <c:Length>24</c:Length> <c:Nonce> <!-- Removed--< </c:Nonce> </c:DerivedKeyToken> <c:DerivedKeyToken u:Id="_1" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc"> <o:SecurityTokenReference> <o:Reference URI="urn:uuid:05adf263-f2bb-4edf-8597-00c7c7f5e858" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"> </o:SecurityTokenReference> <c:Nonce> <!-- Removed--> </c:Nonce> </c:DerivedKeyToken> <e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:DataReference URI="#_3"></e:DataReference> <e:DataReference URI="#_6"></e:DataReference> </e:ReferenceList> <e:EncryptedData Id="_6" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <o:SecurityTokenReference> <o:Reference URI="#_1"></o:Reference> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>...</e:CipherValue> </e:CipherData> </e:EncryptedData> </o:Security> </s:Header> <s:Body u:Id="_2"> <e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#"> <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"></e:EncryptionMethod> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <o:Reference URI="#_1"></o:Reference> </o:SecurityTokenReference> </KeyInfo> <e:CipherData> <e:CipherValue>...</e:CipherValue> </e:CipherData> </e:EncryptedData> </s:Body> </s:Envelope>Now the client will invoke the bussiness logic.
Once completed, add the jar containing the above class to [AXIS2_HOME]\lib.
package org.apache.ws.axis2;
import java.util.Iterator;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.savan.SavanException;
import org.apache.savan.storage.SubscriberStore;
import org.apache.savan.subscribers.Subscriber;
import org.apache.savan.subscribers.SubscriberGroup;
public class CustomSubscriberStore implements SubscriberStore {
public void init(ConfigurationContext arg0) throws SavanException {
// TODO Initialize the storage
}
public void addSubscriberGroup(String arg0) throws SavanException {
// TODO Add subscriber to a subscriber group
}
public void addSubscriberToGroup(String arg0, Subscriber arg1) throws SavanException {
// TODO Add subscriber to a subscriber group
}
public void delete(String arg0) throws SavanException {
// TODO Delete a previously stored subscriber
}
public SubscriberGroup getSubscriberGroup(String arg0) throws SavanException {
// TODO Retrieve a previously stored subscriber group
}
public Subscriber retrieve(String arg0) throws SavanException {
// TODO Retrieve a previously stored subscriber
}
public Iterator retrieveAllSubscriberGroups() throws SavanException {
// TODO Retrieve a previously stored subscriber groups
}
public Iterator retrieveAllSubscribers() throws SavanException {
// TODO Retrieve previously stored subscribers
}
public void store(Subscriber arg0) throws SavanException {
// TODO Store the subscriber in the persistent data store
}
}
Now, we are almost done. Let's configure the event source[axis2-savan-event-source] to use our custom subscriber store.
<subscriberStores>
<subscriberStore>
<key>default</key>
<class>org.apache.savan.storage.DefaultSubscriberStore</class>
</subscriberStore>
<!-- this is your new subscriber store, with the key 'custom' -->
<subscriberStore>
<key>custom
<class>org.apache.ws.axis2.CustomSubscriberStore
</subscriberStore>
</subscriberStores>
All set - redeploy the event source service and test with the client.
<service name="StockQuoteService" scope="application">
<module ref="savan" />
<module ref="addressing" />
<parameter name="ServiceClass" locked="false">org.apache.ws.axis2.StockQuoteService</parameter>
<!-- Set SubscriberStoreKey to the key you set for you custom subscriber store in savan-config.xml -->
<parameter name="SubscriberStoreKey" locked="false">custom</parameter>
</service>