1 2 Previous Next

kumarjayanti

25 posts
kumarjayanti

GlassFish V 3.1  Blog

Posted by kumarjayanti Mar 16, 2011

I posted my blogs on GlassFish V3.1 Security at http://blogs.sun.com/gfsecurity/  due to the non-availability of java.net during the V3.1 release.

 GlassFish users who make use of CLIENT-CERT authentication with SSL  in their JavaEE applications  should consider upgrading to JDK1.6.0_22. The good news is that JDK1.6.0_22 contains a full fix for  the renegotiation protocol flaw in SSL (The IETF issued RFC 5746 ).  A fix which implements RFC 5746 and supports secure renegotiation.

More details are here : http://www.oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html

The GlassFish Certificate Realm in V2.X and V3.0 releases is somewhat limiting. Many users expressed the need to able to do some custom authentication based on the client-certificate (or extensions within)  in a Mutual-SSL scenario. And subsequently do custom group assignment's which ultimately affect the authorization results. With V2.X/V3.0 the only two  things that were possible are :

1. Developer can specify a Single CertificateRealm with fixed name "certificate" to be used with CLIENT-CERT authentication mechanism. No LoginModule was allowed for this realm.

 2. Developer's can make use of the assign-groups functionality whereby every client that had a valid certificate (that is also trusted by the server) could be assigned a list of  group(s).

What is now possible with the latest V3.1 builds on the Trunk is the following

a.  The restriction (1) above of a single "certificate" realm remains. However one can now configure a LoginModule for the realm. The LoginModule would have access to the client certificate-chain and it is possible for the developer to do  application specific custom authentication of the client certificate.

b.  Do custom group assignment based on attributes and extensions present in the client certificate.

My team member sudarsan has created a detailed post on this with a sample loginmodule.

Embedded GlassFish v3 is a delivery vehicle of GFv3 so that applications and tools can use GFv3 just as a library, inside their JVM.  More details on this can be found  on the separate project page that has been created for  Embedded GlassFish.  

One would thus expect that even secure applications which use security annotations on an EJB or security-constraints in a web application to work on the Embedded Server.  My team member Nithya has created two posts which show

1. how to run an EJB App that uses  security annotations such as @RolesAllowed in the Embedded Server.

 2. how to run a Web App that  uses security-constraints and BASIC authentication in the Embedded Server.

Many users often ask the question :  Can i use a custom  JAAS Login Module instead of the Proprietary GlassFish Custom Realms for user authentication ?.

The JSR-196 Login Bridge Profile allows a Server Authentication Module (SAM) to delegate some security processing to JAAS LoginModules. My  team member sudarsan has created a nice blog-post  on this with a sample netbeans  project showing the use of the Login Bridge Profile.  The sample can be plugged in as a ServerAuthentication Module for a webapplication on both GlassFish V2.X and V3.

GlassFish  includes implementations of a number of HTTP layer authentication mechanisms such as Basic, Form, and Digest authentication. JSR-196 support in GlassFish  allows developers to implement and configure new authentication mechanisms or make alternative implementations of the provided ones. The following tech-tip provides all the details for doing this.

So to answer the question at the top, if you have a SAM that implements an Authentication Mechanism (say BASIC), then you can use the Login Bridge Profile to configure a JAAS LoginModule in GlassFish that will be invoked by the SAM. The JAAS Login Module can then perform custom username-password authentication and communicate the resulting  Principal and Group information to GlassFish by making use of standard JSR-196 defined callbacks (which are supported by the GlassFish CallbackHandler supplied to the SAM as an argument).  

The important thing to note is that the LoginModule and the CallbackHandler (if any that the LoginModule uses) need  not have any proprietary Glassfish Code. In other words the JAAS LoginModule is suitable for use with other containers as well.  And if the Non-Glassfish Container supports JSR-196 then the developer essentially is freed from the task of figuring out how to set the Principal and Group information into the target Container, the JSR-196 CallbackHandler supplied by the Container would handle it for the user. 

This is in contrast to the Realm which is a proprietary GlassFish artifact. Though the Realm in GlassFish essentially makes use of  a corresponding LoginModule to do its authentication, it requires use of Glassfish specific code to ensure it communicates the Principal and Group membership information to the container in the right manner.

Servlet 3.0 specification which is part of JavaEE 6 has many new features and some of them are in the area of security. The  post by Ron Monzillo gives a high level summary of the security features that he added in the Servlet 3.0 specification.  In this post i would like to focus on the aspect of Programmatically adding and configuring security for the servlet. Additionally i would provide links to other posts by me and team members on new security features of servlet 3.0.  You can access more information about the API's from the JavaEE 6 Javadocs here.

The ability to programmatically add a servlet to a context is useful for framework developers. For example a framework could declare a controller servlet using this method. The return value of this method is a ServletRegistration or a ServletRegistration.Dynamic object which further allows you to setup the other parameters of the servlet like init-params, url-mappings, security-constraints etc.

The addServlet() method on ServletRegistration.Dynamic can be called from a ServletContextListener and it allows adding a new servlet to the context. Then you can add servlet url-mappings and finally add the security constraints for the servlet by callingsetServletSecurity.  The API class that holds the security-constraints is calledjavax.servlet.ServletSecurityElement.  

Quoting from the specification : "Thejavax.servlet.ServletSecurityElement argument tosetServletSecurity is analogous in structure and model to the ServletSecurity interface of the@ServletSecurity annotation. As such, the mappings defined in Section 13.4.1.2, “Mapping @ServletSecurity to securityconstraint” on page 13-126, apply analogously to the mapping of a ServletSecurityElement with containedHttpConstraintElement andHttpMethodConstraintElement values, to its equivalent<security-constraint> representation".

 In short the ServletSecurityElement can be constructed using a HttpConstraintElement which can specify the http-method independent security. Specifically there are different constructors that allow specifying the RolesAllowed (list of roles), the Transport guarantee value (CONFIDENTIAL, NONE) and the EmptyRoleSemantic (PERMIT, DENY). The value of the EmptyRoleSemantic indicates the default authorization semantic that applies (only) when rolesAllowed returns an-empty array.  There is one constructor which takes all the three things as arguments and as is obvious it would throw an IllegalArgumentException if the EmptyRoleSemantic is set to DENY but there is a non empty list of roles supplied to it.

So here is some sample code developed using NetBeans 6.8 M2. First  i would show the servlet which we are going to add programmatically :


package test;
.....
public class NewServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) 
    throws IOException, ServletException {
        PrintWriter writer = res.getWriter();
        writer.write("GET :Hello, " + req.getRemoteUser() + "\n");
    }
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse res)
    throws IOException, ServletException {
        PrintWriter writer = res.getWriter();
        writer.write("POST :Hello, " + req.getRemoteUser() + "\n");
    }

    @Override
    protected void doTrace(HttpServletRequest req, HttpServletResponse res) 
    throws IOException, ServletException {
        PrintWriter writer = res.getWriter();
        writer.write("TRACE :Hello, " + req.getRemoteUser() + "\n");
    }
}


And here is the ServletContextListener which adds the above servlet into the context using addServlet method on ServletRegistration.Dynamic.


package test;
.....
@WebListener()
public class NewServletListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("NewServletListener.contextInitialized called");
        try {
            ServletContext sc = sce.getServletContext();
            Class<NewServlet> servletCl =
                    (Class<NewServlet>) Class.forName("test.NewServlet");
            NewServlet servlet = sc.createServlet(servletCl);
            ServletRegistration.Dynamic sr =
                    (ServletRegistration.Dynamic) sc.addServlet("test.NewServlet", servlet);
            sr.addMapping("/newServlet");
           //create a security constraint element
            HttpConstraintElement constraint = new HttpConstraintElement();
            List<HttpMethodConstraintElement> methodConstraints =
            new ArrayList<HttpMethodConstraintElement>();
           //Allow GET access only to a user in role javaee
            methodConstraints.add(new HttpMethodConstraintElement("GET",
                new HttpConstraintElement(TransportGuarantee.NONE, new String[]{"javaee"})));
           //Allow POST access only to a user in role javaee and when the Transport is Secure
            methodConstraints.add(new HttpMethodConstraintElement("POST",
                new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL, new String[]{"javaee"})));
           //Deny Trace access.
            methodConstraints.add(new HttpMethodConstraintElement("TRACE",
                new HttpConstraintElement(EmptyRoleSemantic.DENY)));
            ServletSecurityElement servletSecurityElement =
                new ServletSecurityElement(constraint, methodConstraints);
           //set the Servlet Security Constraints on ServletRegistration.Dynamic
            sr.setServletSecurity(servletSecurityElement);
        } catch (Exception e) {
            sce.getServletContext().log("Error during contextInitialized");
            throw new RuntimeException(e);
        }

    }

    public void contextDestroyed(ServletContextEvent sce) {
        //NOP;
    }
}


The comments in the code above show what security-constraints are being added. Note that we used the default constructor forHttpConstraintElement this would set the EmptyRoleSemantic value to PERMIT, which means allow access to all. It is equivalent to a <security-constraint> element with no <auth-constraint>.  And then the code above creates  a list of HttpMethodConstraintElement's which specifies the method level security constraints. 

Deploy the attached Netbeans project and specify the following URL in the browser to exercise the doGet method :

http://localhost:8080/DynamicServlet/newServlet

Note that the servlet that was added from the context listener had a url-mapping to /newServlet.  Since we have specified that GET access should be allowed only for users in role "javaee" so the container would force an authentication here. Before deploying  the sample make sure you create a new File User in the adming console and make sure that the user belongs to a group with name "javaee". Then enable Default Principal to Role Mapping under the Security Tab in the admin-console.

Other Security Features in Servlet 3.0

My previous post shows the use of @ServletSecurity element and my team member nithya has posted information on two other features.

 

1. The authenticate() method on HttpServletRequest

2. The http-method-omission element

There is another method on javax.servlet.HttpServletRequest  which we have not talked about :
public void login(String username, String password)  throws ServletException; here is the javadoc for this method :


 

void login(java.lang.String username,
           java.lang.String password)
           throws ServletException
Validate the provided username and password in the password validation realm used by the web container login mechanism configured for the ServletContext

This method returns without throwing aServletException when the login mechanism configured for the ServletContext supports username password validation, and when, at the time of the call to login, the identity of the caller of the request had not been established (i.e, all of getUserPrincipal,getRemoteUser, and getAuthType return null), and when validation of the provided credentials is successful. Otherwise, this method throws aServletException as described below.

When this method returns without throwing an exception, it must have established non-null values as the values returned bygetUserPrincipal, getRemoteUser, andgetAuthType

Parameters:
username - The String value corresponding to the login identifier of the user.
password - The password Stringcorresponding to the identified user.
Throws:
ServletException - if the configured login mechanism does not support username password authentication, or if a non-null caller identity had already been established (prior to the call to login), or if validation of the provided username and password fails.
Since:
Servlet 3.0

 


The login method of the HttpServletRequest interface provides an alternative means for an application to control the look and feel of it’s login screens (as an alternative to Form-Based Login). 

 NOTE: an bug on this site is preventing me from attaching the sample code. Will get back once the bug is fixed.

Shing Wai's post explains the @ServletSecurity annotation that has been introduced newly in JavaEE 6 (Servlet 3.0 specification). The @ServletSecurity annotation provides an alternative mechanism for defining access control constraints equivalent to those that could otherwise have been expressed declaratively via security-constraint elements in the portable deployment descriptor. There is also a Programmatic approach for adding security (via ServletRegistration.Dynamic API) that has been introduced newly in JavaEE 6, i will talk about it in another post.

Using the @ServletSecurity annotation one can now have a descriptor free secure WebApplication in Glassfish V3. And using the fact that the default mode in calls to enterprise beans from web applications is for the security identity of a web user to be propagated to the EJB container, we can actually have a secure enterprise application without any security information in the portable deployment descriptors.

So let us define an example Servlet which invokes a Secure EJB (A currency converter bean). The ServletSecurity annotation on the servlet below is such that any authenticated user in role "TutorialUser" or "guest" is allowed access to the Servlet. However the Converter EJB would only allow a user in role "TutorialUser" to access its methods. The ServletSecurity annotation below is equivalent to the following <security-constraint> element.

<security-constraint>
<web-resource-collection>
<url-pattern>/TutorialServletBASIC</url-pattern>
</web-resource-collection>
<auth-constraint>
<security-role-name>TutorialUser</security-role-name>
<security-role-name>guest</security-role-name>
</auth-constraint>
</security-constraint>



package test;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name="TutorialServletBASIC", urlPatterns={"/TutorialServletBASIC"})
//for all HTTP methods, auth-constraint requiring membership in Role TutorialUser or guest
@ServletSecurity(@HttpConstraint(rolesAllowed = {"TutorialUser", "guest"}))
public class TutorialServletBASIC extends HttpServlet {
    @EJB
    private ConverterBean converterBean;
    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
           
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet TutorialServletBASIC</title>"); 
            out.println("</head>");
            out.println("<body>");
            BigDecimal result = converterBean.dollarToYen(new BigDecimal("1.0"));
            out.println("<h1>Servlet TutorialServlet result of dollarToYen= " + result + "</h1>");
            out.println("</body>");
            out.println("</html>");
           
        } finally {
            out.close();
        }
    }
   
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
}


 

Now let's look at the NoInterface Converter EJB, which only allows TutorialUser roles to invoke its methods.

 



package test;

import java.math.BigDecimal;
import javax.ejb.*;
import java.security.Principal;
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;

@Stateless()
@DeclareRoles("TutorialUser")
public class ConverterBean {

    @Resource
    SessionContext ctx;
    private BigDecimal yenRate = new BigDecimal("96.0650");
    private BigDecimal euroRate = new BigDecimal("0.0078");

    @RolesAllowed("TutorialUser")
    public BigDecimal dollarToYen(BigDecimal dollars) {
        BigDecimal result = new BigDecimal("0.0");
        Principal callerPrincipal = ctx.getCallerPrincipal();
        if (ctx.isCallerInRole("TutorialUser")) {
            result = dollars.multiply(yenRate);
            return result.setScale(2, BigDecimal.ROUND_UP);
        } else {
            return result.setScale(2, BigDecimal.ROUND_UP);
        }
    }

    @RolesAllowed("TutorialUser")
    public BigDecimal yenToEuro(BigDecimal yen) {
        BigDecimal result = new BigDecimal("0.0");
        Principal callerPrincipal = ctx.getCallerPrincipal();
        if (ctx.isCallerInRole("TutorialUser")) {
            result = yen.multiply(euroRate);
            return result.setScale(2, BigDecimal.ROUND_UP);
        } else {
            return result.setScale(2, BigDecimal.ROUND_UP);
        }
    }
}


 

 We are done with the application, there is no need to add any security information to any deployment descriptors. You will ofcourse need to go to the admin console and enable the "Default Principal to Role Mapping" feature  (Configuration -> Security tab) and create two file-users who are assigned to groups named "guest" and "TutorialUser" respectively.

 

Then build the attached project using Netbeans 6.8 M2 (or latest 6.8 builds) and deploy on GlassFish V3. Then you can try accessing the Servlet URL :


http://localhost:8080/TutorialEAR-war/TutorialServletBASIC

Your browser would then pop-up the BASIC authentication username-password dialog.  You will see that if you specify a user in group TutorialUser as the username then the servlet can successfully invoke the Converter Bean and return a result, but when you login as  user in the "guest" group,  it would throw the following exception when the servlet tries to invoke the  EJB.

 



Caused by: javax.ejb.AccessLocalException: Client not authorized for this invocation.
        at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1801)
        at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:188)


 

One question that would come to mind is where did we specify BASIC authentication for the Servlet . The answer is that the RI establishes BASIC authentication as the default when no auth-method is specified, but the request is for an auth-constrained resource.


In this post i would like to provide a brief summary of some of the Propietary Features and implementation details of SAAJ 1.3.4 that are not necessarily related to the SAAJ API specifications. 


Creating SOAPMessages with Very Large XML Payload

The JavaDoc  of the API method SOAPMessage.saveChanges() poses a problem for the implementation by specifying that "All MIME headers in a message that is created for sending purposes are guaranteed to have valid values only after saveChanges  has been called".  Specifically the RI would try to set the Content-Length header after a  saveChanges() call and for that it would try to buffer the message contents. This prevents the RI from creating a message with a huge payload. There would be an exception of the following form  when the test method below is executed :

Caused by: java.lang.OutOfMemoryError: Java heap space
        at com.sun.xml.messaging.saaj.util.ByteOutputStream.ensureCapacity(ByteOutputStream.java:111)
        at com.sun.xml.messaging.saaj.util.ByteOutputStream.write(ByteOutputStream.java:95)
        at com.sun.xml.messaging.saaj.util.JAXMStreamSource.<init>(JAXMStreamSource.java:63)
        at com.sun.xml.messaging.saaj.soap.SOAPPartImpl.setContent(SOAPPartImpl.java:243)
        at com.sun.xml.messaging.saaj.soap.MessageImpl.init(MessageImpl.java:406)


So SAAJ 1.3.4  has introduced a System Property : saaj.lazy.contentlength which would allow the RI to set the Content-Length header lazily when the SOAPMessage is finally being serialized. While setting this property lazily violates the SAAJ API javadoc statement above, it would allow handling of large payloads by the RI.

 public static void testSAAJIssue50() throws Exception {
       System.setProperty("saaj.lazy.contentlength", "true");
        MessageFactory mf = MessageFactory.newInstance();
        MimeHeaders hdrs = new MimeHeaders();
        hdrs.addHeader("Content-Type", "text/xml");
        //bigmessage.xml is a BIG SOAP Envelope
        SOAPMessage created = mf.createMessage(hdrs, new FileInputStream(new File("bigmessage.xml")));
        created.saveChanges();
        String[] cls = created.getMimeHeaders().getHeader("Content-Length");
        if (cls != null) {
           System.out.println("After saveChanges() Content-Length =" + cls[0]);
        } else {
           System.out.println("After saveChanges() Content-Length =" + 0);
        }
        created.writeTo(new FileOutputStream(new File("bigmessage1.xml")));
        cls = created.getMimeHeaders().getHeader("Content-Length");
        System.out.println("After writeTo() Content-Length =" + cls[0]);
    }

Executing the above test after setting the System property will produce an output as follows :

After saveChanges() Content-Length =0
After writeTo() Content-Length =77376973

Note: The SAAJ RI design did not have any Configuration support and due to the lack of time i resorted to the use of  system properties for enabling this proprietary behavior. In future i may think of adding some Configuration support though it is again unlikely to be something in the standard SAAJ-API specification.

Enhancements in the RI for Handling Very Large MIME Messages

SAAJ RI by default cannot handle incoming SOAP Messages having Large Attachments. See issue 31for more details. The MimeMultipart representation in SAAJ RI borrowed from the original JavaMail implementation cannot handle very large MimeParts since it stores them in Memory and the SAAJ API AttachmentPart directly refers to the MimePart. The SAAJ API is also streaming un-friendly since it has a methods  SOAPMessage.getAttachments()  and SOAPMessage.getAttachments(...).  So what was required was a MimeMultipart implementation that can handle large Mime Parts. The MimePull project uses several smart techniques including the use of the File-System and split-representation (part memory and part file-system) to handle large Mime-Parts.  In SAAJ RI 1.3.4 one can instruct the SAAJ RI runtime to use the MimePull parser by setting the system property   "saaj.use.mimepull" to "true".  This would allowing handling of  large attachments in incoming messages. The comments in  issue 31shows a sample test code which makes use of this property. 

One thought was to make the use of MimePull the default in SAAJ RI,  however i heard from the MimePull project lead that one thing it does not handle right now is any kind of non-default Content-Transfer-Encoding (such as base64 for example).  Furthermore the MimePull API is meant purely for parsing incoming Mime Messages (and not for creating a Mime Package with Large Attachments) whereas one can do crazy things with the SAAJ API like setting the content of a received attachment part again and recreating a new SOAPMessage etc. While the latter issue has been handled the  issue of Content-Transfer-Encoding prevented me from making the use of  MimePull as the default. In future we should see the use of  MimePull as the default in SAAJ RI. 

The MimePull parser has configuration support that allows one to configure the Limits and Thresholds but the SAAJ RI just creates and uses a default configuration object. In future we could consider exposing the MimePull parser configuration in SAAJ RI.

When using the MimePull feature make sure that you close the InputStream of the Large AttachmentPart after you are done with it, this should allow the MimePull runtime to release any resources that the MimePart associated with this attachment is holding onto. For example :

AttachmentPart ap = ..... //get the attachment part from the SOAPMessage

InputStream is = ap.getRawContent();

OR

InputStream is = ap.getDataHandler().getInputStream();

try {

//use the inputstream

} finally {

  //finally close the stream

    try {

      is.close();

   }catch (IOException e) {

  }

}

When using getRawContentBytes() api, the SAAJ RI would close the inputStream. There was a bug that ap.clearContent() does not call close() on the MimePart. This has been fixed in the latest trunk after the 1.3.4 release and you can obtain the latest SAAJ 1.3.4 update bits  (saaj.1.3.4.zip) with this fix from here.

 As early as SAAJ 1.3.2,  the SAAJ RI introduced the use of the Boyer-Moore algorithm for efficient Mime-Boundary Parsing of a Mime Packaged Message. Prior to this SAAJ was using the Mime Parsing code present in JavaMail. The switch to Boyer-Moore provided 20-30%  improvement in Mime-Parsing performance. The Boyer-Moore algorithm was then re-implemented in JavaMail and lately the MimePullproject uses the same Boyer-Moore implementation as in JavaMail.

However when i introduced the Boyer-Moore implementation in SAAJ 1.3.2 as the default, i was afraid of having missed some boundary conditions (not detected by our existing tests), especially i found that the original JavaMail implementation was somewhat lenient in that it accepted messages which had minor violations w.r.t  (RFC 2045), i cannot recollect exactly what they are now, need to dig up my old notes. So there is a System property in SAAJ  "saaj.mime.optimization" which has value "true" by default but can be set to "false" to switch-off Boyer-Moore and fallback to the old JavaMail Mime-Boundary parsing implementation. Ever since, we did have a few users report issues with the Boyer-Moore implementation and we fixed them.

SAAJ RI in its very early days was also trying to eagerly load all the attachments in an incoming message. We changed this behavior in SAAJ 1.3.2 timeframe but provided a way to fall back to the eager loading scheme incase someone needs it. For this one can set the system property "saaj.lazy.mime.optimization" to "false".  This optimization has limited utility in the absence of MimePull especially when seen in the context of  SOAPMessage.getAttachments()  and SOAPMessage.getAttachments(...) apis.  However it does help a scenario where an intermediate (SOAP Handler) recives a large MimeMessage but never needs to look at the Attachments (but only needs to read/manipulate the SOAP Envelope/Body) before resending the message to an ultimate recipient.

One property  which is only available in the latest builds  (saaj1.3.4.zip) is the system property  saaj.mime.multipart.ignoremissingendboundary  its default value is true and needs to be set tofalse to indicate that the SAAJ runtime should report an error if the Multipart Mime Package has a missing end boundary. This feature was requested by an end user recently on the lines of what is supported in Java Mail. Note that this feature does not work when one enables saaj.use.mimepull .   


Some Other Features of the SAAJ RI

The SAAJ RI makes use of a ParserPool (a pool of SAXParser's) and this provides upto 15% reduction in time taken when 1000's of messages are being parsed. There is a JAXP issue which prevents SAAJ RI from cleanly using a Pool of Parsers, and a workaround for this has been currently used in SAAJ RI 1.3.4. The issue was reported by one of the SAAJ users and more details are in Issue 46.  The Old implementation of the ParserPool itself was inefficient and was upgraded in 1.3.4 to make use of the BlockingQueue from the java.util.concurrent pacakge. This fix was provided by an external user (kevinconaway) as a patch.

The SAAJ RI has had support for handling incoming messages that are  Fast-Infosetencoded since SAAJ 1.3.2 and there is support for handling MTOM encoded messages as well.  Both MTOM with SOAP 1.1 and SOAP 1.2 are supported. There was an issue in MTOM handling and again that was fixed in SAAJ RI 1.3.4, a patch was provided by an external user (jeremyhuiskamp). This is primarily to support the SOAPHandlers in JAXWS 2.X. There is no way to actually create FI or MTOM encoded messages using the SAAJ API's directly.

There was an issue of poor performance with large payloads (Issue 42) and this was due to a Xalan issue (JAXP issue 48). People reading this post should make sure that they either use the steps mentioned in Issue 42 to solve this problem or get the right version of JDK Update release that has the fix for  JAXP Issue 48.

The Java KeyStore API supports multiple keystore formats which include JKS( the default Java KeyStore), PKCS12, PKCS11 etc. By default when GlassFish V3 is installed the default Keystore Type is JKS and the server keystore (keystore.jks) is located in the domain config directory.  With latest GlassFish V3 builds it should be possible to define a different KeyStore Type such as PKCS11 or PKCS12 for the KeyStore type and use a corresponding PKCS11 or PKCS12 store as the server keystore.

Here are the steps to configure GlassFish V3 with a PKCS12 keystore as the server keystore. All the steps mentioned here can be achieved by using the Admin GUI however i would just show the resultant change in domain.xml

1. Install the PKCS12 (.pfx/.p12) Keystore inside the domain config dir (such as domains/domain1/config). Assuming the name of the KeyStore is s1as.p12 copy the file into the config dir

2. Update the jvm-options corresponding to keystore and truststore settings to look as follows :

           <jvm-options>-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks</jvm-options>
        <jvm-options>-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/s1as.p12</jvm-options>
        <jvm-options>-Djavax.net.ssl.keyStoreType=PKCS12</jvm-options>
        <jvm-options>-Djavax.net.ssl.trustStoreType=JKS</jvm-options>

3.  In V3 the network-listener corresponding to secure port 8181 is disabled by default. So set the enabled attribute to true on network-listener corresponding to 8181

4.  Make sure the SSL child element under the protocol configuration for http-listener-2 looks as below (specifically remove the  cert-nickname="s1as" attribute since we now use a PKCS12 Keystore containing the Public/Private KeyPair).

             <protocol security-enabled="true" name="http-listener-2">
            <http max-connections="250" default-virtual-server="server" server-name="">
              <file-cache enabled="false" />
            </http>
            <ssl ssl3-enabled="false" />
          </protocol>

 5. If the server ceritificate contained in your PKCS12 keystore is issued by a tursted CA then make sure the CA certificate appears inside the glassfish truststore (cacerts.jks). Incase you are using self-signed certificates inside the PKCS12 keystore then make sure you import the server certificate into glassfish truststore.

6. save the changes, restart glassfish  and try to accesshttps://localhost:8181. This should take you to the GlassFish Server Welcome page.

 For my testing i had to use the default s1as  KeyPair that comes with the GlassFish default installation (residing inside keystore.jks). So here are the steps to export the s1as keypair as a PKCS12 keystore.

  a) Export the server certificate

     keytool -export -file s1as.der -keystore keystore.jks -storepass <GF-password> -alias s1as

  b) Export the Private Key for the server in PEM (Privacy Enhanced Mail)  format. Use the KeyExport tool for doing this (download keyexport.zip here)

  c) unzip keyexport.zip to find the jar file keyexport.jar

  d) run the following command to export the private key :

    java -cp keyexport.jar com.sun.xml.wss.tools.KeyExport -keyfile s1askey.pem  -alias s1as -keystore <GF-DOMAIN-CONFIG-DIR>/keystore.jks -outform PEM -storepass <GF-password> -keypass <GF-password>

  e) Convert the DER encoded certificate from step (a) into PEM format as well

     openssl x509 -in s1as.der -inform DER -out s1as.PEM -outform PEM

  f)  Concatenate the  Certificate and PrivateKey PEM files into a single file. In mycase i would append the private key file to the certificate file. So that the file looks as follows :

-----BEGIN CERTIFICATE-----

.....

-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----

......

-----END PRIVATE KEY-----

 g) Now use openssl again to convert the concatenated Certificate + PrivateKey into a PKCS12 keystore

openssl pkcs12 -export -in s1as.PEM -out s1as.p12
Enter Export Password: <enter GF-password>
Verifying - Enter Export Password: <enter GF-password again>

The last step above creates the s1as.p12 which is a PKCS12 keystore that can be used as the GlassFish Server Keystore.

 

 





 



Metro Security has a pluggable architecture and it makes use of JSR 196  (SOAP Profile) to achieve this pluggability.   The use of JSR-196 provides a standard way to integrate Metro with the Authentication and Authorization Infrastructure of the underlying container.  Though not all containers  on which metro can run today support JSR 196, the idea is that as more and more containers adopt JSR-196, integrating the metro webservices stack with those container would become easy. The use of JSR-196 in metro is also based on the principle of  re-using what is already a standard inorder to avoid proliferation of proprietary API's.

  In the absence of JSR-196, when Metro is used on a Non-GlassFish container then developers of  Secure WebServices today are forced to configure a whole lot of things such as CallbackHandler's, Validator's, Keystore's, CertStore's etc, some of which can be non-trivial.  All of these configurations would not be necessary if  the container supported a publicly callable JSR-196 CallbackHandler that metro could use. 

When a Metro Secure WebService runs on GlassFish it automatically leverages  the Container's Authentication and Authorization Mechanisms by way of invoking the GlassFish JSR-196 CallbackHandler, so user's of metro on GlassFish would generally not have to configure  additional things inside the metro configuration file w.r.t security. Metro runtime would invoke the GlassFish JSR-196 CallbackHandler. The GlassFish CallbackHandler would use the container configured mechanisms to authenticate let's say the username-password and finally establish the container's representation of the caller principal in the Subject. This Subject would then be used during the Authorization process.

Metro bundles the JSR-196 API along with it so that one can use  Metro with JSR-196 enabled on any Container (not just GlassFish). So here are  some of the pluggability points that are enabled in metro due to the use of JSR 196 underneath.

  1.  At the lowest level one can specify  a JSR 196 CallbackHandler on the client and server side to be used by the metro configuration. A JSR 196 Callbackhandler is a callbackhandler that handles the callbacks defined by the JSR-196 specification. More details on how end-users can specify a JSR-196 callbackhandler  can be found in this post here (look for section : JMACCallbackHandler). This facility can be used only when running on GlassFish.  When specified it overrides the GlassFish default Callbackhandler.
  2.  By default only JSR-109 WebServices on GlassFish make use of the JSR-196 path but one can enable the use of JSR-196 for Plain-JAXWS applications as well by placing the following (gf-196-hook.jar) into GlassFish lib directory. This maybe fixed in near future such that all webservices on glassfish would use JSR-196 path. However we get bitten by the same old backward-compatibility bug that prevents us from eagerly doing it.
  3. The Metro WS-* implementation makes use of the  JAXWS Tubes SPI . This  allows composing different Tubes in a Tubeline in a certain order to make the different WS-* implementations work together and produce the desired transformation on the WebService Messages.  The Security Tube in Metro in turn uses JSR-196 and thereby allows someone to replace the default JSR-196 AuthConfigProvider in Metro with something of their own. This feature is used by the OpenSSO stack when it replaces the WS-Security Implementation in Metro with it's own implementation for a few product specific reasons. The use of JSR-196 decouples the Security Tube from the Specifics of the WS-Security Implementation thereby allowing a different WS-Security implementation to be plugged in (complete with its own configuration definitions etc).   This feature is available when Metro Stack in running on any container including GlasssFish. Again for backward-compatibility reasons this feature is currently not enabled by default in Metro, but can be enabled by placing (wsit-196-hook.jar) in the containers classpath (for example the lib directory in GlassFish V2). There is a META-INF/services entry inside  wsit-196-hook.jar named javax.security.auth.message.config.AuthConfigProvider  whose contents point to the default Metro AuthConfigProvider (ACP).  If someone needs to plugin their own ACP then they would need to update this entry with the classname of their ACP implementation classs.

When using Pluggability Option 3 above one has to be aware of (and handle) three Container/Environment specific issues.

  1. The Keying Infrastructure and Container's Representation of caller Principal/Groups differ from container to container and so the JSR-196 CallbackHandler comes to the rescue here.  There are a few limitations when it comes to the set of Callbacks defined in the JSR-196 standard versus those required in a typical WS-Security scenario (for example the JSR-196 callbacks do not have any callback to handle CertificateValidation which is generally an important thing in a Mutual Certificates Scenario). However the JSR-196 standard does not prevent CallbackHandlers to handle other proprietary callbacks. So metro defines a few extension callbacks to deal with this.   There is a  META-INF/services entry inside wsit-196-hook.jar named javax.security.auth.message.callback.CallbackHandler  whose contents by default point to the correct classname of the JSR-196 CallbackHandler for GlassFish V2. When running on a different container one would need to update this services entry with the right classname of the JSR-196 CallbackHandler to be used on that container.

    2.  The place where the Metro Security-Tube needs to finally place the JSR-196 javax.security.auth.Subjectobject such that it gets used for Authorization decisions on the Container is again not defined in any standard. For example on GlassFish this subject is to be set into a  GlassFish specific SecurityContext object .  For other containers it maybe something else. So there is a META-INF/services entry inside wsit-196-hook.jar named com.sun.xml.ws.security.spi.SecurityContext.  The default value of this entry points to an implementation of the following SecurityContext interface that does the correct thing for GlassFish V2.

package com.sun.xml.ws.security.spi;
import javax.security.auth.Subject;

/**
 * Provides
 * 1. a way to obtain credentials from an
 * encompassing runtime into the Metro Pipeline runtime
 * 2. API to set the credentials after authentication as understood
 * by the container
 *
 */
public interface SecurityContext {
    /**
     * @return the subject containing credentials from the encompassing runtime, null if none is available
     */
    public Subject getSubject();
   
    /**
     * Set the subject after message authentication as understood by the container
     * @param subject
     */
    public void setSubject(Subject subject);
}

     3. Another thing which is again handled by appropriately defining  the META-INF/services entry for the above defined SecurityContext is the fact that when there are credentials established by the encompassing runtime under which the SOAP layer webservice interaction is happening  (for example an authetication at the transport layer or an SSO Token) then one needs to make the SecurityContext established by the encompassing runtime available to the SOAP layer interaction. Again there is no standard that defines how to obtain this information from the encompassing runtime and hence the mechanism differs from Container to Container (For example, in GlassFish it is again the same SecurityContext object that needs to be retrieved).

  As stated above the JSR-196 path is not enabled by default for Non-GlassFish containers, and i mentioned backward-compatibility as the reason. There is some work involved to package the Non-196 path as a JSR-196 Authentication module and once that is done then pluggability option 3 above can be made the default in metro. We may do this in the near future.

My previous post Security Token Configuration in Metro has exceeded the maximum limits (even after having used the extended entry) of a post and hence when i added some more details yesterday, i am seeing that the tail end of my post was truncated. So here is what was in the tail end... 

Appendix

    Here is  the complete abstract schema for CallbackHandlerConfiguration and ValidatorConfiguration elements in Metro. I decided to paste the complete configuration here because for these two elements the configuration has been shown in bits and pieces under different tokens (as relevant).

<sc:CallbackHandlerConfigurationwspp:visibility="private"xmlns:sc="http://schemas.sun.com/2006/03/wss/{server  or client}"
        timestampTimeout="{Timeout value in Second(s) : This value is used to compute the Expiry time of the WSU:Timestamp being sent in the message, value specified should be greater than zero}"
        useXWSSCallbacks="{Value true indicates use XWSS Callbacks in place of Standard J2SE callbacks for Non-109 App. For 109 Apps a value true indicates passing RuntimePropertiesCallback as an Extra Callback to CallbackHandler}" >
       <sc:CallbackHandler  name="usernameHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.NameCallback}"
        default="{the default username value as a string, to be provided incase classname is  not provided}" />
       <sc:CallbackHandler  name="passwordHandler"  classname="{a callbackhandler  classname that handles javax.security.auth.callback.PasswordCallback}"
        default="{the default password value as a string, to be provided incase classname
        is not provided}"  />
       <sc:CallbackHandler  name="samlHandler"  classname="{a callbackhandler  classname that  handles com.sun.xml.wss.impl.callback.SAMLCallback}"/>

       <sc:CallbackHandler  name="jmacCallbackHandler" classname="{a callbackhandler  classname that  handles all the Standard JSR 196 Callbacks}" />
       <sc:CallbackHandler  name="xwssCallbackHandler"  classname="{a callbackhandler  classname that  handles all the XWSS Callbacks}" />
</sc:CallbackHandlerConfiguration>

   <sc:ValidatorConfigurationwspp:visibility="private"xmlns:sc="http://schemas.sun.com/2006/03/wss/{server  or client}"
sc:maxClockSkew="{The assumed maximum skew (milliseconds) between the local times of any two systems, runtime defaults used when not specified}"
sc:timestampFreshnessLimit="{The period (milliseconds) for which a Timestamp is considered fresh, runtime defaults used when not specified }
sc:maxNonceAge="{The length of time (milliseconds) a previously received Nonce value in a UsernameToken will be stored, runtime defaults used when not specified}"
sc:revocationEnabled="{If this flag is true, the default certificate revocation checking mechanism of the underlying PKIX service provider will be used. If this flag is false, the default revocation checking mechanism will be disabled (not used).}">

<sc:Validator name= "usernameValidator"  classname={class name of a usernameToken Validator,
    should implement com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator }/>

    <sc:Validator  name="timestampValidator" classname ={class name of a Timestamp Validator,
    should implement com.sun.xml.wss.impl.callback.TimestampValidationCallback.TimestampValidator,  a default Timestamp validator from Metro runtime used when not supplied} />

    <sc:Validator  name="certificateValidator" classname ={class name of a certificate Validator,
    should implement com.sun.xml.wss.impl.callback.CertificateValidationCallback.CertificateValidator,
    default Certificate validator from XWSS runtime used when not supplied} />

<sc:Validator name="samlAssertionValidator" classname = {class name of a SAML Assertion Validator, should implement com.sun.xml.wss.impl.callback.SAMLAssertionValidator,
    Partial validation (in the form of verifying enveloped signature) occurs on SAML Assertion within  the WSIT/XWSS 3.0 Runtime even if the validator is not specified} /> ?
</sc:ValidatorConfiguration>

 How does Metro Pickup the Certificate to use for Response Encryption

With so many different ways of configuring things one might ask the question how does metro pickup the certificate for response encryption to the client.  So here are the abstract steps that metro uses in that order of preference :

1. if peeralias is specified then use it (not practical in real world apps since a service would have many clients)
2. if a certstore was specified then look for the cert in the certstore using the specified CertSelector
3. if a truststore CertSelector was specified use that to locate the cert
4. if the request contained a certificate use that certificate for the response
5. Pick the first one from the truststore (this was a legacy feature from early metro days and it would work well when your truststore has just one cert that of the client , you never need to configure anything then, there is a TODO comment to remove this piece of code and we don't expect metro users to use this option)

On step 4 metro currently has a limitation that only if the Certificate of the client appears as a Binary Security Token in the message then metro tries to use it for response encryption. However this can  be improved since even an indirect reference to the client certificate should also cause metro to make use that certificate for response encryption. The opportunity is rare though because usually the server never stores the certificates of its client inside it's certstore/truststores.

The earliest version of WS-SecurityPolicy implemented during early days of Metro/WSIT did not allow Binding Assertions to be attached to any scope other than the EndPoint scope. The latest versions of WS-SecurityPolicy specification allows Binding Assertions to be attached to operation scope.

We had a bug in our Metro code which prevented this from working correctly all these days. With latest metro 2.0 nightly builds starting 2nd July you should be able to use this feature.

My team member suresh has nore details on it here We have also asked our NetBeans Plugin Expert to make this feature available via NetBeans. Until then you would have to manually place the policy references at the operation scope.

In this post, i  would like to describe how to configure various types of security tokens that Metro supports. There are various aspects to token configuration depending on the type of the token and the article i wrote long ago is outdated, things have changed for good and i will talk about it here.

The details in this entry would be applicable to Metro 2.0 EA (to be released for JavaOne 2009) and Metro 2.0 Final Release. I would not be at JavaOne 2009 but the Metro Architect Harold and Jiandong (Lead for WebServices Trust and SecureConversation implementation in Metro) would present a Technical Session : Metro Web Services Security Usage Scenarioson Thursday, June 04, 9:30 AM - 10:30 AM Hall E 134. So if you are attending JavaOne 2009do plan to go for the session.

The WS-SecurityPolicy specification defines a whole set of token assertions that can be used for securing SOAP messages. Metro supports some of them. The token assertions are abstract declarations of the type of token to be used and can contain other information such as claims, reference types etc. The abstract token assertions need to be bound to concrete physical tokens from the runtime environment for Metro to be able to secure the messages. The notation for establishing this binding is not defined in any specification and hence each vendor implementation would have its own proprietary way of doing this. In this blog i would describe how the binding is done in Metro.  The binding in metro is essentially expressed in terms of  proprietary token configuration assertions inside the Metro client and server side configuration files. More details about writing metro client and server side configuration files can be found here.   Metro attempts to move this binding to a standard API JSR 196CallbackHandler and Callbacks defined by the JSR (in other words the entire configuration for various tokens can be achieved by implementing a single CallbackHandler and configuring the CallbackHandler in the client and server side metro configuration files). However the result is not a totally clean binding (devoid to proprietary stuff). This is because JSR 196 defines a minimal set of necessary callbacks but we endup requiring other types of callbacks when handling WS-Security. To this effect the JSR 196 specification does allow the Callback Handler to handle other types of callbacks where necessary.

Note that there is support in NetBeans for most (if not all) of the configurations described in this post.  This post is very informal and is a prelude to Documentation that would eventuall appear. However it contains the set of all configurations (some of which were probably not publicly documented before).

Underlying Architecture for Token Configuration

 Before describing the token configuration details it would help if i describe how the metro security runtime tries to obtain the configuration. As metro security involved from early days in 2004 we realized two things :

1. The use of the JAAS CallbackHandler for obtaining Tokens especially username/password is a standard approach in Java.

2. Metro has to run in different enviroments/containers and there could be different set of Callback Vocabularies in different environments. For example Pre-Metro XWSS defined its own set of  Callbacks and JSR 196 defines another set of standard Callback subset in the javax package.

 So it was clear that Metro Security runtime cannot depend on any specific set of Callback's if it were to run on different environments, but instead should utilize the callback vocabulary of the target container on which it is running. Accordingly the Metro Security runtime defines an Internal SPI called SecurityEnvironment which has necessary methods for retrieving Tokens of various types, possibly using some search criteria (for example locate a certificate which has a given IssuerName and IssuerSerial value). Then there are different default implementations of this SPI within metro and the right implementation is picked up based on the environment. The SPI implementation would then invoke the container/environment specific callbackhandler. So one can expect that the configuration required by metro would be influenced to some extent by the configuration needed by the underlying CallbackHandler used by the container (although the general design goal is to make the configuration agnostic to the underlying CallbackHandler of the target container).

In this post you would see the use of term CallbackHandler and Validator at several places and the way these pieces fit together is that metro has two default implementation's of the SecurityEnvironment SPI,  one implementation used for all  Non-GlassFish containers and also for GlassFish Non-109 deployments and another implementation of the SPI for GlassFish 109 deployments.  This is because 109 deployments on GlassFish can levarage the Default JSR 196 CallbackHandler implemented by GlassFish. Using a native CallbackHandler supported by the container results in less configuration required in the Metro configuration file(s), although it may put some external (container specific) configuration requirements.

So the first implementation of the SPI invokes  a Metro DefaultCallbackHandler (which operates on the Metro/XWSS specific Callback vocabulary) and the second implementation invokes the JSR 196 CallbackHandler of GlassFish. So the DefaultCallbackHandler in the first case is a Gigantic Wrapper which would inturn delegate to any CallbackHandler(s) and Validator(s) specified in by the developer in the Metro configuration files.  In the  second case it turns out that the JSR 196 Callback vocabular is actually a subset of what would be required in a WS-Security environment and hence the SecurityEnviroment SPI uses a Mixed approach.  If a JSR 196 Callback exists for a particular case it would  invoke the JSR 196 CallbackHandler by default unless overriden by a metro specific configuration. If a JSR 196 Callback does not exist (or was overriden) for a task then it would directly invoke any CallbackHandler(s) and Validator(s) specified by the developer in the Metro configuration.

 Note: It is possible for GlassFish Non-109 (plain-jaxws) webservice deployments to make use of the JSR 196 dependent SecurityEnvironment SPI implementation. This can be achieved by placing the jar gf-196-hook.jar in the lib directory of GlassFish and re-starting GlassFish.

  Metro Security supports the following token assertions defined in the WS-SecurityPolicy specfication :

  • Timestamp Token
  • Username Token
  • X509Token
  • SAML Token
  • Kerberos Token
  • Issued Token 
  • SecureConversation Token

The last one is not an authentication token but metro allows certain configuration for it and hence i have mentioned it there.  

Let us look at the token configuration details for various tokens supported by Metro. We would also refer to them as Configuration Assertions in this post since they are really proprietary assertion's using the same WS-Policy syntax. One might wonder if it could cause some interoperability problems but the fact of matter is that these assertions are required to bind the various aspects of the  Token Assertions to phyiscal entities, and these assertions are marked with Visibility attribute private stating that the other party importing the WSDL would not see these assertion.  

Token Configuration for the Timestamp Token

 

The timestamp token can appear in both request and response messages and hence the configuration described here applies to both the client and server side with the exception that the namespace of the configuration would be http://schemas.sun.com/2006/03/wss/serveron the server side and http://schemas.sun.com/2006/03/wss/clienton the client side, However different configurations apply to an outgoing timestamp and an incoming timestamp.  .  

Note that this namespace distinction described here applies to all configuration assertions that can appear on both the client and server side and i may not emphasize this again in this post.

Outgoing Timestamp Configuration

 

For an outgoing timestamp the Expires time as shown in the sample timestamp token  (timeout interval) can be controlled.

         <wsu:Timestamp wsu:Id="3">
            <wsu:Created>2009-05-30T06:14:45Z</wsu:Created>
            <wsu:Expires>2009-05-30T06:19:45Z</wsu:Expires>
         </wsu:Timestamp>


So the required configuration is an attribute timestampTimeout on the CallbackHandlerConfiguration. This can appear on both the client and server side with appropriate namesapce.
<sc:CallbackHandlerConfiguration
        timestampTimeout="{Timeout value in Second(s) : This value is used to compute the Expiry time of the WSU:Timestamp being sent in the message,
value specified should be greater than zero}"/>

 

 

 The default value for timestampTimeout is 5 seconds.

Configuration for an Incoming Timestamp

 

 And incoming Timestamp needs to be validated and the set of configuration to control this validation process is described in the following post. The configuration described in the post are about configuring the default timestamp validation process in Metro. However one can optionally take the complete timestamp validation into their own hands by configuring a TimestampValidator assertion under the ValidatorConfiguration. See the abstract schema below.

<sc:ValidatorConfiguration ../>

<sc:Validator  name="timestampValidator" classname ={class name of a Timestamp Validator,
    should implement com.sun.xml.wss.impl.callback.TimestampValidationCallback.TimestampValidator,
    a default Timestamp validator from XWSS runtime is used when not supplied} />

</sc:ValidatorConfiguration>

The attributes described in the post would then have no effect when someone configures a Validator for timestamps.

Note: In this post i am showing the  child assertions of  CallbackHandlerConfiguration and ValidatorConfiguration in a token wise manner showing only the relevant portions each time. In reality there can only be a single CallbackHandlerConfiguration and a single ValidatorConfiguration with all child assertions combined under them. The runtime currently does not validate this restriction, users need to be aware of it. Also note that Metro currently does not perform schema validation for any of the configuration(s) described in this post.

 Token Configuration for UsernameToken

 

 This section describes the client and server side configuration possibilities for dealing with UsernameToken assertions.

 Client Side Configuration for UsernameToken

 

  The primary action on the client side for a UsernameToken is to specify the username and password. There can be three different types of clients  webservice clients and we shall discuss the configuration applicable to each of them. The three possible types of clients are

  1.  Standalone Java Clients
  2. WebApplications/WebServices acting as client to another WebService 
  3. Java EE Application Clients
Standalone Java Clients

 The configuration possible for Standalone Java Client's is two fold

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown  in my earlier post here.
  2. described in the following abstract schema

<sc:CallbackHandlerConfiguration
  useXWSSCallbacks="{Value true indicates use XWSS Callbacks in place of Standard J2SE callbacks for Non-109 App. For 109 Apps a value true indicates passing RuntimePropertiesCallback as an Extra Callback to CallbackHandler.handle(Callbacks[]) method}" >
       <sc:CallbackHandler  name="usernameHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.NameCallback}"
        default="{the default username value as a string, to be provided incase classname is not provided}"/>
       <sc:CallbackHandler  name="passwordHandler"  classname="{a callbackhandler  classname that handles javax.security.auth.callback.PasswordCallback}"
        default="{the default password value as a string, to be provided incase classname is not provided}" />

</sc:CallbackHandlerConfiguration>

 So one can either specify a default username and password

 

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
       <sc:CallbackHandler  name="usernameHandler" default="<my username>"/>
       <sc:CallbackHandler  name="passwordHandler" default="<my password>" />

</sc:CallbackHandlerConfiguration>

 

or specify a Username and Password Handler separately as below

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
       <sc:CallbackHandler  name="usernameHandler" classname="my.UsernameCallbackHandler"/>
       <sc:CallbackHandler  name="passwordHandler" classname="my.PasswordCallbackHandler" />

</sc:CallbackHandlerConfiguration>

The first option is generally for quick and dirty development. The attribute useXWSSCallbacks is relevant in the second case. By default the UsernameCallbackHandler is expected to handle NameCallback  and PasswordCallback defined in the javax package but by specifying useXWSSCallbacks="true" metro would expect the Handler to handle UsernameCallback and PasswordCallback from com.sun.xml.wss.impl.callback  package, the support for useXWSSCallback attribute was added based on request from metro forum users, and the reason is  a unique property of  the callbacks defined in com.sun.xml.wss.impl.callback  package. The callbacks in this package extend XWSSCallback (base class) which supports a public method   public HashMap getRuntimeProperties(); ks these are properties defined by JAXWS runtime as well as  properties that developers can set inside the client program on the BindingProvider's RequestContext.  An example of how the Metro user made use of these runtime properties is as follows :

 The user would have a WebServiceClient that needs to contact multiple WebServices and the username/password pair for each service is different. So the developer could use a single CallbackHandler implementation but then set some property within the client (BindingProvider.RequestContext) indicating the Service being called. The CallbackHandler would then get this property as a runtime property on the callback and can return the username/password appropriate for the service being invoked.

As you can see this would not be possible if the Callback used was a standard javax NameCallback/PasswordCallback  since it does not allow setting any properties on it.Another more relevant example would be the case when the WS-SecurityPolicy of the service has more than one Token of the same type. Let's say one as a Binding Token and another as a Supporting Token or an Endorsing Token. Please read the WS-SecurityPolicy specification for more details on what are supporting and Endorsing Tokens.  But the thing to understand here is that a callback handler needs to return a different token for the  Binding  and Supporting/Endorsing Tokens case.  So unless the Callback Handler has some information conveyed through the Callback about the type of usage of the token (Binding/Endorsing/Supporting) there is no way it can return the right token. Please note that this particular description applies to any security token supported by Metro and not just username/password.  So it turns out that it is difficult for runtime to convey this information directly to the callback. But the latest versions of WS-SecurityPolicy specification comes to the rescue.  A Token assertion can have the following child metadata assertions :

  1. Token Issuer
  2. Required Claims

This metadata can now be accessed by the callbackhandler using the TokenPolicyMetaData API (see sample code below). This API again makes use of Runtime Properties on the callback under the covers.

import com.sun.xml.wss.impl.callback.XWSSCallback;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

public class MyCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof XWSSCallback) {
                XWSSCallback cb = (XWSSCallback)callbacks[i];
               com.sun.xml.wss.TokenPolicyMetaData data = new com.sun.xml.wss.TokenPolicyMetaData(cb.getRuntimeProperties());
                org.w3c.dom.Element claims = data.getClaims();
                String issuer = data.getIssuer();
                ....
                //rest of CBH processing
                if (issuer.equals("XYZ")) {
                    //do something special
                } else {
                    //do something else
                }
            }
        }
    }

WebApplications/WebServices acting as Clients to another WebService

 

WebApplication and WebService clients have the following configuration options

 

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown  in my earlier post here.
  2. CallbackHandler configuration (described for standalone clients above) but only the default static option. This is because there can be no Callback from a WebApplication back to the End-User.

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
       <sc:CallbackHandler  name="usernameHandler" default="<my username>"/>
       <sc:CallbackHandler  name="passwordHandler" default="<my password>" />

</sc:CallbackHandlerConfiguration>

But as noted earlier this option has the drawback of storing the plain-text password inside a configuration file. Metro security users on GlassFish have an option here. They can leverage the password security feature by creating a password  alias  and storing the actual password in an encrypted password store.  The only requirement here is that the password alias should start with a "$" symbol, for example, below is the configuration of user "xyz" with password alias "$xyzpasswordalias".

 

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
       <sc:CallbackHandler  name="usernameHandler" default="xyz"/>
       <sc:CallbackHandler  name="passwordHandler" default="$xyzpasswordalias" />

</sc:CallbackHandlerConfiguration>

The metro runtime knows to contact the password store when it sees that the password specified in the configuration begins with a "$".

 

JavaEE Application Clients

 

JavaEE Application Clients have the following options

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext (same as with other types of clients above)
  2. Use the GlassFish Default AppClient CallbackHandler for collecting the Username/Password
  3. Specify a Custom CallbackHandler configured with the GlassFish Appclient Container.

Server Side Configuration for UsernameToken

The primary action(s) on the server side for a UsernameToken are two fold

  1. Validation of the Username-Password pair and setting the corresponding caller principal which can be used for authorization purposes
  2. Controlling the time-period for which a recieved Nonce is  stored on the server for replay detection

There are three different validation scenarios depending on the Type/Usage of the UsernameToken in the Policy of the Service.

  1. Username Token containing Plain-Text password and username being used as an Authentication Token. Usually configured as a*SupportingTokens in Policy. The wildcard before the SupportingTokens keyword is because the WS-SecurityPolicy  specification allows specifying an Encrypted/Signed/SignedEncrypted SupportingToken. 
  2. Username Token containing the hashed password (also known as Password Digest Authentication).
  3. Username Token used as a Binding/Endorsing Token where the token password is used to derive a new symmetric key which is used for Signing and Encrypting the Messages. This is also referred to as password derived keys as described in OASIS WS-Security UsernameToken Profile 1.1 specification.
Configuration for Plain-Text Username/Password Validation

 

For a plain-text username/password  most containers define some mechanisms for validating the pair. Java EE as such does define any API for defining the same and hence each container would have its own proprietary framework and API's. So there are two different deployment scenarios for which different mechanism apply. The four scenarios are

  1. GlassFish 109 deployment
  2. Non-GlassFish container or GlassFish Non-109 deployment

For GlassFish 109 deployments there is no configuration required for Plain-Text Username-Password  validation within the Metro configuration files. Instead one would need to configure the GlassFish Realm for the application and make sure the appropriate users exist in the Realm being configured. More details on this can be found here. As noted earlier GlassFish 109 deployments make use of the underlying GlassFish JSR 196 CallbackHandler and i have also described how a GlassFish Non-109 deployment can also be forced to make use of the JSR 196 CallbackHandler.

For Non-GlassFish containers and for GlassFish Non-109 deployments the following two options exist

  1. ValidatorConfiguration can be used  for validating passwords. The override rule defined earlier applies as well, i.e one can configure a Validator for a 109 deployment and it will override the default JSR 196 callback.
  2. A RealmAuthentication Adapter can be specified.

A ValidatorConfiguration with a usernameValidator child on the server side WSDL has the following abstract schema.

<sc:ValidatorConfiguration ...>

<sc:Validator name= "usernameValidator"  classname={class name of a usernameToken Validator,
    should implement com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator  a sample validator can be seen here}/>
</sc:ValidatorConfiguration>

 As noted earlier i am showing pieces under ValidatorConfiguration as applicable, there can be other types of validators under the ValidatorConfiguration that will be shown elsewhere in this post. There has to be a single ValidatorConfiguration element on the client/server side.  Since we are talking about Plain-Text password validation here, so the validator is expected to recieve a PlainTextPasswordRequestObject here.

As it turns out the validate method on the Validator : boolean validate(Request request) throws PasswordValidationException;  is a legacy method and does not provide a way for the validator to set the caller-principal somewhere such that the target container can then interpret it, in this case metro sets the caller-principal in a container independent manner.

  The second option was designed based on the idea that most containers have a notion of  Realms which allow authentication against them. So for RealmAuthentication on Containers other than GlassFish we have this SPI called com.sun.xml.wss.RealmAuthenticationAdapter.

It has an abstract method :

public abstract boolean authenticate(Subject callerSubject, String username, String password) throws XWSSecurityException;

So what does the developer need to do :

1. Implement your own RealmAuthentication class that extends the com.sun.xml.wss.RealmAuthenticationAdapter.
2. Package the implementation class inside your WAR File
3. Create a META-INF/services entry (inside the WAR) for your RealmAuthenticator. The services file should be named as : com.sun.xml.xwss.RealmAuthenticator and the contents of the file should be the fully qualified package name of your RealmAuthenticator class.

This allows for an application specific configuration of RealmAuthenticator.  Since the clientSubject is passed as an argument, the Autheticator could also update the Subject with the target containers representation of the Caller Principal.

Server Side Configuration for Password Digest Authentication

 

 The configuration required for Password Digest authentication is again a usernameValidator. And this applies to both GlassFish 109 deployments and Non-GlassFish deployments. The details of the configuration are described here. GlassFish Realm SPI's allow for developing custom realms that support Digest Authentication, in addition the JDBC Realm in GlassFish V2.1 and GlassFish V3 does support Digest Authentication. So, ideally no configuration should be required for Password Digest Authentication  in metro when running on GlassFish V2.1 and V3, however this particular integration of Metro with Digest Authentication in Realms is a TBD for future releases of metro.

Another piece of configuration relevant to Password Digest Authentication is a parameter that controls the Caching of Nonce values present in the UsernameToken. A Nonce is especially a mandatory element in Password Digest authentication, see the WSS 1.1 UsernameToken profile for a description of the Nonce element. So the Metro implementation would cache Nonces and can detect a message replay based on a repeated Nonce value. However it is obivious that a received nonce cannot be stored indefinitely on the server (it would result in a memory leak, and can be the cause of a DOS attack). So the specification recommends that nonces be stored for a configurable time-period. Accordingly the following attribute on ValidationConfiguration can be specified by application developers :

<sc:ValidatorConfiguration
sc:maxNonceAge="{The length of time (milliseconds) a previously received Nonce value in a
UsernameToken will be stored, runtime default of 15 minutes used when not specified}"?

>
Note that this attribute is one among many other attributes allowed on a ValidatorConfiguration. The other attributes are defined elsewhere in this post. The NonceCache used by Metro is a global Nonce Cache and hence Nonces have to be unique across applications. And so one can imagine that if multiple WebServices were deployed with different values for this attribute, then only the value defined by the first deployed WebService will be used in reality as the maximum Nonce Age. This is a minor ceveat that developers need to be aware of.

 

Server Side Configuration for Password Derived Keys

 

Password Derived Keys is an interesting new addition to Metro 2.0. It allows a username-password to be used for authentication as well as integrity/confidentiality protection. The configuration required for this case is again a usernameValidator for both  GlassFish 109 and Non-GlassFish deployments.  The details can be seen here. Again here it is possible to have support for this with No configuration whatsoever when running on GlassFish, but this integration with GlassFish has not happened yet and is aTBD for future

Configuration for X509Token

 

The X509 Token is the most commonly used token with metro and we have a whole lot of configuration syntax around it. When talking about X509Tokens that thing that comes to our mind immediately is the Java Keystore API and it would appear that the only way to configure X509Tokens with Metro is to use a KeyStore. But this is not true, as described in the beginning, the Metro SecurityEnvironment (Internal) SPI deals only with Keys and Certificates and has no dependence on the Java Keystore. The idea is that the keys can come potentially from anywhere, even a plain file on the filesystem,  but handling such cases would require custom code to be written by the developers. I shall say more  about it towards the end of this post.

However the DefaultCallbackHandler in Metro (which is used when running metro on GlassFish with Non-109 deployments or when running Metro on Non-GlassFish containers ) needs to be configured with  Keystore(s), Truststore(s) and Certstore(s) to be able to do its job. The following configurations are possibile for X509 Tokens.

A KeyStore is used to store the keys-pairs (certificate and private-key) of the entity participating in a WebService interaction. A TrustStore is used to store trusted CA certificates. A CertStore is used to store trusted other-party certificates. In general KeyStore, TrustStore and CertStore(s) would need to configured on both the client and server side (with appropriate namespace change). In addition one may configure a Certificate Validator for Validating incoming certificates (this is generally done on the server side).

Note : Though most of the samples and NetBeans UI today allow configuring other-party (non-CA) certificates inside truststore this is not a good idea in reality, though it allows quick and dirty development. This is because the truststore is meant to contain only CA certificates or trust-roots. Metro supports a CertStore configuration that can be used to store other-party certificates. We have not demonstrated samples around it but some metro users have used it. We intend to support the SSL/TLS Handshake and SPNego protocols (at the SOAP Layer) for WebServices in future Metro releases. This will reduce the need to store other-party (non-CA) certificates in general.There is also a Programmatic way of configuring a single private-key and certificate pair on the client side (it will not help if the policy requires multiple X509 Tokens for securing the message such as one for binding and another for endorsing). This is desribed in my earlier post.

 Static Configuration of KeyStore

  <sc:Keystore
   location={absolute path to keystore file OR a path relative to META-INF (on the classpath), not required for 109 cases}?
   type={type of the keystore (default is JKS)}?
   storepass={the password of the keystore as a string, OR a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles
   the javax.security.auth.callback.PasswordCallback, not required for 109 cases}?
   alias={the certificate alias from the  keystore to be used for Signatures}
   aliasSelector={the fully qualified classname of a class implementing  com.sun.xml.wss.AliasSelector interface}?
   keypass={the password for the key, OR  a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles the javax.security.auth.callback.PasswordCallback, not required for 109 cases }?
  />  

Note : ? in abstract schema definitions indicates optional attribute for the rest of this post.
Only one of  alias or aliasSelector maybe specified, if specified an AliasSelector is responsible to locating and returning the correct alias to be used for accessing the Key-Certificate pair. The alias takes precedence over aliasSelector. As you can see, the keystore location and password are not to be specified when running JSR 109 WebServices on GlassFish. This is because in this case the GlassFish JSR 196 callbackhandler knows about these values from configuration that is specific to GlassFish.  The keypass is assumed to be same as storepass in case of 109 services and hence cannot be specified.

This simple configuration has the main drawback that it requires absolute location of the keystore.   This would be a problem when one wants to move the application around on different servers. The other alternative when using static configuration is to specify a path relative to META-INF. Metro would try to locate the keystore as a resource using the callclassLoader.getResource(relative-keystoreURL). This expects that the directory contaning META-INF is on the classpath.  So ideally the keystore and truststore would need to be packaged inside the WAR files and kept under WEB-INF/classes/META-INF.  The second problem is that it accepts a plain-text password which is not good for production deployment. This problem is mitigated by the fact that you can also specify a fully qualified classname of a CallbackHandler that handles the PasswordCallback in this case instead of a plain-text password.

 As one can see this simplistic configuration is good for quick development (you do not need to write any code to configure the keystore) with the exception of the problems stated above. The fact that keystore type is accepted as an argument allows developers to use either the default type JKS keystore or use other types supported by the Java KeyStore API such as PKCS11 (Hardware Tokens) and PKCS12 tokens. An example with PKCS11 was posted recently by one metro user, here is how it was configured :

<sc1:KeyStore wspp:visibility="private" alias="Sign_Keypair" storepass="12345678" type="PKCS11" location=""/>

I have also seen in the past PKCS12 being used as the type by another user.

When developing services for glassfish 109-deployment the keystore assertion needs to only specify the alias value and the truststore need only specify the peeralias. The other fields of the static configuration  such as storepass, type and location are ignored. Glassfish provides its own means to change the keystore location and password. The location of the keystore and truststore is specified via javax.net.ssl.keyStore and javax.net.ssl.trustStore properties in domain.xml. The password is controlled by the GlassFish MasterPassword and one limitation is that the keypassword cannot be different from the keystore password. Glassfish 109 deployments cannot make use of the Dynamic KeyStore configuration described in the next section however one can override the JSR-196 callbackhandler completely thereby providing the required level of control. Overiding the JSR-196 (JMACCallbackHandler) is described towards the end of this post.

Note the use of wspp:visibility="private" attribute, this can bee added to all the configuration assertions discussed in this document. When you use NetBeans it automatically sets the visibility attribute.

  Dynamic KeyStore Configuration

<sc:Keystore
   alias={the certificate alias from the  keystore to be used for Signatures}
   aliasSelector={the fully qualified classname of a class implementing com.sun.xml.wss.AliasSelector interface}?
   callbackHandler={fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler, should be able to handle  com.sun.xml.wss.impl.callback.KeyStoreCallback and  com.sun.xml.wss.impl.callback.PrivateKeyCallback}
/>


Only one of  alias or aliasSelector are required.  This form of KeyStore configuration gives more flexibility in that you can write a CallbackHandler which handles the KeyStoreCallback and expose your keys (even those located on your filesystem or in other  stores such as NSS etc) via a Java KeyStore constructed on the fly.  This form also gets rid of the two drawbacks mentioned above with the Static KeyStore Configuration.

Static TrustStore Configuration

<sc:Truststore
      location={absolute path to truststore file
OR a path relative to META-INF (on the classpath), , not required for 109 cases}?
      type={type of the keystore (default is JKS)}?
      storepass={the password of the truststore as a string, OR a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles  the javax.security.auth.callback.PasswordCallback, not required for 109 cases}?
      peeralias={the alias of the peer entity involved in secure communication, not required if no encryption is involved, never required on the server side}?
      certSelector={the fully qualified classname of a class implementing java.security.cert.CertSelector interface}?
/>


Only one of peeralias or certSelector may be specified. The description of Static TrustStore configuration is more or less similar to its corresponding KeyStore counterpart described earlier with the exception that a TrustStore accepts a  Java CertSelector as opposed to an AliasSelector. This is because the runtime primarily needs to match an incoming certificate with something in the Truststore as opposed to picking an alias. In general an alias has little utility inside a TrustStore.

 Dynamic TrustStore Configuration

<sc:Truststore
      peeralias={the alias of the peer entity involved in secure communication,
      not required if no encryption is involved, never required on the server side}?
      certSelector={the fully qualified classname of a class implementing java.security.cert.CertSelector interface}?
      callbackHandler={fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler, should be able to handle
      com.sun.xml.wss.impl.callback.KeyStoreCallback to return the Truststore}
/>


Only one of peeralias or certSelector may be specified. The description of the Dynamic TrustStore is similar to that of Dynamic KeyStore above.

CertStore Configuration

 <sc:CertStore
    callbackHandler="{fully qualified ClassName of a class that implements
    javax.security.auth.callback.CallbackHandler interface and handles
    the com.sun.xml.wss.impl.callback.CertStoreCallback}" 
    certSelector="{fully qualified ClassName of a class that implements
    the java.security.cert.CertSelector interface}"
/>


The use of  CertStore is optional and when using it on GlassFish 109 deployments, specifying the callbackHandlerattribute has no effect, this is becuase the GlassFish  JSR 196 CallbackHandler  provides its own CertStore (via a JSR 196 defined CertStoreCallback) which cannot be overridden.

 The following post by a former member explains the use of the some of these features as part of the WS-I Supply Chain Management Sample Application that we developed.

Configuration for CertificateValidator

 

  The Metro runtime has a powerful default certificate validator which uses the Java CertPathValidator API's to do certificate-chain validation for incoming certificates. The default implementation also does revocation checking based on CRL's and OCSP. By default this revocation checking is disabled and one can enable it by setting the revocationEnabled  attribute to "true" on the  ValidatorConfiguration as shown below.

<sc:ValidatorConfiguration
sc:revocationEnabled="{If this flag is true, the default certificate revocation checking mechanism
of the underlying PKIX service provider will be used. If this flag is false,
the default revocation checking mechanism will be disabled (not used).}"?
>

Note that enabling revocation would cause certificate validation to fail if the certificates being used in the application do not have CRL distribution point or OCSP responder URL's. While this is not a problem with Production Certificates (those issued by well known CA's such as Verisign etc), it is definitely a problem if you are using experimental certificates which do not have the required certificate extensions defining these values. For example the default Metro Certificates(copyv3) do not have these extensions.

 Despite the default implementation for Certificate Validation people often find themselves in situations where they need to do additional Validations than those performed by the default implementation. For example an application may want to allow only those certificates in which a particular extension/regular attribute has a specific value. For all such cases one can configure a CertificateValidator which Metro runtime would invoke to validate the incoming certificate. The  revocationEnabled attribute defined above would then have no effect. The configuration is as shown below :

<sc:ValidatorConfiguration

<sc:Validator  name="certificateValidator" classname ={class name of a certificate Validator,
    should implement com.sun.xml.wss.impl.callback.CertificateValidationCallback.CertificateValidator,
    default Certificate validator from Metro runtime used when not supplied} /> ?

</sc:ValidatorConfiguration>

Configuration for SAML Token

 

The WS-SecurityPolicy specification defines a SAMLToken assertion which can be used as a Binding Token or as an Endorsing/Supporting token.  The configuration applicable for SAMLToken assertion is described below.

Client Side Configuration

 

<sc:CallbackHandlerConfiguration ...xmlns:sc="http://schemas.sun.com/2006/03/wss/client">
       <sc:CallbackHandler  name="samlHandler"  classname="{a callbackhandler  classname that
        handles com.sun.xml.wss.impl.callback.SAMLCallback}"
 />

The client side configuration is a CallbackHandler that can handle the SAMLCallback. The CallbackHandler is expected to set the SAML Assertion into the SAMLCallback. If the <sp:ProtectTokens/> assertion is being used and the SAML Assertion is used as a  Binding Assertion (one that is used to secure messages) then the CallbackHandler should set the AssertionID of the SAML assertion onto the Callback. See the following post for more details. Note that the details of how the SAML Assertion is obtained is out-of-scope of Metro here. The CallbackHandler may use any Protocol (ex. SAMLP etc) to obtain the SAML Assertion. We have a sample CallbackHandler that just creates new SAML Assertions on the fly (SAMLCallbackHandler.java).

Note that the SAMLCallback has two setter methods for setting the assertion.  void setAssertionElement(org.w3c.dom.Element samlAssertion) and  void setAssertionReader(XMLStreamReader samlAssertion) . It is desirable (in terms of performance) that you use the latter one if you have the assertion as an XMLStreamReader. But if the tools that you use to obtain the SAML Assertion within the CallbackHandler already return you a DOM Element then you might want to use the former. The sample SAMLCallbackHandler.java actually uses the former.        

 Server Side Configuration

 

  The server side configuration for a SAML Assertion consists primarily of a Validator.

<sc:ValidatorConfiguration .... xmlns:sc="http://schemas.sun.com/2006/03/wss/server">

<sc:Validator name="samlAssertionValidator" classname = {class name of a SAML Assertion Validator, should implement com.sun.xml.wss.impl.callback.SAMLAssertionValidator,
    Partial validation (in the form of verifying enveloped signature) occurs on SAML Assertion within  the Metro Runtime even if the validator is not specified} /> ?
</sc:ValidatorConfiguration>

   the SAMLAssertionValidator can be used by developers to do additional validations on an incoming SAML Assertion other than verifying the signature of the Singed Assertion. See the following post for more details on the SAMLAssertionValidator.

 

Token Configuration for Kerberos Tokens

 

  A very nice Technical Tip on securing WebServices in Metro using Kerberos Tokens is here. The same information is also available in the form of blogs from our former team member here and here.

 

 

Token Configuration for IssuedToken

 

Server Side Configuration

On the server side, there are no Proprietary configuration other than  the standard IssuedToken. Please see the following detailed article.

Client Side Configuration

On the client side for trust there is a PreConfiguredSTS assertion which statically gives information about the STS that needs to be contacted by the client runtime in order to obtain the Issued Token.

   <tc:PreconfiguredSTS xmlns:tc="http://schemas.sun.com/ws/2006/05/trust/client"

endpoint={the endpoint URL of the STS}

wsdlLocation={the WSDL location of the STS WSDL}?

 serviceName={the service name of the STS service}?

portName={the relevant port name of the STS service to be contacted}?

namespace={the namespace of the STS WSDL}

wstVersion={ defaults to "http://docs.oasis-open.org/ws-sx/ws-trust/200512",  indicates the
version of the WS-Trust used by the STS. It is mainly used in the case that STS and the
service have different versions of WS-Trust in use.}
   shareToken={â€

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.  

With Latest Metro 2.0 bits you can now try signing and encrypting SOAP Messages using the WSS 1.1 Password Derived Keys Feature. This is useful incase one does not want to use Certificates or Kerberos tokens etc. A secret key derived from your password would be used to sign and encrypt the SOAP messages. 

Configuring Password Derived Keys can be done Via WS-SecurityPolicy assertions in the WSDL. NetBeans support for this is not yet there but one can add the assertions manually to do this.

While our QE is still testing this feature which is going to be part of Metro 2.0 release, you can already start using it. 

Checkout the post by my team member suresh for more info on this feature : Post By Suresh

Metro 2.0 Nightlies can be obtained here: Metro 2.0 Nightlies

Filter Blog

By date: