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>