SRP Authentication via a Database, Tips And Code
wglozer Sep 21, 2001 1:52 PMSRPDatabaseVerifierStoreServiceMBean.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