Skip to main content

Overriding WebServiceContext in Metro to handle security related methods

Posted by kumarjayanti on May 26, 2009 at 2:25 AM PDT

One of the design goals of Metro is to be able to run on any Application Server as a WebServices Stack. One project that i know levarages this ability is OpenSSO. The OpenSSO product is supported on several application servers.

There are two methods in the JAXWS defined WebServiceContext interface which relate to the Caller Identity (getUserPrincipal()) and Role Membership (isUserInRole()) of the caller respectively. These methods cannot be implemented in a generic manner. This is because the container's representation of the caller principal differs between different application servers. If nothing else the Java Principal class itself would be a container specific one.

When JSR 196 is enabled in Metro then it actually provides an opportunity to populate the containers representation of the caller principal. This is because Metro would invoke the JSR 196 defined CallerPrincipalCallback. However most usages of Metro on other containers has been without using JSR 196 underneath. So there is a need to override the method getUserPrincipal() on the WebServiceContext for the target container.

The other method which allows users to do programmatic access control is isUserInRole. Java EE specs do not enumerate how principals are to be mapped to roles for the simple reason that there is no unique way of doing this. Different application server's provide different ways of managing the principal to role mapping and there is no standard Java EE API to query the RoleMapping information, add to this the fact that Metro needs to work on Non JavaEE compliant containers such as Tomcat. So the method isUserInRole() on the WebServiceContext again needs to be overriden for the target container.

With latest Metro 2.0 builds you can thus override the default WebServiceContext implementation with a custom one.  The class should implement com.sun.xml.ws.api.server.WebServiceContextDelegate The implementing class should have a Constructor which accepts a delegate of type com.sun.xml.ws.api.server.WebServiceContextDelegate. Note that when Metro is running on GlassFish container there is no need to override WebServiceContext implementation for  JSR 109 webservices.

Here is a sample, where i ovverride only the getUserPrincipal(). The idea is that one can delegate the implementation of all the other methods on this interface to the default implementation which is passed as a constructor argument and only handle the two security related methods in a container specific way.

import com.sun.xml.ws.api.message.Packet;

import com.sun.xml.ws.api.server.WSEndpoint;

import java.security.Principal;

import java.util.Set;

import javax.security.auth.Subject;

public class WebServiceContextDelegate implements com.sun.xml.ws.api.server.WebServiceContextDelegate {

private static final String AUTH_SUBJECT="javax.security.auth.Subject";

private com.sun.xml.ws.api.server.WebServiceContextDelegate delegate = null;

    public WebServiceContextDelegate(com.sun.xml.ws.api.server.WebServiceContextDelegate delegate) {

        this.delegate = delegate;

    }

    public Principal getUserPrincipal(Packet packet) {

        Subject subject = (Subject)packet.invocationProperties.get(AUTH_SUBJECT);

        if (subject == null) {

             return null;

          }

          Set
set = subject.getPrincipals(Principal.class);


          if (set.isEmpty()) { return null; }


         return set.iterator().next();


    }


    public boolean isUserInRole(Packet arg0, String arg1) {


        //TODO: implement isUserInRole as appropriate for the server


        return false;


    }


    public String getEPRAddress(Packet arg0, WSEndpoint arg1) {


         return delegate.getEPRAddress(arg0, arg1);


     }


    public String getWSDLAddress(Packet arg0, WSEndpoint arg1) {


     return delegate.getWSDLAddress(arg0, arg1);


    }


}


The last step is to configure this WebServiceContext class name. This can be done on a per-application basis by specifying the following META-INF/services entry inside your application WAR. META-INF/services/com.sun.xml.ws.api.server.WebServiceContextDelegate The content of the file com.sun.xml.ws.api.server.WebServiceContextDelegate should be the fully qualified classname of your implementation class. And lastly it is expected that the implementation class is available inside WEB-INF/classes of your application WAR.

 If you are interested in knowing how JSR 196 can be enabled on non GlassFish containers send me a message. Metro has a pluggable security architecture where you can override the default JSR 196 AuthConfigProvider with one of your own. I will probably try to write about it some other day.

Related Topics >>

Comments

I have followed instructions but I cannot make it work. Is there any chance you can provide a sample app?. Thanks JC