Adding Authentication Mechanisms to the GlassFish Servlet Container

1 2 Page 2
Page 2 of 2

Option 2: The first option leverages the native AuthConfigProvider implementation that ships with GlassFish. Another approach would be to develop your own AuthConfigProvider and register it with the Glassfish AuthConfigFactory for use on behalf of your applications. For example, a simple AuthConfigProvider might obtain, through its initialization properties, the classname of a SAM to configure on behalf of the applications for which the provider is registered. You can find a description of the functionality of an AuthConfigProvider and of the registration facilities provided by an AuthConfigFactory in the JRS-196 specification.

After you have bound the SAM for use by the container on behalf of your application(s), the container will invoke MySam whenever a request is made to a resource within your application. Moreover, when a request is made to a resource within your application that is protected by an auth-constraint, MySam will not dispatch the request until it has determined that a successful authentication has occurred.

Let's complete the implementation of validateRequest so that MySam will be able to perform the authentication.

Revising the SAM

You've gone through the steps of installing, configuring, and binding a SAM. Now let's return to the authentication mechanism implementation and make some changes to complete the implementation of the validateRequest method. To keep things simple, let's change the SAM to implement HTTP Basic Authentication, or at least an approximation of it.

Here is the modified SAM. The primary changes are as follows:

  • New imports are added to account for the use of the Group and Password Validation callbacks, and the Base64 decoder.
        import javax.security.auth.message.callback.GroupPrincipalCallback;
        import javax.security.auth.message.callback.PasswordValidationCallback;
        import org.apache.catalina.util.Base64;
    
  • New constants are added to represent the property names and the HTTP Basic header identifiers.
        private String realmName = null;
        private String defaultGroup[] = null;
        privte static final String REALM_PROPERTY_NAME =
            "realm.name";
        private static final String GROUP_PROPERTY_NAME =
            "group.name";
        private static final String BASIC = "Basic";
        static final String AUTHORIZATION_HEADER =
            "authorization";
        static final String AUTHENTICATION_HEADER =
            "WWW-Authenticate";
    
  • The initialize method looks for the group.name and realm.name properties. The group.name property is used to configure the default group that will be assigned as a result of any successful authentication. The realm.name property is used to define the realm value sent back to the browser in the www-authenticate challenge.
       public void initialize(MessagePolicy reqPolicy,
               MessagePolicy resPolicy,
               CallbackHandler cBH, Map opts)
               throws AuthException {
           requestPolicy = reqPolicy;
           responsePolicy = resPolicy;
           handler = cBH;
           options = opts;
           if (options != null) {
               realmName = (String)
                   options.get(REALM_PROPERTY_NAME);
               if (options.containsKey(GROUP_PROPERTY_NAME)) {
                   defaultGroup = new String[]{(String)
                       options.get(GROUP_PROPERTY_NAME)};
               }
           }
       }
    
  • The implementation of the validateRequest method is revised to evaluate the www-authorize header and to issue the www-authenticate challenge.
       public AuthStatus validateRequest(
               MessageInfo msgInfo, Subject client,
               Subject server) throws AuthException {
           try {
    
               String username =
                   processAuthorizationToken(msgInfo, client);
               if (username ==
                   null && requestPolicy.isMandatory()) {
                   return sendAuthenticateChallenge(msgInfo);
               }
    
              setAuthenticationResult(
                  username, client, msgInfo);
              return AuthStatus.SUCCESS;
    
           } catch (Exception e) {
               AuthException ae = new AuthException();
               ae.initCause(e);
               throw ae;
           }
       }
    
  • The setAuthenticationResult method is extended to add the defaultGroup if it is configured.
       // distinguish the caller principal
       // and assign default groups
       private void setAuthenticationResult(String name,
               Subject s, MessageInfo m)
               throws IOException,
               UnsupportedCallbackException {
           handler.handle(new Callback[]{
               new CallerPrincipalCallback(s, name)
           });
    
           if (name != null) {
               // add the default group if the property is set
               if (defaultGroup != null) {
                   handler.handle(new Callback[]{
                       new GroupPrincipalCallback(s, defaultGroup)
                   });
               }
               m.getMap().put(AUTH_TYPE_INFO_KEY, ""MySAM");
           }
       }
    

Configuring the Revised SAM

After you have built and installed the revised SAM in the GlassFish lib directory, from your browser, use the GlassFish v2 Admin Console to reconfigure the SAM as follows:

  1. Expand the Configuration node at the bottom of the left-hand pane.
  2. Navigate to the Security node, expand it, and click Message Security.
  3. Under Message Security Configurations, select HttpServlet.
  4. Select the Providers tab.
  5. Click the entry for MySam to open the Edit Provider Configuration screen.
  6. Click the Add Property button in the Additional Properties frame and enter group.name in the Name field and user in the Value field.
  7. Click the Add Property button again and enter realm.name in the Name field and Sam in the Value field.
  8. Click the Save button.

Alternatively, you could create a second provider with a different name and with the values for the defined properties. You could then switch the binding of your application to the new provider and redeploy your application.

As before, after the revised SAM is installed and bound to your application, it will be invoked by the container on behalf of your application. When you attempt to access an auth-protected resource within your application, the revised SAM will prompt you for a username and password. The SAM will use the CallbackHandler to ask the container to validate the supplied username and password using the realm configured for your application. For the validation to succeed, you will need to know the username and password of a user in the realm configured for your application.

By default, GlassFish applications are configured to use the file realm. To add a user to the file realm, use the GlassFish v2 Admin Console as follows:

  1. Expand the Configuration node at the bottom of the left-hand pane.
  2. Navigate to the Security node, expand it, and click on Realms.
  3. Under Realms, open the file realm.
  4. Click the Manage Users button.
  5. Click on New.
  6. Fill in values for "User Id", "New Password", and "Confirm New Password".
  7. Click the OK button.

Further Reading

You can learn more about using JSR 196 in the following documents:

About the Author

Ron Monzillo is the specification lead for JSR 196 and JSR 115: Java Authorization Contract for Containers. He defined the declarative security model for servlets and led the team that defined the EJB Secure Interoperability protocol, that is, CORBA/CSIv2. He also made contributions to the OASIS WS-Security standards and was the primary author of the WS-Security SAML token profile. Ron participates in most security activities relating to Java EE, servlets, and GlassFish.


2008 JavaOne Conference: Last Chance for Discount Registration

Don't miss this opportunity. Register by May 5, and save $100 for the JavaOne conference, May 6-9, 2008, in San Francisco. Experience 300+ sessions on Java technology, Rich Internet Applications, open source, compatibility and interoperability, next-generation scripting languages, Web 2.0, services integration, e-commerce collaboration, and more. Meet with 100+ companies leading Java technology innovations and expanding into new technologies; and take advantage of opportunities to meet the experts in the SOA Village, Mobility and Device Village, and Startup Exhibitor Alley, all in the JavaOne Pavilion.

Use priority code J8EM5IC, and register today at java.sun.com/javaone.

1 2 Page 2
Page 2 of 2