/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.jaas; import java.security.Principal; import java.util.Arrays; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import com.sun.security.auth.callback.TextCallbackHandler; import org.ldaptive.Credential; import org.ldaptive.LdapEntry; import org.ldaptive.LdapException; import org.ldaptive.ReturnAttributes; import org.ldaptive.auth.AuthenticationRequest; import org.ldaptive.auth.AuthenticationResponse; import org.ldaptive.auth.Authenticator; import org.ldaptive.auth.User; /** * Provides a JAAS authentication hook for LDAP authentication. * * @author Middleware Services */ public class LdapLoginModule extends AbstractLoginModule { /** User attribute to add to role data. */ private String[] userRoleAttribute = ReturnAttributes.NONE.value(); /** Factory for creating authenticators with JAAS options. */ private AuthenticatorFactory authenticatorFactory; /** Authenticator to use against the LDAP. */ private Authenticator auth; /** Authentication request to use for authentication. */ private AuthenticationRequest authRequest; @Override public void initialize( final Subject subject, final CallbackHandler callbackHandler, final Map<String, ?> sharedState, final Map<String, ?> options) { setLdapPrincipal = true; setLdapCredential = true; super.initialize(subject, callbackHandler, sharedState, options); for (String key : options.keySet()) { final String value = (String) options.get(key); if ("userRoleAttribute".equalsIgnoreCase(key)) { if ("".equals(value)) { userRoleAttribute = ReturnAttributes.NONE.value(); } else if ("*".equals(value)) { userRoleAttribute = ReturnAttributes.ALL_USER.value(); } else { userRoleAttribute = value.split(","); } } else if ("authenticatorFactory".equalsIgnoreCase(key)) { try { authenticatorFactory = (AuthenticatorFactory) Class.forName(value).newInstance(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { throw new IllegalArgumentException(e); } } } if (authenticatorFactory == null) { authenticatorFactory = new PropertiesAuthenticatorFactory(); } logger.trace( "authenticatorFactory = {}, userRoleAttribute = {}", authenticatorFactory, Arrays.toString(userRoleAttribute)); auth = authenticatorFactory.createAuthenticator(options); logger.debug("Retrieved authenticator from factory: {}", auth); authRequest = authenticatorFactory.createAuthenticationRequest(options); authRequest.setReturnAttributes(userRoleAttribute); logger.debug("Retrieved authentication request from factory: {}", authRequest); } @Override protected boolean login(final NameCallback nameCb, final PasswordCallback passCb) throws LoginException { try { getCredentials(nameCb, passCb, false); authRequest.setUser(new User(nameCb.getName())); authRequest.setCredential(new Credential(passCb.getPassword())); AuthenticationResponse response = auth.authenticate(authRequest); LdapEntry entry = null; if (response.getResult()) { entry = response.getLdapEntry(); if (entry != null) { roles.addAll(LdapRole.toRoles(entry)); if (defaultRole != null && !defaultRole.isEmpty()) { roles.addAll(defaultRole); } } loginSuccess = true; } else { if (tryFirstPass) { getCredentials(nameCb, passCb, true); response = auth.authenticate(authRequest); if (response.getResult()) { entry = response.getLdapEntry(); if (entry != null) { roles.addAll(LdapRole.toRoles(entry)); } if (defaultRole != null && !defaultRole.isEmpty()) { roles.addAll(defaultRole); } loginSuccess = true; } else { loginSuccess = false; } } else { loginSuccess = false; } } if (!loginSuccess) { logger.debug("Authentication failed: " + response); throw new LoginException("Authentication failed: " + response); } else { if (setLdapPrincipal) { principals.add(new LdapPrincipal(nameCb.getName(), entry)); } final String loginDn = response.getResolvedDn(); if (loginDn != null && setLdapDnPrincipal) { principals.add(new LdapDnPrincipal(loginDn, entry)); } if (setLdapCredential) { credentials.add(new LdapCredential(passCb.getPassword())); } storeCredentials(nameCb, passCb, loginDn); } } catch (LdapException e) { logger.debug("Error occurred attempting authentication", e); loginSuccess = false; throw new LoginException(e != null ? e.getMessage() : "Authentication Error"); } return true; } /** * This provides command line access to this JAAS module. * * @param args command line arguments * * @throws Exception if an error occurs */ public static void main(final String[] args) throws Exception { String name = "ldaptive"; if (args.length > 0) { name = args[0]; } final LoginContext lc = new LoginContext(name, new TextCallbackHandler()); lc.login(); System.out.println("Authentication/Authorization succeeded"); final Set<Principal> principals = lc.getSubject().getPrincipals(); System.out.println("Subject Principal(s): "); for (Principal p : principals) { System.out.println(" " + p); } lc.logout(); } }