I am creating my own LoginModule. I need a UserPrincipal that holds also
the common name and e-mail address of the user. I want to get these
values from the LDAP.
I started with the PropertiesLoginModule so I could read a parameter
file from the Tomee conf directory. For this I created the file
ldap.properties. I changed the server.xml and the login.conf so all
should be configured correct. I put the JAR file with my UserPrincipal,
GroupPrincipal and LoginModule in the Tomee lib directory. When I
restart Tomee and try to access the Tomcat console I enter the userame
and password. My LoginModule is accessed but it cannot read the
properties file. The URL (in the initialize method) is null.
When I put in the values of the ldap.properties in the source and
comment out the reading of the file everything seems to work fine but I
am refused access to the console (Code 403. The group manager-gui is
fetched from the LDAP and put in the subject Principal rolePrincipal list).
Any hint on what I do wrong? Here is the LoginModule class:
package eu.debooy.jaas.ldap;
import static org.apache.openejb.loader.IO.readProperties;
import eu.debooy.jaas.RolePrincipal;
import eu.debooy.jaas.UserPrincipal;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapContext;
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.spi.LoginModule;
import org.apache.openejb.util.ConfUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Marco de Booij
*
* Deze class zorgt ervoor dat de UserPrincipal ook wordt gevuld met
het e-mail
* adres en de volledige naam van de gebruiker.
*
* @see javax.security.auth.spi.LoginModule
*/
public class DoosLoginModule implements LoginModule {
private static final Logger LOGGER =
LoggerFactory.getLogger(DoosLoginModule.class);
private DirContext ctx;
private CallbackHandler handler;
private Properties ldap;
private RolePrincipal rolePrincipal;
private Subject subject;
private List<String> userRoles;
private UserPrincipal userPrincipal;
/**
* Initialiseer de DoosLoginModule.
*/
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?>
options) {
handler = callbackHandler;
this.subject = subject;
if (options.containsKey("ldap")) {
String properties = String.valueOf(options.get("ldap"));
LOGGER.info("ldap : " + properties );
URL propertiesUrl = ConfUtils.getConfResource(properties);
if (null == propertiesUrl) {
LOGGER.info("URL == null");
}
try {
ldap = readProperties(ConfUtils.getConfResource(properties));
LOGGER.debug("host : " + ldap.get("host"));
LOGGER.debug("factories.initctx: " +
ldap.get("factories.initctx"));
LOGGER.debug("factories.control: " +
ldap.get("factories.control"));
LOGGER.debug("user.searchbase : " + ldap.get("user.searchbase"));
LOGGER.debug("role.searchbase : " + ldap.get("role.searchbase"));
} catch (IOException e) {
LOGGER.error(e.getLocalizedMessage());
}
} else {
LOGGER.error("Missing parameter ldap");
}
}
/**
* Controleer de credentials.
*
* @exception LoginException als het authenticatie faalt.
*/
public boolean login() throws LoginException {
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("login");
callbacks[1] = new PasswordCallback("password", false);
try {
handler.handle(callbacks);
String login = ((NameCallback) callbacks[0]).getName();
String password =
String.valueOf(((PasswordCallback) callbacks[1]).getPassword());
// Aanmelden aan de LDAP server
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(LdapContext.CONTROL_FACTORIES,
ldap.getProperty("factories.control"));
env.put(Context.INITIAL_CONTEXT_FACTORY,
ldap.getProperty("factories.initctx"));
env.put(Context.PROVIDER_URL, ldap.getProperty("host"));
env.put(Context.SECURITY_PRINCIPAL, ldap.getProperty("user"));
env.put(Context.SECURITY_CREDENTIALS, ldap.getProperty("password"));
ctx = new InitialDirContext(env);
// Zoeken naar gebruiker
String zoekUid =
MessageFormat.format(ldap.getProperty("user.search"), login);
String[] attrIDs = new String[]{"cn", "mail"};
SearchControls zoek = new SearchControls();
zoek.setReturningAttributes(attrIDs);
zoek.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration<SearchResult>
antwoord =
ctx.search(ldap.getProperty("user.searchbase"),
zoekUid, zoek);
if (!antwoord.hasMore()) {
throw new LoginException("error.authenticatie.verkeerd");
}
SearchResult sr = (SearchResult) antwoord.next();
if (antwoord.hasMore()) {
throw new LoginException("error.authenticatie.verkeerd");
}
Attributes attrs = sr.getAttributes();
String cn = attrs.get("cn").toString().substring(4);
String email =
attrs.get("mail").toString().substring(6);
antwoord.close();
// Sla de informatie op zodat die bij de commit kunnen worden vrij-
// gegeven.
userPrincipal = new UserPrincipal(login);
userPrincipal.setEmail(email);
userPrincipal.setVolledigeNaam(cn);
LOGGER.debug(userPrincipal.toString());
// Zoeken naar alle rollen.
String principal =
MessageFormat.format(ldap.getProperty("check.password"), cn);
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, password);
ctx = new InitialDirContext(env);
zoekUid = MessageFormat.format(ldap.getProperty("role.search"),
login);
userRoles = new ArrayList<String>();
attrIDs = new String[]{"cn"};
zoek = new SearchControls();
zoek.setReturningAttributes(attrIDs);
zoek.setSearchScope(SearchControls.SUBTREE_SCOPE);
antwoord = ctx.search(ldap.getProperty("role.searchbase"),
zoekUid, zoek);
while (antwoord.hasMore()) {
sr = (SearchResult) antwoord.next();
attrs = sr.getAttributes();
userRoles.add(attrs.get("cn").toString().substring(4));
}
antwoord.close();
LOGGER.debug(userRoles.toString());
return true;
} catch (IOException e) {
LOGGER.error(e.getLocalizedMessage());
throw new LoginException(e.getMessage());
} catch (UnsupportedCallbackException e) {
LOGGER.error(e.getLocalizedMessage());
throw new LoginException(e.getMessage());
} catch (NamingException e) {
LOGGER.error(e.getLocalizedMessage());
throw new LoginException(e.getMessage());
}
}
/**
* Zet de UserPrincipal en RolePrincipal.
*
* @exception LoginException als de commit faalt.
*/
public boolean commit() throws LoginException {
if (null == userPrincipal) {
return false;
}
subject.getPrincipals().add(userPrincipal);
if (userRoles != null && userRoles.size() > 0) {
for (String roleNaam : userRoles) {
rolePrincipal = new RolePrincipal(roleNaam);
subject.getPrincipals().add(rolePrincipal);
}
}
return true;
}
/**
* Stop het aanmelden.
*
* @exception LoginException als de abort faalt.
*/
public boolean abort() throws LoginException {
if (null == userPrincipal) {
return false;
}
userRoles = null;
userPrincipal = null;
return true;
}
/**
* Doe een logout.
*
* @exception LoginException als de logout faalt.
*/
public boolean logout() throws LoginException {
subject.getPrincipals().remove(userPrincipal);
subject.getPrincipals().remove(rolePrincipal);
return true;
}
}
Regards,
Marco