/* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY * DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility.*/
package samples.security.jdbcrealm;
import java.util.*;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Driver;
import java.sql.DriverManager;
import javax.security.auth.login.LoginException;
import samples.security.jdbcrealm.JDBCRealm;
import com.iplanet.ias.security.auth.login.PasswordLoginModule;
import com.sun.enterprise.security.auth.AuthenticationStatus;
import com.sun.enterprise.security.auth.realm.Realm;
/**
* JDBCRealm login module.
*
* <P>This login module provides a sample implementation of a custom realm.
* You may use this sample as a template for creating alternate custom
* authentication realm implementations to suit your applications needs.
*
* <P>In order to plug in a realm into the server you need to implement
* both a login module (as shown by this class) which performs the
* authentication and a realm (see JDBCRealm for an example) which is used
* to manage other realm operations.
*
* <P>The PasswordLoginModule class is a JAAS LoginModule and must be
* extended by this class. PasswordLoginModule provides internal
* implementations for all the LoginModule methods (such as login(),
* commit()). This class should not override these methods.
*
* <P>This class is only required to implement the authenticate() method as
* shown below. The following rules need to be followed in the implementation
* <P>This class is only required to implement the authenticate() method as
* shown below. The following rules need to be followed in the implementation
* of this method:
*
* <ul>
* <li>Your code should obtain the user and password to authenticate from
* _username and _password fields, respectively.
* <li>The authenticate method must finish with this call:
* return commitAuthentication(_username, _password, _currentRealm,
* grpList);
* <li>The grpList parameter is a String[] which can optionally be
* populated to contain the list of groups this user belongs to
* </ul>
*
* <P>The PasswordLoginModule, AuthenticationStatus and other classes and
* fields referenced in the sample code should be treated as opaque
* undocumented interfaces.
*
* <P>Sample setting in server.xml for JDBCLoginModule
* <pre>
* <auth-realm name="jdbc" classname="samples.security.jdbcrealm.JDBCRealm">
* <property name="dbdrivername" value="com.pointbase.jdbc.jdbcUniversalDriver"/>
* <property name="dburl" value="jdbc:pointbase:server://localhost:9092/sample"/>
* <property name="dbusername" value="public"/>
* <property name="dbpasswd" value="public"/>
* <property name="usertable" value="user_tbl"/>
* <property name="usernamecol" value="uid"/>
* <property name="userpasswdcol" value="passwd"/>
* <property name="usergroupcol" value="groups"/>
* <property name="jaas-context" value="jdbcRealm"/>
* </auth-realm>
* </pre>
*/
public class JDBCLoginModule extends PasswordLoginModule
{
static final String PARAMS_DBDRIVERNAME= "dbdrivername";
static final String PARAMS_DBURL = "dburl";
static final String PARAMS_DBUSERNAME = "dbusername";
static final String PARAMS_DBPASSWD = "dbpasswd";
static final String PARAMS_USERTABLE = "usertable";
static final String PARAMS_ROLETABLE = "roletable";
static final String PARAMS_USERNAMECOL = "usernamecol";
static final String PARAMS_USERPASSWDCOL= "userpasswdcol";
static final String PARAMS_USERGROUPCOL = "usergroupcol";
static Driver _dbdriver = null;
static Connection _dbConnection = null;
/**
* Perform authentication.
*/
protected AuthenticationStatus authenticate()
throws LoginException
{
if (!(_currentRealm instanceof JDBCRealm)) {
throw new LoginException("JDBCLoginModule requires JDBCRealm.");
}
String[] grpList = this.authenticate(_username, _password);
if (grpList == null) { // JAAS behavior
throw new LoginException("Failed JDBC login: " + _username);
}
System.out.println("JDBCRealm login succeeded.");
return commitAuthentication(_username, _password,
_currentRealm, grpList);
}
/**
* Return the user group associated with the specified username and
* credentials, if there is one; otherwise return <code>null</code>.
*
* @param username the user's id
* @param passwd the user's clear password
*/
private String[] authenticate(String username,String passwd)
{
// Look up the user's credentials
String dbCredential = null;
String dbgroups = null;
JDBCRealm jdbcRealm = (JDBCRealm)_currentRealm;
String usertable = jdbcRealm.getRealmProperty(PARAMS_USERTABLE);
String roletable = jdbcRealm.getRealmProperty(PARAMS_ROLETABLE);
String usernamecol = jdbcRealm.getRealmProperty(PARAMS_USERNAMECOL);
String userpasswdcol= jdbcRealm.getRealmProperty(PARAMS_USERPASSWDCOL);
String usergroupcol = jdbcRealm.getRealmProperty(PARAMS_USERGROUPCOL);
String sql = "SELECT " + userpasswdcol + "," + usergroupcol +
" FROM " + usertable + ","+ roletable +
" WHERE " + usertable + "." + usernamecol + " =? and " +
usertable + ".id = " + roletable + ".userid" ;
PreparedStatement ps = null;
try {
Connection dbcon = getConnection();
ps = dbcon.prepareStatement(sql);
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
dbCredential = rs.getString(1).trim();
dbgroups = rs.getString(2).trim();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
ps.close();
} catch (SQLException ignore) {
ignore.printStackTrace();
}
}
String[] g = null;
if ( (dbCredential!= null) && (dbCredential.equals(passwd)) ) {
Vector membership = new Vector();
if (dbgroups != null) {
StringTokenizer gst = new StringTokenizer(dbgroups,",;");
while (gst.hasMoreTokens()) {
membership.add(gst.nextToken() );
}
}
if (membership.size()>0) {
g = new String[membership.size()];
membership.toArray(g);
jdbcRealm.setGroupNames(username,g);
}
}
return g;
}
/**
* get jdbc connection.
*/
private Connection getConnection() throws SQLException
{
if (_dbConnection != null)
return (_dbConnection);
if (_dbConnection != null)
return (_dbConnection);
JDBCRealm jdbcRealm = (JDBCRealm)_currentRealm;
String dbdrivername = jdbcRealm.getRealmProperty(PARAMS_DBDRIVERNAME);
String dburl = jdbcRealm.getRealmProperty(PARAMS_DBURL);
String dbusername = jdbcRealm.getRealmProperty(PARAMS_DBUSERNAME);
String dbpasswd = jdbcRealm.getRealmProperty(PARAMS_DBPASSWD);
if (_dbdriver == null) {
try {
Class clazz = Class.forName(dbdrivername);
_dbdriver = (Driver) clazz.newInstance();
} catch (Throwable e) {
throw new SQLException(e.getMessage());
}
}
// Open a new connection
Properties props = new Properties();
props.put("user",dbusername);
props.put("password",dbpasswd);
Connection dbcon = _dbdriver.connect(dburl,props);
dbcon.setAutoCommit(false);
return (dbcon);
}
}