0 Replies Latest reply on Sep 21, 2001 1:52 PM by wglozer

    SRP Authentication via a Database, Tips And Code

    wglozer

      SRPDatabaseVerifierStoreServiceMBean.java

      package jboss;
      
      import org.jboss.security.srp.*;
      
      /**
       * JMX interface for the Database driven SRPVerifierStore.
       *
       * @author Will Glozer
       * @version 1.00a 09/21/2001
       */
      public interface SRPDatabaseVerifierStoreServiceMBean
       extends SRPVerifierStoreServiceMBean {
      
       /**
       * Set the JNDI name of the DataSource that will be used to verify
       * users.
       *
       * @param name The JNDI name.
       */
       void setDsJndiName(String name);
      
       /**
       * Get the JNDI name of the DataSource that will be used to verify users.
       *
       * @return The JNDI name.
       */
       String getDsJndiName();
      
       /**
       * Set the SQL query that will be used to retrieve a user's password,
       * given the username/userid/other user information passed to the verifier.
       *
       * @param query The SQL query.
       */
       void setPasswordQuery(String query);
      
       /**
       * Get the SQL query that will be used to retrieve a user's password.
       *
       * @return The SQL query.
       */
       String getPasswordQuery();
      
      }
      

      SRPDatabaseVerifierStoreService.java
      package jboss;
      
      import javax.naming.*;
      import javax.sql.DataSource;
      
      import org.jboss.naming.*;
      import org.jboss.security.srp.*;
      
      /**
       * A JMX MBean that loads a JDBC driven password verifier for use
       * by the SRP authentication components.
       *
       * @author Will Glozer
       * @version 1.00a 09/21/2001
       */
      public class SRPDatabaseVerifierStoreService
       extends SRPVerifierStoreService
       implements SRPDatabaseVerifierStoreServiceMBean {
      
       protected String dsJndiName = "java:/DefaultDS";
       protected String passwordQuery;
      
       /**
       * Set the JNDI name of the DataSource that will be used to verify
       * users.
       *
       * @param name The JNDI name.
       */
       public void setDsJndiName(String name) {
       dsJndiName = name;
       }
      
       /**
       * Get the JNDI name of the DataSource that will be used to verify users.
       *
       * @return The JNDI name.
       */
       public String getDsJndiName() {
       return dsJndiName;
       }
      
       /**
       * Set the SQL query that will be used to retrieve a user's password,
       * given the username/userid/other user information passed to the verifier.
       *
       * @param query The SQL query.
       */
       public void setPasswordQuery(String query) {
       passwordQuery = query;
       }
      
       /**
       * Get the SQL query that will be used to retrieve a user's password.
       *
       * @reutrn The SQL query.
       */
       public String getPasswordQuery() {
       return passwordQuery;
       }
      
       /**
       * Start this JMX service and bind a JDBCVerifierStore for use by
       * the SRPService.
       */
       public void startService() throws Exception {
       Context ctx = new InitialContext();
      
       try {
       SRPVerifierStore store = new JDBCVerifierStore(dsJndiName,
       passwordQuery);
      
       NonSerializableFactory.rebind(ctx, getJndiName(), store);
       } catch (Exception e) {
       e.printStackTrace();
       }
       }
      }
      

      JDBCVerifierStore.java
      package jboss;
      
      import java.io.IOException;
      import java.math.BigInteger;
      import java.util.*;
      import java.sql.*;
      import java.security.KeyException;
      import javax.naming.*;
      import javax.sql.*;
      
      import org.jboss.security.Util;
      import org.jboss.security.srp.*;
      
      /**
       * SRPVerifierStore implementation that verifies users against a JDBC
       * DataSource.
       *
       * @author Will Glozer
       * @version 1.00a 09/21/2001
       */
      public class JDBCVerifierStore implements SRPVerifierStore {
       protected String dsJndiName;
       protected String passwordQuery;
       protected Map userVerifiers;
       protected BigInteger g, N;
      
       /**
       * Create a new JDBCVerifierStore.
       *
       * @param dsJndiName The JNDI location of the DataSource to
       * run queries against.
       * @param passwordQuery The query to use to retrieve passwords.
       */
       public JDBCVerifierStore(String dsJndiName, String passwordQuery)
       throws Exception {
      
       this.passwordQuery = passwordQuery;
       this.dsJndiName = dsJndiName;
       userVerifiers = Collections.synchronizedMap(new HashMap());
      
       try {
       Util.init();
      
       g = SRPConf.getDefaultParams().g();
       N = SRPConf.getDefaultParams().N();
       } catch (Exception e) {
       e.printStackTrace();
       throw new Exception("Failed to initialize security utils: " +
       e.getMessage());
       }
       }
      
       /**
       * Get the VerifierInfo for the specified user.
       *
       * @param username The user's username.
       */
       public VerifierInfo getUserVerifier(String username)
       throws KeyException, IOException {
      
       try {
       VerifierInfo info = (VerifierInfo) userVerifiers.get(username);
       if (info == null) {
       info = makeUserVerifier(username);
       setUserVerifier(username, info);
       }
      
       return info;
       } catch (Exception e) {
       throw new IOException("Cannot create UserVerifier: " + e);
       }
       }
      
       /**
       * Set the VerifierInfo for the specified user.
       *
       * @param username The user's username.
       * @param info The VerifierInfo.
       */
       public void setUserVerifier(String username, VerifierInfo info) {
       userVerifiers.put(username, info);
       }
      
       /**
       * Run the query to retrieve a password from the database.
       *
       * @param username The username to look for.
       */
       protected VerifierInfo makeUserVerifier(String username)
       throws NamingException, IOException, SQLException {
      
      
       Context ctx = new InitialContext();
      
       DataSource ds = (DataSource) ctx.lookup(dsJndiName);
       Connection c = ds.getConnection();
      
       try {
       PreparedStatement st = c.prepareStatement(passwordQuery);
       st.setString(1, username);
      
       ResultSet rs = st.executeQuery();
       if (rs.next() == false) {
       throw new IOException("DB missing data.");
       }
      
       String password = rs.getString(1);
       c.close();
      
       VerifierInfo info = new VerifierInfo();
       info.username = username;
       info.salt = Long.toHexString(Util.nextLong()).getBytes();
       info.verifier = Util.calculateVerifier(username, password,
       info.salt, N, g);
       info.g = g.toByteArray();
       info.N = N.toByteArray();
      
       return info;
       } catch (SQLException e) {
       c.close();
       throw e;
       }
       }
      }
      


      Instead of using the default VerifierStoreService, add this MBean to jboss.jcml:



      SRPVerifierSource
      java:/DefaultDS
      select PASSWORD from USERS where USERNAME=?


      Add the log4j.jar to your base classpath in run.bat/run.sh:

      set JBOSS_CLASSPATH=%JBOSS_CLASSPATH%;run.jar;../lib/ext/log4j.jar

      **Client Section**

      You'll need a JAAS authentication config file containing something like this:

      srp {
      org.jboss.security.srp.jaas.SRPLoginModule required
      password-stacking="useFirstPass"
      principalClassName="org.jboss.security.SimplePrincipal"
      srpServerJndiName="SRPServerInterface"
      debug=true
      ;

      org.jboss.security.ClientLoginModule required
      ;
      };

      When you run your client app, you'll have to set a SecurityManager and a security Policy,
      mine just grants java.security.AllPermission, so run it like this:

      java -Djava.security.manager -Djava.security.policy=my.policy MyApp