User: stark   
  Date: 01/03/06 00:35:33

  Added:       src/main/org/jboss/security/srp/jaas
                        SRPCacheLoginModule.java SRPLoginModule.java
  Log:
  Added srp package that was missed. Updated AbstractServerLoginModule to
  support password stacking. Updated RolesLoginModule to use existing
  Groups. Updated JaasSecurityManager to operate correctly as a role-mapping
  only manager when so configured.
  
  Revision  Changes    Path
  1.1                  
jbosssx/src/main/org/jboss/security/srp/jaas/SRPCacheLoginModule.java
  
  Index: SRPCacheLoginModule.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp.jaas;
  
  import java.security.Principal;
  import java.util.Arrays;
  import java.util.Map;
  import java.util.Set;
  import javax.naming.InitialContext;
  import javax.naming.NamingException;
  import javax.security.auth.Subject;
  import javax.security.auth.callback.CallbackHandler;
  import javax.security.auth.callback.Callback;
  import javax.security.auth.callback.UnsupportedCallbackException;
  import javax.security.auth.login.LoginException;
  import javax.security.auth.spi.LoginModule;
  
  import org.jboss.security.plugins.SecurityAssociationCallback;
  import org.jboss.security.srp.PkgCategory;
  import org.jboss.security.srp.SRPClientSession;
  import org.jboss.security.srp.SRPServerInterface;
  import org.jboss.security.srp.SRPServerInterface.SRPParameters;
  import org.jboss.util.CachePolicy;
  
  /** A server side login module that validates a username and
  their session key hash against the cache of authentication
  info maintained by the SRPService mbean. This module needs
  a CallbackHandler that supplies the user principal and
  credential via the SecurityAssociationCallback object.
  
  module options:
  cacheJndiName, the JNDI name of the CachePolicy of <Principal,Subject>
  information managed by the SRPSerice.
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SRPCacheLoginModule implements LoginModule
  {
      private Subject subject;
      private CallbackHandler handler;
      private Map sharedState;
      private String domainName;
      private String cacheJndiName;
      private byte[] sessionKey;
      private Principal userPrincipal;
      private boolean debug;
      private boolean loginFailed;
  
      public SRPCacheLoginModule()
      {
      }
  
  // --- Begin LoginModule interface methods
      /**
      @param subject, the subject to authenticate
      @param handler, the app CallbackHandler used to obtain username & password
      @param sharedState, used to propagate the authenticated principal and
          credential hash.
      @param options, the login module options. These include:
          cacheJndiName: the JNDI name of the CachePolicy of <Principal,Subject>
          information managed by the SRPSerice.
          domainName: the security domain name.
      */
      public void initialize(Subject subject, CallbackHandler handler, Map 
sharedState, Map options)
      {
          this.subject = subject;
          this.handler = handler;
          this.sharedState = sharedState;
          cacheJndiName = (String) options.get("cacheJndiName");
          domainName = (String) options.get("domainName");
          String d = (String) options.get("debug");
          if( d != null )
              debug = Boolean.valueOf(d).booleanValue();
      }
  
      /** Access the 
      @return true is login succeeds, false if login does not apply.
      @exception LoginException, thrown on login failure.
      */
      public boolean login() throws LoginException
      {
          loginFailed = true;
          getUserInfo();
  
          String username = userPrincipal.getName();
          // First try to locate an SRPServerInterface using JNDI
          try
          {
              if( cacheJndiName == null )
                  throw new LoginException("Required cacheJndiName option not set");
              InitialContext iniCtx = new InitialContext();
              CachePolicy cache = (CachePolicy) iniCtx.lookup(cacheJndiName);
              Object cacheCredential = cache.get(userPrincipal);
              if( validateCache(cacheCredential) == false )
                  throw new LoginException("Failed to validate SRP session key for: 
"+username);
          }
          catch(NamingException e)
          {
              e.printStackTrace();
              throw new LoginException("Failed to load SRP auth cache: 
"+e.toString(true));
          }
  
          PkgCategory.debug("Login succeeded");
          // Put the username and the client challenge into the sharedState map
          sharedState.put("javax.security.auth.login.name", username);
          sharedState.put("javax.security.auth.login.password", sessionKey);
          loginFailed = false;
          return true;
      }
  
      /** All login modules have completed the login() phase, comit if we
      succeeded. This entails adding the princial to the subject Principals set.
      @return false, if the login() failed, true if the commit succeeds.
      @exception LoginException, thrown on failure to add the principal.
      */
      public boolean commit() throws LoginException
      {
          if( loginFailed == true )
              return false;
          Set principals = subject.getPrincipals();
          subject.getPrincipals().add(userPrincipal);
          subject.getPublicCredentials().add(sessionKey);
          return true;
      }
  
      public boolean abort() throws LoginException
      {
          userPrincipal = null;
          sessionKey = null;
          return true;
      }
  
  
      /** Remove the userPrincipal associated with the subject.
      @return true always.
      @exception LoginException, thrown on exception during remove of the Principal
          added during the commit.
      */
      public boolean logout() throws LoginException
      {
          try
          {
              if( subject.isReadOnly() == false )
              {   // Remove userPrincipal
                  Set s = subject.getPrincipals(userPrincipal.getClass());
                  s.remove(userPrincipal);
              }
          }
          catch(Exception e)
          {
              throw new LoginException("Failed to remove user principal, 
"+e.getMessage());
          }
          return true;
      }
  
  // --- End LoginModule interface methods
  
      private void getUserInfo() throws LoginException
      {
          // Get the security association info
          if( handler == null )
              throw new LoginException("No CallbackHandler provied");
  
          SecurityAssociationCallback sac = new SecurityAssociationCallback();
          Callback[] callbacks = { sac };
          try
          {
              handler.handle(callbacks);
              userPrincipal = sac.getPrincipal();
              sessionKey = (byte[]) sac.getCredential();
              sac.clearCredential();
          }
          catch(java.io.IOException e)
          {
              throw new LoginException(e.toString());
          }
          catch(UnsupportedCallbackException uce)
          {
              throw new LoginException("UnsupportedCallback: " + 
uce.getCallback().toString());
          }
          catch(ClassCastException e)
          {
              throw new LoginException("Credential info is not of type byte[], "+ 
e.getMessage());
          }
      }
  
      private boolean validateCache(Object cacheCredential)
      {
          boolean isValid = false;
          if( cacheCredential instanceof byte[] )
          {
              byte[] a1 = (byte[]) cacheCredential;
              isValid = Arrays.equals(a1, sessionKey);
          }
          return isValid;
      }
  
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/jaas/SRPLoginModule.java
  
  Index: SRPLoginModule.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp.jaas;
  
  import java.lang.reflect.Constructor;
  import java.rmi.Naming;
  import java.security.Principal;
  import java.util.Map;
  import java.util.Set;
  import javax.naming.InitialContext;
  import javax.security.auth.Subject;
  import javax.security.auth.callback.CallbackHandler;
  import javax.security.auth.callback.Callback;
  import javax.security.auth.callback.NameCallback;
  import javax.security.auth.callback.PasswordCallback;
  import javax.security.auth.callback.UnsupportedCallbackException;
  import javax.security.auth.login.LoginException;
  import javax.security.auth.spi.LoginModule;
  
  import org.jboss.security.srp.PkgCategory;
  import org.jboss.security.srp.SRPClientSession;
  import org.jboss.security.srp.SRPServerInterface;
  import org.jboss.security.srp.SRPServerInterface.SRPParameters;
  
  /** A login module that uses the SRP protocol documented in RFC2945
  to authenticate a username & password in a secure fashion without
  using an encrypted channel.
  
  This product uses the 'Secure Remote Password' cryptographic
  authentication system developed by Tom Wu ([EMAIL PROTECTED]).
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SRPLoginModule implements LoginModule
  {
      private Subject subject;
      private CallbackHandler handler;
      private Map sharedState;
      private String principalClassName;
      private String srpServerRmiUrl;
      private String srpServerJndiName;
      private String username;
      private String password;
      private Principal userPrincipal;
      private boolean debug;
      private boolean loginFailed;
  
      /** Creates new SRPLoginModule */
      public SRPLoginModule()
      {
      }
  
  // --- Begin LoginModule interface methods
      /**
      @param subject, the subject to authenticate
      @param handler, the app CallbackHandler used to obtain username & password
      @param sharedState, used to propagate the authenticated principal and
          credential hash.
      @param options, the login module options. These include:
          principalClassName: the java.security.Principal class name implimentation to 
use.
          srpServerJndiName: the jndi name of the SRPServerInterface implimentation to 
use. This
              is tried before srpServerRmiUrl.
          srpServerRmiUrl: the rmi url for the SRPServerInterface implimentation to 
use.
          debug: if true, print the login module progress details
      */
      public void initialize(Subject subject, CallbackHandler handler, Map 
sharedState, Map options)
      {
          this.subject = subject;
          this.handler = handler;
          this.sharedState = sharedState;
          principalClassName = (String) options.get("principalClassName");
          srpServerJndiName = (String) options.get("srpServerJndiName");
          srpServerRmiUrl = (String) options.get("srpServerRmiUrl");
          String o = (String) options.get("debug");
          if( o != null )
              debug = Boolean.valueOf(o).booleanValue();
      }
  
      /** This is where the SRP protocol exchange occurs.
      @return true is login succeeds, false if login does not apply.
      @exception LoginException, thrown on login failure.
      */
      public boolean login() throws LoginException
      {
          loginFailed = true;
          getUserInfo();
          SRPServerInterface server;
          // First try to locate an SRPServerInterface using JNDI
          if( srpServerJndiName != null )
          {
              server = loadServerFromJndi(srpServerJndiName);
          }
          else if( srpServerRmiUrl != null )
          {
              server = loadServer(srpServerRmiUrl);
          }
          else
          {
              throw new LoginException("No option specified to access a 
SRPServerInterface instance");
          }
          if( server == null )
              throw new LoginException("Failed to access a SRPServerInterface 
instance");
  
          byte[] M1, M2;
          SRPClientSession client = null;
          try
          {   // Perform the SRP login protocol
              PkgCategory.debug("Getting SRP parameters for username: "+username);
              SRPParameters params = server.getSRPParameters(username);
              PkgCategory.debug("Creating SRPClientSession");
              client = new SRPClientSession(username, password, params.s, params.N, 
params.g);
              PkgCategory.debug("Generating client public key");
              byte[] A = client.exponential();
              PkgCategory.debug("Exchanging public keys");
              byte[] B = server.init(username, A);
              PkgCategory.debug("Generating server challenge");
              M1 = client.response(B);
              PkgCategory.debug("Exchanging challenges");
              M2 = server.verify(username, M1);
          }
          catch(Exception e)
          {
              PkgCategory.warn("Failed complete SRP login", e);
              throw new LoginException("Failed complete SRP login, 
msg="+e.getMessage());
          }
          finally
          {
              server = null;
          }
  
          PkgCategory.debug("Verifying server response");
          if( client.verify(M2) == false )
              throw new LoginException("Failed to validate server reply");
          PkgCategory.debug("Login succeeded");
  
          // Put the username and the client challenge into the sharedState map
          sharedState.put("javax.security.auth.login.name", username);
          sharedState.put("javax.security.auth.login.password", M1);
          loginFailed = false;
          return true;
      }
  
      /** All login modules have completed the login() phase, comit if we
      succeeded. This entails adding an instance of principalClassName to the
      subject principals set.
      @return false, if the login() failed, true if the commit succeeds.
      @exception LoginException, thrown on failure to create a Principal.
      */
      public boolean commit() throws LoginException
      {
          if( loginFailed == true )
              return false;
          if( principalClassName == null )
              throw new LoginException("No principalClassName specified");
  
          // Associate an instance of Principal with the subject
          userPrincipal = null;
          try
          {
              ClassLoader loader = Thread.currentThread().getContextClassLoader();
              Class clazz = loader.loadClass(principalClassName);
              Class[] parameterTypes = {String.class};
              Constructor ctor = clazz.getConstructor(parameterTypes);
              String[] args = {username};
              userPrincipal = (Principal) ctor.newInstance(args);
          }
          catch(Exception e)
          {
              throw new LoginException("Failed to create Principal, "+e.getMessage());
          }
          finally
          {
              password = null;
          }
          subject.getPrincipals().add(userPrincipal);
  
          return true;
      }
  
      public boolean abort() throws LoginException
      {
          username = null;
          password = null;
          return true;
      }
  
  
      /** Remove the userPrincipal associated with the subject.
      @return true always.
      @exception LoginException, thrown on exception during remove of the Principal
          added during the commit.
      */
      public boolean logout() throws LoginException
      {
          try
          {
              if( subject.isReadOnly() == false )
              {   // Remove userPrincipal
                  Set s = subject.getPrincipals(userPrincipal.getClass());
                  s.remove(userPrincipal);
              }
          }
          catch(Exception e)
          {
              throw new LoginException("Failed to remove user principal, 
"+e.getMessage());
          }
          return true;
      }
  
  // --- End LoginModule interface methods
  
      private void getUserInfo() throws LoginException
      {
          // See if there is a shared username & password
          String _username = (String) 
sharedState.get("javax.security.auth.login.name");
          char[] _password = null;
          if( username != null )
          {
              Object pw = sharedState.get("javax.security.auth.login.password");
              if( pw instanceof char[] )
                  _password = (char[]) pw;
              else if( pw != null )
                  _password = pw.toString().toCharArray();
          }
  
          // If we have a username, password return
          if( _username != null && _password != null )
          {
              username = _username;
              password = new String(_password);
              return;
          }
  
          // Request a username and password
          if( handler == null )
              throw new LoginException("No CallbackHandler provied to SRPLoginModule");
  
          NameCallback nc = new NameCallback("Username: ", "guest");
          PasswordCallback pc = new PasswordCallback("Password: ", false);
          Callback[] callbacks = { nc, pc };
          try
          {
              handler.handle(callbacks);
              username = nc.getName();
              _password = pc.getPassword();
              if( _password != null )
                  password = new String(_password);
              pc.clearPassword();
          }
          catch(java.io.IOException e)
          {
              throw new LoginException(e.toString());
          }
          catch(UnsupportedCallbackException uce)
          {
              throw new LoginException("UnsupportedCallback: " + 
uce.getCallback().toString());
          }
      }
  
      private SRPServerInterface loadServerFromJndi(String jndiName)
      {
          SRPServerInterface server = null;
          try
          {
              InitialContext ctx = new InitialContext();
              server = (SRPServerInterface) ctx.lookup(jndiName);
          }
          catch(Exception e)
          {
              e.printStackTrace();
          }
          return server;
      }
      private SRPServerInterface loadServer(String rmiUrl)
      {
          SRPServerInterface server = null;
          try
          {
              server = (SRPServerInterface) Naming.lookup(rmiUrl);
          }
          catch(Exception e)
          {
              e.printStackTrace();
          }
          return server;
      }
  }
  
  
  

Reply via email to