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

Reply via email to