FileDocCategorySizeDatePackage
JDBCRealm.javaAPI DocGlassfish v2 API17963Fri May 25 07:56:56 BST 2007com.sun.enterprise.security.auth.realm.jdbc

JDBCRealm

public final class JDBCRealm extends com.sun.enterprise.security.auth.realm.IASRealm
Realm for supporting JDBC authentication.

The JDBC realm needs the following properties in its configuration:

  • jaas-context : JAAS context name used to access LoginModule for authentication (for example JDBCRealm).
  • datasource-jndi : jndi name of datasource
  • db-user : user name to access the datasource
  • db-password : password to access the datasource
  • digest: digest mechanism
  • charset: charset encoding
  • user-table: table containing user name and password
  • group-table: table containing user name and group name
  • user-name-column: column corresponding to user name in user-table and group-table
  • password-column : column corresponding to password in user-table
  • group-name-column : column corresponding to group in group-table
see
com.sun.enterprise.security.auth.login.SolarisLoginModule

Fields Summary
public static final String
AUTH_TYPE
public static final String
PARAM_DATASOURCE_JNDI
public static final String
PARAM_DB_USER
public static final String
PARAM_DB_PASSWORD
public static final String
PARAM_DIGEST_ALGORITHM
public static final String
DEFAULT_DIGEST_ALGORITHM
public static final String
NONE
public static final String
PARAM_ENCODING
public static final String
HEX
public static final String
BASE64
public static final String
DEFAULT_ENCODING
public static final String
PARAM_CHARSET
public static final String
PARAM_USER_TABLE
public static final String
PARAM_USER_NAME_COLUMN
public static final String
PARAM_PASSWORD_COLUMN
public static final String
PARAM_GROUP_TABLE
public static final String
PARAM_GROUP_NAME_COLUMN
private static final char[]
HEXADECIMAL
private Map
groupCache
private Vector
emptyVector
private String
passwordQuery
private String
groupQuery
private MessageDigest
md
Constructors Summary
Methods Summary
public java.lang.String[]authenticate(java.lang.String username, java.lang.String password)
Invoke the native authentication call.

param
username User to authenticate.
param
password Given password.
returns
true of false, indicating authentication status.

        String[] groups = null;
        if (isUserValid(username, password)) {
            groups = findGroups(username);
            groups = addAssignGroups(groups);
            setGroupNames(username, groups);
        }
        return groups;
    
private java.lang.Stringbase64Encode(byte[] bytes)

        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    
private voidclose(java.sql.Connection conn, java.sql.PreparedStatement stmt, java.sql.ResultSet rs)

        if (rs != null) {
            try {
                rs.close();
            } catch(Exception ex) {
            }
        }
            
        if (stmt != null) {
            try {
                stmt.close();
            } catch(Exception ex) {
            }
        }
            
        if (conn != null) {
            try {
                conn.close();
            } catch(Exception ex) {
            }
        }
    
private java.lang.String[]findGroups(java.lang.String user)
Delegate method for retreiving users groups

param
user user's identifier
return
array of group key

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        try{
            connection = getConnection();
            statement =  connection.prepareStatement(groupQuery);
            statement.setString(1, user);
            rs = statement.executeQuery();
            final List<String> groups = new ArrayList<String>();
            while (rs.next()) {
                groups.add(rs.getString(1));
            }
            final String[] groupArray = new String[groups.size()];
            return groups.toArray(groupArray);
        } catch(Exception ex) {
            _logger.log(Level.SEVERE, "jdbcrealm.grouperror", user);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Cannot load group", ex);
            }
            return null;
        } finally {
            close(connection, statement, rs);
        }
    
public java.lang.StringgetAuthType()
Returns a short (preferably less than fifteen characters) description of the kind of authentication which is supported by this realm.

return
Description of the kind of authentication that is directly supported by this realm.

        return AUTH_TYPE;
    
private java.sql.ConnectiongetConnection()
Return a connection from the properties configured

return
a connection


        final String dsJndi = this.getProperty(PARAM_DATASOURCE_JNDI);
        final String dbUser = this.getProperty(PARAM_DB_USER);
        final String dbPassword = this.getProperty(PARAM_DB_PASSWORD);
        try{
            final DataSource dataSource = 
                (DataSource)ConnectorRuntime.getRuntime().lookupNonTxResource(dsJndi,false);
            
            Connection connection = null;
            if (dbUser != null && dbPassword != null) {
                connection = dataSource.getConnection(dbUser, dbPassword);
            } else {
                connection = dataSource.getConnection();
            }
            return connection;
        } catch(Exception ex) {
            String msg = sm.getString("jdbcrealm.cantconnect", dsJndi, dbUser);
            LoginException loginEx = new LoginException(msg);
            loginEx.initCause(ex);
            throw loginEx;
        }
    
public java.util.EnumerationgetGroupNames(java.lang.String username)
Returns the name of all the groups that this user belongs to. It loads the result from groupCache first. This is called from web path group verification, though it should not be.

param
username Name of the user in this realm whose group listing is needed.
return
Enumeration of group names (strings).
exception
InvalidOperationException thrown if the realm does not support this operation - e.g. Certificate realm does not support this operation.

        Vector vector = groupCache.get(username);
        if (vector == null) {
            String[] grps = findGroups(username);
            setGroupNames(username, grps);
            vector = groupCache.get(username);
        }
        return vector.elements();
    
private java.lang.StringhashPassword(java.lang.String password)

        String result = null;
        byte[] bytes = null;
        String charSet = getProperty(PARAM_CHARSET);
        if (charSet != null) {
            bytes = password.getBytes(charSet);
        } else {
            bytes = password.getBytes();
        }
        if (md != null) {
            synchronized(md) {
                md.reset();
                bytes = md.digest(bytes);
            }
        }

        String encoding = getProperty(PARAM_ENCODING);
        if (HEX.equalsIgnoreCase(encoding)) {
            result = hexEncode(bytes);
        } else if (BASE64.equalsIgnoreCase(encoding)) {
            result = base64Encode(bytes);
        } else { // no encoding specified
            result = new String(bytes);
        }
        return result;
    
private java.lang.StringhexEncode(byte[] bytes)

        StringBuilder sb = new StringBuilder(2 * bytes.length);
        for (int i = 0; i < bytes.length; i++) {
            int low = (int)(bytes[i] & 0x0f);
            int high = (int)((bytes[i] & 0xf0) >> 4);
            sb.append(HEXADECIMAL[high]);
            sb.append(HEXADECIMAL[low]);
        }
        return sb.toString();
    
public synchronized voidinit(java.util.Properties props)
Initialize a realm with some properties. This can be used when instantiating realms from their descriptions. This method may only be called a single time.

param
props Initialization parameters used by this realm.
exception
BadRealmException If the configuration parameters identify a corrupt realm.
exception
NoSuchRealmException If the configuration parameters specify a realm which doesn't exist.

    
                                                                            
        
              
        super.init(props);
        String jaasCtx = props.getProperty(IASRealm.JAAS_CONTEXT_PARAM);
        String dbUser = props.getProperty(PARAM_DB_USER);
        String dbPassword = props.getProperty(PARAM_DB_PASSWORD);
        String dsJndi = props.getProperty(PARAM_DATASOURCE_JNDI);
        String digestAlgorithm = props.getProperty(PARAM_DIGEST_ALGORITHM,
            DEFAULT_DIGEST_ALGORITHM);
        String encoding = props.getProperty(PARAM_ENCODING);
        String charset = props.getProperty(PARAM_CHARSET);
        String userTable = props.getProperty(PARAM_USER_TABLE);
        String userNameColumn = props.getProperty(PARAM_USER_NAME_COLUMN);
        String passwordColumn = props.getProperty(PARAM_PASSWORD_COLUMN);
        String groupTable = props.getProperty(PARAM_GROUP_TABLE);
        String groupNameColumn = props.getProperty(PARAM_GROUP_NAME_COLUMN);
        
        if (jaasCtx == null) {
            String msg = sm.getString(
                "realm.missingprop", IASRealm.JAAS_CONTEXT_PARAM, "JDBCRealm");
            throw new BadRealmException(msg);
        }

        if (dsJndi == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_DATASOURCE_JNDI, "JDBCRealm");
            throw new BadRealmException(msg);
        }
        if (userTable == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_USER_TABLE, "JDBCRealm");
            throw new BadRealmException(msg);
        }
        if (groupTable == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_GROUP_TABLE, "JDBCRealm");
            throw new BadRealmException(msg);
        }
        if (userNameColumn == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_USER_NAME_COLUMN, "JDBCRealm");
            throw new BadRealmException(msg);
        }
        if (passwordColumn == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_PASSWORD_COLUMN, "JDBCRealm");
            throw new BadRealmException(msg);
        }
        if (groupNameColumn == null) {
            String msg = sm.getString(
                "realm.missingprop", PARAM_GROUP_NAME_COLUMN, "JDBCRealm");
            throw new BadRealmException(msg);
        }

        passwordQuery = "SELECT " + passwordColumn + " FROM " + userTable +
            " WHERE " + userNameColumn + " = ?";

        groupQuery = "SELECT " + groupNameColumn + " FROM " + groupTable +
            " WHERE " + userNameColumn + " = ? ";

        if (!NONE.equalsIgnoreCase(digestAlgorithm)) {
            try {
                md = MessageDigest.getInstance(digestAlgorithm);
            } catch(NoSuchAlgorithmException e) {
                String msg = sm.getString("jdbcrealm.notsupportdigestalg",
                    digestAlgorithm);
                throw new BadRealmException(msg);
            }
        }
        if (md != null && encoding == null) {
            encoding = DEFAULT_ENCODING;
        }

        this.setProperty(IASRealm.JAAS_CONTEXT_PARAM, jaasCtx);
        if (dbUser != null && dbPassword != null) {
            this.setProperty(PARAM_DB_USER, dbUser);
            this.setProperty(PARAM_DB_PASSWORD, dbPassword);
        }
        this.setProperty(PARAM_DATASOURCE_JNDI, dsJndi);
        this.setProperty(PARAM_DIGEST_ALGORITHM, digestAlgorithm);
        if (encoding != null) {
            this.setProperty(PARAM_ENCODING, encoding);
        }
        if (charset != null) {
            this.setProperty(PARAM_CHARSET, charset);
        }

        if (_logger.isLoggable(Level.FINEST)) {
            _logger.finest("JDBCRealm : " + 
                IASRealm.JAAS_CONTEXT_PARAM + "= " + jaasCtx + ", " +
                PARAM_DATASOURCE_JNDI + " = " + dsJndi + ", " +
                PARAM_DB_USER + " = " + dbUser + ", " +
                PARAM_DIGEST_ALGORITHM + " = " + digestAlgorithm + ", " +
                PARAM_ENCODING + " = " + encoding + ", " +
                PARAM_CHARSET + " = " + charset);
        }

        groupCache = new HashMap<String, Vector>();
        emptyVector = new Vector<String>();
    
private booleanisUserValid(java.lang.String user, java.lang.String password)
Test if a user is valid

param
user user's identifier
param
password user's password
return
true if valid

        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;
        boolean valid = false;

        try {
            String hpwd = hashPassword(password);
            connection = getConnection();
            statement =  connection.prepareStatement(passwordQuery);
            statement.setString(1, user);
            rs = statement.executeQuery();
            String pwd = null;
            if (rs.next()) {
                pwd = rs.getString(1);
                if (HEX.equalsIgnoreCase(getProperty(PARAM_ENCODING))) {
                    valid = pwd.equalsIgnoreCase(hpwd);
                } else {
                    valid = pwd.equals(hpwd);
                }
            }
        } catch(Exception ex) {
            _logger.log(Level.SEVERE, "jdbcrealm.invaliduser", user);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Cannot validate user", ex);
            }
        } finally {
            close(connection, statement, rs);
        }
        return valid;
    
private voidsetGroupNames(java.lang.String username, java.lang.String[] groups)

        Vector<String> v = null;
        
        if (groups == null) {
            v = emptyVector;

        } else {
            v = new Vector<String>(groups.length + 1);
            for (int i=0; i<groups.length; i++) {
                v.add(groups[i]);
            }
        }
        
        synchronized (this) {
            groupCache.put(username, v);
        }