Search code examples
jbossapache-axisws-securitywebsphere-7weblogic11g

Axis2 WS-Security Running on Java EE Application Server


I have Axis2 web services running in an Application Server (like JBoss, WebSphere and Weblogic) and till now I am passing the user details within a request and authenticating the user before processing it.

The next step is that I want to delegate the authentication bit to the Java EE Application Server and once authenticated the application server should pass the UserPrinciple which I will be using as context to execute the request.

I am not sure if I have asked the question correctly? I think I am mixing the WebContainer authentication with WS-Security stuff.

Can anyone please point me to the right direction with some documentation which I can refer as start-up guide.


Solution

  • OK, I have tried a solution and it worked to some extent. Here are details;

    Created TestService with following services.xml

    <serviceGroup>
        <service name="TestWebService" scope="application" targetNamespace="http://TestServiceWs"> 
            <schema schemaNamespace="http://TestServiceWs"/>
            <description>Test POJO Axis2 AAR deployment</description>
            <parameter name="ServiceClass">test.TestServiceWS</parameter>
            <messageReceivers>
                <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
                    class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
                <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
                    class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
            </messageReceivers>
        </service>
    
        <module ref="rampart" />
    
        <parameter name="InflowSecurity">
          <action>
            <items>UsernameToken Timestamp</items>
            <passwordCallbackClass>test.PWHandlerServer</passwordCallbackClass>
          </action>
        </parameter>
    </serviceGroup>
    

    Implemented PWHandlerServer.java

    package test;
    
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.ws.security.WSPasswordCallback;
    
    public class PWHandlerServer implements CallbackHandler {
    
        // the username and password we expect incoming WS calls to use
        private String user = "wsuser";
        private String pwd = "wspwd";
    
        public void handle (Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (int i = 0; i < callbacks.length; i++) {
                if (callbacks[i] instanceof WSPasswordCallback) {
                    WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                    System.out.println("identifier: "+pc.getIdentifer()+", usage: "+pc.getUsage());
    
                    if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN) {
                        // for passwords sent in digest mode we need to provide the password,
                        // because the original one can't be un-digested from the message
    
                        // we can throw either of the two Exception types if authentication fails
                        if (! user.equals(pc.getIdentifer()))
                            throw new IOException("unknown user: "+pc.getIdentifer());
    
                        // this will throw an exception if the passwords don't match
                        pc.setPassword(pwd);
    
                    } else if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {
                        // for passwords sent in cleartext mode we can compare passwords directly
    
                        if (! user.equals(pc.getIdentifer()))
                            throw new IOException("unknown user: "+pc.getIdentifer());
    
                        // we can throw either of the two Exception types if authentication fails
                        if (! pwd.equals(pc.getPassword()))
                            throw new IOException("password incorrect for user: "+pc.getIdentifer());
                    }
                    // If everything is OK then set the context and move on
                    TestRequestContext ctx = new TestRequestContext(pc.getIdentifer());
                    TestRequestContext.setRequestContext(ctx);
    
                } else {
                    throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
                }
            }
        }
    }
    

    Implemented TestRequestContext

    package test;
    
    
    class TestRequestContext {
        private final static ThreadLocal<TestRequestContext> currentContext = new ThreadLocal<TestRequestContext>();
    
        public static void setRequestContext(TestRequestContext context) {
            currentContext.set(context);
        }
    
        public static TestRequestContext getRequestContext() {
            return currentContext.get();
        }
    
        public static void clearRequestContext() {
            currentContext.remove();
        }
    
        private String userPrincipal;
    
        public TestRequestContext(String principal) {
            this.userPrincipal = principal;
        }
    
        public String getUserPrincipal(){
            return this.userPrincipal;
        }
    }
    

    Now I should be able to access my TestRequestContext.getUserPricipal() in my web service class and pass it on DB for transaction and switching a security context. The only problem is when I am trying to access the service via SoapUI its giving me following exception;

        15:07:34,924 INFO  [STDOUT] identifier: wsuser, usage: 5
    15:08:48,081 INFO  [STDOUT] [ERROR] WSDoAllReceiver: security processing failed (actions mismatch)
    org.apache.axis2.AxisFault: WSDoAllReceiver: security processing failed (actions mismatch)
            at org.apache.rampart.handler.WSDoAllReceiver.processBasic(WSDoAllReceiver.java:344)
            at org.apache.rampart.handler.WSDoAllReceiver.processMessage(WSDoAllReceiver.java:86)
            at org.apache.rampart.handler.WSDoAllHandler.invoke(WSDoAllHandler.java:72)
            at org.apache.axis2.engine.Phase.invoke(Phase.java:318)
            at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:254)
            at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:160)
            at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:173)
            at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:144)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
            at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:182)
            at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
            at java.lang.Thread.run(Thread.java:619)
    

    Within SoapUI, I am simply using 'Auth' tab to set username and password and invoke? do I need to setup anything else before invocation.

    Also, the approach to use ThreadLocal is correct or I can access the principle some otherway as well?

    Thanks.