/*
 * JBoss, the OpenSource WebOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.security.auth.spi;

// $Id: DeploymentRolesLoginModule.java,v 1.1 2004/03/30 21:21:11 tdiesler Exp $

import org.jboss.metadata.SecurityRoleMetaData;
import org.jboss.security.SecurityRolesAssociation;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import java.security.Principal;
import java.security.acl.Group;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * The DeploymentRolesLoginModule adds the roles to the subject that were declared in the
 * assembly-descriptor element in jboss.xml.
 *
 * It gets the roles from the SecurityRolesAssociation, which holds a Map of SecurityRoleMetaData.
 *
 * @author Thomas.Diesler@jboss.org
 * @version $Revision: 1.1 $
 */
public class DeploymentRolesLoginModule extends AbstractServerLoginModule
{
   /**
    * Initialize the login module.
    *
    * @param subject         the Subject to update after a successful login.
    * @param callbackHandler the CallbackHandler that will be used to obtain the
    *                        the user identity and credentials.
    * @param sharedState     a Map shared between all configured login module instances
    * @param options         the parameters passed to the login module.
    */
   public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
   {
      super.initialize(subject, callbackHandler, sharedState, options);

      // Relies on another LoginModule having done the authentication
      useFirstPass = true;
   }

   /**
    * Overriden by subclasses to return the Principal that corresponds to
    * the user primary identity.
    */
   protected Principal getIdentity()
   {
      // Setup our view of the user
      Object username = sharedState.get("javax.security.auth.login.name");
      if(username == null)
         throw new IllegalStateException("Expected to find the username in the shared state");

      if (username instanceof Principal)
         return (Principal)username;

      return new SimplePrincipal((String)username);
   }

   /**
    * Create the 'Roles' group and populate it with the
    * principals security roles from the SecurityRolesAssociation
    * @return Group[] containing the sets of roles
    */
   protected Group[] getRoleSets() throws LoginException
   {
      Group group = new SimpleGroup("Roles");
      Iterator itRoleNames = getSecurityRoleNames().iterator();
      while (itRoleNames.hasNext())
      {
         String roleName = (String) itRoleNames.next();
         group.addMember(new SimplePrincipal(roleName));
      }

      return new Group[]{group};
   }

   /**
    * Get the securtiy role names for the current principal from the
    * SecurityRolesAssociation.
    */
   private Set getSecurityRoleNames()
   {
      HashSet roleNames = new HashSet();
      String userName = getIdentity().getName();

      Map securityRoles = SecurityRolesAssociation.getSecurityRoles();
      if (securityRoles != null)
      {
         Iterator it = securityRoles.values().iterator();
         while (it.hasNext())
         {
            SecurityRoleMetaData srMetaData = (SecurityRoleMetaData) it.next();
            if (srMetaData.getPrincipals().contains(userName))
               roleNames.add(srMetaData.getRoleName());
         }
      }
      return roleNames;
   }
}
