User: stark
Date: 01/03/05 01:53:36
Added: src/main/org/jboss/security/plugins/samples
DatabaseServerLoginModule.java
IdentityLoginModule.java JaasServerLoginModule.java
RolesLoginModule.java SimpleServerLoginModule.java
Log:
Initial version of the JBossSX module
Revision Changes Path
1.1
jbosssx/src/main/org/jboss/security/plugins/samples/DatabaseServerLoginModule.java
Index: DatabaseServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins.samples;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
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.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
public class DatabaseServerLoginModule implements LoginModule {
private String _db;
private String _table;
private String _nameCol;
private String _pswCol;
private Subject _subject;
private CallbackHandler _callbackHandler;
private String _username;
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
_subject = subject;
_callbackHandler = callbackHandler;
_db = (String) options.get("db");
_table = (String) options.get("table");
_nameCol = (String) options.get("name");
_pswCol = (String) options.get("password");
}
/**
* Method to authenticate a Subject (phase 1).
*/
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
char[] password;
char[] tmpPassword;
InitialContext initial;
DataSource ds;
Connection conn = null;
PreparedStatement ps;
ResultSet rs;
Object psw;
boolean ok;
try {
// prompt for a username and password
if (_callbackHandler == null) {
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from
the user");
}
callbacks[0] = new NameCallback("User name: ", "guest");
callbacks[1] = new PasswordCallback("Password: ", false);
_callbackHandler.handle(callbacks);
_username = ((NameCallback)callbacks[0]).getName();
tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
if (tmpPassword == null) {
password = null;
} else {
password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);
((PasswordCallback)callbacks[1]).clearPassword();
}
// password authorization
if (_pswCol != null) {
initial = new InitialContext();
ds = (DataSource) initial.lookup( _db );
conn = ds.getConnection();
ps = conn.prepareStatement("SELECT " + _pswCol + " FROM " + _table +
" WHERE " + _nameCol + "=?");
ps.setString(1, _username);
rs = ps.executeQuery();
if (!rs.next()) {
throw new FailedLoginException("Incorrect user name");
}
psw = rs.getObject(1);
if (password == null || psw == null) {
ok = (password == psw);
} else if (psw instanceof byte[]) {
byte[] bpsw;
int len;
char[] cpsw;
bpsw = (byte[]) psw;
// trim zero bytes
for (len = bpsw.length; len>0; len--) {
if (bpsw[len - 1] != 0) {
break;
}
}
cpsw = new char[len];
for (int i = 0; i < len; i++) {
cpsw[i] = (char) bpsw[i];
}
ok = Arrays.equals(password, cpsw);
} else if (psw instanceof String) {
// trim spaces
ok = (new String(password)).equals(((String) psw).trim());
} else {
throw new LoginException("Unsupported SQL type of password
column");
}
if (!ok) {
throw new FailedLoginException("Incorrect password");
}
}
} catch (NamingException ex) {
throw new LoginException(ex.toString());
} catch (java.io.IOException ex) {
throw new LoginException(ex.toString());
} catch (SQLException ex) {
throw new LoginException(ex.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException("Error: " + uce.getCallback().toString() +
" not available to garner authentication information " +
"from the user");
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception ex) {
}
}
}
return true;
}
/**
* Method to commit the authentication process (phase 2).
*/
public boolean commit() throws LoginException {
return true;
}
/**
* Method to abort the authentication process (phase 2).
*/
public boolean abort() throws LoginException {
_username = null;
return true;
}
public boolean logout() throws LoginException {
return true;
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/samples/IdentityLoginModule.java
Index: IdentityLoginModule.java
===================================================================
package org.jboss.security.plugins.samples;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimplePrincipal;
/** A simple login module that simply associates the principal specified
in the module options with any subject authenticated against the module.
The type of Principal class used is org.jboss.security.SimplePrincipal.
If no principal option is specified a principal with the name of 'guest'
is used.
@see org.jboss.security.SimplePrincipal
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class IdentityLoginModule implements LoginModule
{
String principal;
Subject subject;
Map sharedState;
/** Creates new IdentityLoginModule */
public IdentityLoginModule()
{
}
public void initialize(Subject subject, CallbackHandler handler, Map
sharedState, Map options)
{
this.subject = subject;
this.sharedState = sharedState;
principal = (String) options.get("principal");
if( principal == null )
principal = "guest";
}
public boolean login() throws LoginException
{
subject.getPrincipals().add(new SimplePrincipal(principal));
// Put the username into the sharedState map
sharedState.put("javax.security.auth.login.name", principal);
return true;
}
public boolean commit() throws LoginException
{
return true;
}
public boolean abort() throws LoginException
{
return true;
}
public boolean logout() throws LoginException
{
return true;
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/samples/JaasServerLoginModule.java
Index: JaasServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins.samples;
import java.util.*;
import java.io.*;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
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.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.plugins.AbstractServerLoginModule;
/**
* JaasServerLoginModule
* written by: Edward Kenworthy 12th Dec 2000
*
* An example of a realistic ServerLoginModule that can be used when using JAAS
* security with jBoss. I took SimpleServerLoginModule, written by Oleg Nitz and
extended
* the functionality.
*
* It uses two properties files:
* users.properties, which holds users (key) and their password (value).
* roles.properties which holds users (key) and a list of their roles as csv
(value).
*
* Obviously using properties files means it will struggle with very large numbers
of users and
* also as it reads the properties file in at initialisation it will be insensitive
to subsequent
* password changes. It does have the advantage of being realistic in its
functionality.
*
* The other major change I have made is to pull out an abstract class
(AbstractServerLoginModule)
* so that if you want to implement a more scalable way of looking up users and
passwords and roles then you can
* do so without having to start from scratch.
*
* @author <a href="[EMAIL PROTECTED]">Edward Kenworthy</a>
*/
public class JaasServerLoginModule extends AbstractServerLoginModule
{
// users+passwords, users+roles
private Properties _users; // You might think these should be static. The only
problem with
private Properties _roles; // static attributes is they are shared across the
VM. So I chose safety
// over performance.
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
super.initialize(subject, callbackHandler, sharedState, options);
try
{
// Load the properties file that contains the list of users and passwords
LoadUsers();
LoadRoles();
}
catch (Exception e)
{
System.out.print("[JAASSecurity] PANIC! Couldn't load users/passwords/role
files.\n");
e.printStackTrace();
// Note that although this exception isn't passed on, _users or _roles will be null
// so that any call to login will throw a LoginException.
}
}
/**
* Method to authenticate a Subject (phase 1).
*
* Most of the changes from the original SimpleServerLoginModule
* are made in this method. They are:
* users and passwords read from users.properties file
* users and roles read from roles.properties file
*
* I've also removed the notion of a guest login. If you want to provide 'guest'
* access to your beans then simply disable security on them.
*
*/
public boolean login() throws LoginException
{
if (_users == null || _roles == null)
{
throw new LoginException("Missing _users or _roles properties file.");
}
return super.login();
}
// Polymorphic, used by the abstract base class.
protected Enumeration getUsersRoles()
{
String roles = _roles.getProperty(getUsername());
return (roles == null ? null : new StringTokenizer(roles, ","));
}
protected String getUsersPassword()
{
return _users.getProperty(getUsername(), null);
}
// utility methods
private void LoadUsers() throws IOException
{
_users = LoadProperties("users.properties");
}
private void LoadRoles() throws IOException
{
_roles = LoadProperties("roles.properties");
}
/**
* Loads the given properties file and returns a Properties object containing the
* key,value pairs in that file.
* The properties files should be in the class path.
*/
private Properties LoadProperties(String propertiesName) throws IOException
{
Properties bundle = null;
InputStream is
=Thread.currentThread().getContextClassLoader().getResource(propertiesName).openStream();
if (null != is)
{
bundle = new Properties();
bundle.load(is);
}
else
{
throw new IOException("Properties file " + propertiesName + " not found");
}
return bundle;
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/samples/RolesLoginModule.java
Index: RolesLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins.samples;
import java.io.IOException;
import java.io.InputStream;
import java.security.acl.Group;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.Callback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
/** A role mapping LoginModule. This module loads a roles.properties
file from the classpath and creates role mappings for a username
by creating Groups for any username.Roles and username.CallerPrincipal
entries found in the roles.properties file. The Groups are added
to the Subject Principals set. This module must be combined with
a module that does the authentication and passes the username via
the sharedMap as the javax.security.auth.login.name property.
@author [EMAIL PROTECTED]
@version $Revision: 1.1 $
*/
public class RolesLoginModule implements LoginModule
{
private Subject subject;
private Map sharedState;
private Properties roles;
private Group userRoles;
private Group callerPrincipal;
public RolesLoginModule()
{
}
// --- Begin LoginModule interface methods
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler, Map
sharedState, Map options)
{
this.subject = subject;
this.sharedState = sharedState;
}
/** Load the roles.properties file
*/
public boolean login() throws LoginException
{
loadRoles();
return true;
}
public boolean commit()
{
// Get the username from the shared state
String username = (String) sharedState.get("javax.security.auth.login.name");
boolean committed = false;
if( username != null )
{
committed = true;
Set principals = subject.getPrincipals();
// Get the username.Roles for the 'Roles' group
String key = username + ".Roles";
userRoles = createGroup(key, "Roles");
principals.add(userRoles);
// Get the username.CallerPrincipal for the 'CallerPrincipal' group
key = username + ".CallerPrincipal";
callerPrincipal = createGroup(key, "CallerPrincipal");
principals.add(callerPrincipal);
}
return committed;
}
public boolean abort()
{
roles = null;
userRoles = null;
callerPrincipal = null;
return true;
}
public boolean logout()
{
Set principals = subject.getPrincipals();
principals.remove(userRoles);
principals.remove(callerPrincipal);
return true;
}
// --- End LoginModule interface methods
private Group createGroup(String key, String name)
{
String value = roles.getProperty(key);
Group group = new SimpleGroup(name);
if( value != null )
{
StringTokenizer tokenizer = new StringTokenizer(value, ",");
while( tokenizer.hasMoreTokens() )
{
String token = tokenizer.nextToken();
SimplePrincipal p = new SimplePrincipal(token);
group.addMember(p);
}
}
return group;
}
/** Load the roles.properties from the current thread class loader.
*/
private void loadRoles() throws LoginException
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("roles.properties");
if( is == null )
throw new LoginException("Failed to find roles.properties resource");
roles = new Properties();
try
{
roles.load(is);
}
catch(IOException e)
{
throw new LoginException("Failed to load roles.properties,
ioe="+e.getMessage());
}
}
}
1.1
jbosssx/src/main/org/jboss/security/plugins/samples/SimpleServerLoginModule.java
Index: SimpleServerLoginModule.java
===================================================================
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.security.plugins.samples;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
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.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
/**
* This server login module implements the following simple algorithm:
* if password is null, authenticate the user and assign the "guest" role
* else if password is equal to the user name, assign both "user" and "guest" roles
* else don't authenticate.
*/
public class SimpleServerLoginModule implements LoginModule {
private Subject _subject;
private CallbackHandler _callbackHandler;
// username and password
private String _username;
private char[] _password;
/**
* Initialize this LoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map sharedState, Map options) {
_subject = subject;
_callbackHandler = callbackHandler;
}
/**
* Method to authenticate a Subject (phase 1).
*/
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
// prompt for a username and password
if (_callbackHandler == null)
throw new LoginException("Error: no CallbackHandler available " +
"to garner authentication information from the user");
callbacks[0] = new NameCallback("User name: ", "guest");
callbacks[1] = new PasswordCallback("Password: ", false);
try {
_callbackHandler.handle(callbacks);
_username = ((NameCallback)callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback)callbacks[1]).getPassword();
if (tmpPassword != null) {
_password = new char[tmpPassword.length];
System.arraycopy(tmpPassword, 0, _password, 0, tmpPassword.length);
((PasswordCallback)callbacks[1]).clearPassword();
}
} catch (java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch (UnsupportedCallbackException uce) {
throw new LoginException("Error: " + uce.getCallback().toString() +
" not available to garner authentication information " +
"from the user");
}
if (_password != null && !(new String(_password)).equals(_username)) {
throw new FailedLoginException("Password Incorrect");
}
return true;
}
/**
* Method to commit the authentication process (phase 2).
*/
public boolean commit() throws LoginException {
Set roles = _subject.getPublicCredentials();
roles.add("guest");
if (_password != null) {
roles.add("user");
}
return true;
}
/**
* Method to abort the authentication process (phase 2).
*/
public boolean abort() throws LoginException {
_username = null;
if (_password != null) {
for (int i = 0; i < _password.length; i++)
_password[i] = ' ';
_password = null;
}
return true;
}
public boolean logout() throws LoginException {
return true;
}
}