Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » security » auth » spi » [javadoc | source]
    1   /*
    2    * JBoss, the OpenSource WebOS
    3    *
    4    * Distributable under LGPL license.
    5    * See terms of license at gnu.org.
    6    */
    7   package org.jboss.security.auth.spi;
    8   
    9   
   10   import java.security.Principal;
   11   import java.security.acl.Group;
   12   import java.util.Enumeration;
   13   import java.util.Iterator;
   14   import java.util.Map;
   15   import java.util.Set;
   16   
   17   import javax.security.auth.Subject;
   18   import javax.security.auth.callback.CallbackHandler;
   19   import javax.security.auth.login.LoginException;
   20   import javax.security.auth.spi.LoginModule;
   21   
   22   import org.jboss.logging.Logger;
   23   import org.jboss.security.NestableGroup;
   24   import org.jboss.security.SimpleGroup;
   25   
   26   /**
   27    * This class implements the common functionality required for a JAAS
   28    * server side LoginModule and implements the JBossSX standard Subject usage
   29    * pattern of storing identities and roles. Subclass this module to create your
   30    * own custom LoginModule and override the login(), getRoleSets() and getIdentity()
   31    * methods.
   32    * <p>
   33    * You may also wish to override
   34    * <pre>
   35    *    public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
   36    * </pre>
   37    * In which case the first line of your initialize() method should be:
   38    * <pre>
   39    *    super.initialize(subject, callbackHandler, sharedState, options);
   40    * </pre>
   41    * <p>
   42    * You may also wish to override
   43    * <pre>
   44    *    public boolean login() throws LoginException
   45    * </pre>
   46    * In which case the last line of your login() method should be
   47    * <pre>
   48    *    return super.login();
   49    * </pre>
   50    *
   51    *@author <a href="edward.kenworthy@crispgroup.co.uk">Edward Kenworthy</a>, 12th Dec 2000
   52    *@author Scott.Stark@jboss.org
   53    *@version $Revision: 1.6.4.3 $
   54    */
   55   public abstract class AbstractServerLoginModule implements LoginModule
   56   {
   57      protected Subject subject;
   58      protected CallbackHandler callbackHandler;
   59      protected Map sharedState;
   60      protected Map options;
   61      protected Logger log;
   62      /** Flag indicating if the shared credential should be used */
   63      protected boolean useFirstPass;
   64      /** Flag indicating if the login phase succeeded. Subclasses that override
   65       the login method must set this to true on successful completion of login
   66       */
   67      protected boolean loginOk;
   68   
   69   //--- Begin LoginModule interface methods
   70      /**
   71       * Initialize the login module. This stores the subject, callbackHandler
   72       * and sharedState and options for the login session. Subclasses should override
   73       * if they need to process their own options. A call to super.initialize(...)
   74       * must be made in the case of an override.
   75       * <p>
   76       * The options are checked for the <em>password-stacking</em> parameter.
   77       * If this is set to "useFirstPass", the login identity will be taken from the
   78       * <code>javax.security.auth.login.name</code> value of the sharedState map,
   79       * and the proof of identity from the
   80       * <code>javax.security.auth.login.password</code> value of the sharedState map.
   81       *
   82       * @param subject the Subject to update after a successful login.
   83       * @param callbackHandler the CallbackHandler that will be used to obtain the
   84       *    the user identity and credentials.
   85       * @param sharedState a Map shared between all configured login module instances
   86       * @param options the parameters passed to the login module.
   87       */
   88      public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
   89      {
   90         this.subject = subject;
   91         this.callbackHandler = callbackHandler;
   92         this.sharedState = sharedState;
   93         this.options = options;
   94         log = Logger.getLogger(getClass());
   95         log.trace("initialize");
   96        /* Check for password sharing options. Any non-null value for
   97            password_stacking sets useFirstPass as this module has no way to
   98            validate any shared password.
   99         */
  100         String passwordStacking = (String) options.get("password-stacking");
  101         if( passwordStacking != null && passwordStacking.equalsIgnoreCase("useFirstPass") )
  102            useFirstPass = true;
  103      }
  104   
  105      /** Looks for javax.security.auth.login.name and javax.security.auth.login.password
  106       values in the sharedState map if the useFirstPass option was true and returns
  107       true if they exist. If they do not or are null this method returns false.
  108   
  109       Note that subclasses that override the login method must set the loginOk
  110       ivar to true if the login succeeds in order for the commit phase to
  111       populate the Subject. This implementation sets loginOk to true if the
  112       login() method returns true, otherwise, it sets loginOk to false.
  113       */
  114      public boolean login() throws LoginException
  115      {
  116         log.trace("login");
  117         loginOk = false;
  118         // If useFirstPass is true, look for the shared password
  119         if( useFirstPass == true )
  120         {
  121            try
  122            {
  123               Object identity = sharedState.get("javax.security.auth.login.name");
  124               Object credential = sharedState.get("javax.security.auth.login.password");
  125               if( identity != null && credential != null )
  126               {
  127                  loginOk = true;
  128                  return true;
  129               }
  130               // Else, fall through and perform the login
  131            }
  132            catch(Exception e)
  133            {   // Dump the exception and continue
  134               log.error("login failed", e);
  135            }
  136         }
  137         return false;
  138      }
  139   
  140      /** Method to commit the authentication process (phase 2). If the login
  141       method completed successfully as indicated by loginOk == true, this
  142       method adds the getIdentity() value to the subject getPrincipals() Set.
  143       It also adds the members of each Group returned by getRoleSets()
  144       to the subject getPrincipals() Set.
  145       
  146       @see javax.security.auth.Subject;
  147       @see java.security.acl.Group;
  148       @return true always.
  149       */
  150      public boolean commit() throws LoginException
  151      {
  152         log.trace("commit, loginOk="+loginOk);
  153         if( loginOk == false )
  154            return false;
  155   
  156         Set principals = subject.getPrincipals();
  157         Principal identity = getIdentity();
  158         principals.add(identity);
  159         Group[] roleSets = getRoleSets();
  160         for(int g = 0; g < roleSets.length; g ++)
  161         {
  162            Group group = roleSets[g];
  163            String name = group.getName();
  164            Group subjectGroup = createGroup(name, principals);
  165            if( subjectGroup instanceof NestableGroup )
  166            {
  167               /* A NestableGroup only allows Groups to be added to it so we
  168               need to add a SimpleGroup to subjectRoles to contain the roles
  169               */
  170               SimpleGroup tmp = new SimpleGroup("Roles");
  171               subjectGroup.addMember(tmp);
  172               subjectGroup = tmp;
  173            }
  174            // Copy the group members to the Subject group
  175            Enumeration members = group.members();
  176            while( members.hasMoreElements() )
  177            {
  178               Principal role = (Principal) members.nextElement();
  179               subjectGroup.addMember(role);
  180            }
  181         }
  182         return true;
  183      }
  184   
  185      /** Method to abort the authentication process (phase 2).
  186       @return true alaways
  187       */
  188      public boolean abort() throws LoginException
  189      {
  190         log.trace("abort");
  191         return true;
  192      }
  193      
  194      /** Remove the user identity and roles added to the Subject during commit.
  195       @return true always.
  196       */
  197      public boolean logout() throws LoginException
  198      {
  199         log.trace("logout");
  200         // Remove the user identity
  201         Principal identity = getIdentity();
  202         Set principals = subject.getPrincipals();
  203         principals.remove(identity);
  204         // Remove any added Groups...
  205         return true;
  206      }
  207      //--- End LoginModule interface methods
  208      
  209      // --- Protected methods
  210      
  211      /** Overriden by subclasses to return the Principal that corresponds to
  212       the user primary identity.
  213       */
  214      abstract protected Principal getIdentity();
  215      /** Overriden by subclasses to return the Groups that correspond to the
  216       to the role sets assigned to the user. Subclasses should create at
  217       least a Group named "Roles" that contains the roles assigned to the user.
  218       A second common group is "CallerPrincipal" that provides the application
  219       identity of the user rather than the security domain identity.
  220       @return Group[] containing the sets of roles
  221       */
  222      abstract protected Group[] getRoleSets() throws LoginException;
  223      
  224      protected boolean getUseFirstPass()
  225      {
  226         return useFirstPass;
  227      }
  228      
  229      /** Find or create a Group with the given name. Subclasses should use this
  230       method to locate the 'Roles' group or create additional types of groups.
  231       @return A named Group from the principals set.
  232       */
  233      protected Group createGroup(String name, Set principals)
  234      {
  235         Group roles = null;
  236         Iterator iter = principals.iterator();
  237         while( iter.hasNext() )
  238         {
  239            Object next = iter.next();
  240            if( (next instanceof Group) == false )
  241               continue;
  242            Group grp = (Group) next;
  243            if( grp.getName().equals(name) )
  244            {
  245               roles = grp;
  246               break;
  247            }
  248         }
  249         // If we did not find a group create one
  250         if( roles == null )
  251         {
  252            roles = new NestableGroup(name);
  253            principals.add(roles);
  254         }
  255         return roles;
  256      }
  257   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » security » auth » spi » [javadoc | source]