import java.security.Principal; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.jcr.Credentials; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; import javax.jcr.Value; import javax.jcr.ValueFactory; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginException; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.principal.PrincipalIterator; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.security.authentication.AbstractLoginModule; import org.apache.jackrabbit.core.security.authentication.Authentication; import org.apache.jackrabbit.core.security.authentication.token.TokenBasedAuthentication; import org.apache.jackrabbit.core.security.principal.EveryonePrincipal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyCustomLoginModule extends AbstractLoginModule { private static final String PARAM_CACHE_EXPIRATION = "cache.expiration"; private static final String ATTR_CLEAR_CREDENTIAL_COOKIE = "CLEAR_CREDENTIAL_COOKIE"; /** The everyone group principal */ private static final EveryonePrincipal EVERYONE_PRINCIPAL = EveryonePrincipal.getInstance(); private static final Principal FAILED_PRINCIPAL = new Principal() { public String getName() { return null; } }; /** * Optional configuration parameter to disable token based authentication. */ private static final String PARAM_DISABLE_TOKEN_AUTH = "disableTokenAuth"; /** * Optional configuration parameter to disable token based authentication. */ private static final String PARAM_TOKEN_EXPIRATION = "tokenExpiration"; private static final String PARAM_INTERMEDIATE_PATH = "autocreate.intermediatePath"; /** * Flag indicating if Token-based authentication is disabled by the * LoginModule configuration. */ private boolean disableTokenAuth; /** * The expiration time for login tokens as set by the LoginModule * configuration. */ private long tokenExpiration = TokenBasedAuthentication.TOKEN_EXPIRATION; /** * The user object retrieved during the authentication process. */ private User user; @SuppressWarnings("rawtypes") private Map options; private SessionImpl session; private UserManager userManager; private int profileCacheExpirationInSeconds; @Override public boolean abort() throws LoginException { this.loggedInPerson = null; this.cookieCredentials = null; return super.abort(); } @Override public boolean commit() throws LoginException { if (!isInitialized() || principal == null) { return false; } if (credentials != null && isAnonymous(credentials)) { return super.commit(); } // Your custom Logic to do something with user // add everyone group, unless principal is everyone if (!principal.equals(EVERYONE_PRINCIPAL)) { principals.add(EVERYONE_PRINCIPAL); } if (TokenBasedAuthentication.doCreateToken(credentials)) { Session s = null; try { /* * use a different session instance to create the token node * in order to prevent concurrent modifications with the * shared system session. */ s = session.createSession(session.getWorkspace().getName()); Credentials tc = TokenBasedAuthentication.createToken((User) user, credentials, tokenExpiration, s); if (tc != null) { subject.getPublicCredentials().add(tc); } } catch (RepositoryException e) { LoginException le = new LoginException("Failed to commit: " + e.getMessage()); le.initCause(e); throw le; } finally { if (s != null) { s.logout(); } } } subject.getPrincipals().addAll(principals); } catch (RepositoryException e) { log.error("commit: could not commit: " + e); abort(); throw (LoginException) new LoginException().initCause(e); } subject.getPublicCredentials().add(credentials); return true; } private boolean shouldSync(Authorizable authz) throws RepositoryException { //Logic to if sync is required } private Collection<Principal> readPrincipalsFromDefaultPrincipalProvider() { Collection<Principal> principals = new HashSet<Principal>(); principals.add(principal); PrincipalIterator itr = principalProvider.getGroupMembership(principal); while (itr.hasNext()) { Principal principal = itr.nextPrincipal(); principals.add(principal); } return principals; } private boolean verifyPassword(Principal principal, SimpleCredentials credentials) { //Your custom Logic to verify Password } @Override protected void doInit(CallbackHandler callbackHandler, Session session, @SuppressWarnings("rawtypes") Map options) throws LoginException { this.session = (SessionImpl) session; try { this.userManager = ((JackrabbitSession) session).getUserManager(); } catch (RepositoryException e) { LoginException ex = new LoginException("Unable to get user manager from session"); ex.initCause(e); throw ex; } this.options = options; // configuration options related to token based authentication if (options.containsKey(PARAM_DISABLE_TOKEN_AUTH)) { disableTokenAuth = Boolean.parseBoolean(options.get(PARAM_DISABLE_TOKEN_AUTH).toString()); log.debug("- Token authentication disabled -> '" + disableTokenAuth + "'"); } if (options.containsKey(PARAM_TOKEN_EXPIRATION)) { try { tokenExpiration = Long.parseLong(options.get(PARAM_TOKEN_EXPIRATION).toString()); log.debug("- Token expiration -> '" + tokenExpiration + "'"); } catch (NumberFormatException e) { log.warn("Unabled to parse token expiration: ", e.getMessage()); } } if (options.containsKey(PARAM_CACHE_EXPIRATION)) { try { this.profileCacheExpirationInSeconds = Integer.parseInt((String) options.get(PARAM_CACHE_EXPIRATION)); log.debug("- Profile cache expiration -> '" + profileCacheExpirationInSeconds + "'"); } catch (NumberFormatException e) { // ignore and use default } } } @Override protected Authentication getAuthentication(final Principal principal, final Credentials creds) throws RepositoryException { if (principal == FAILED_PRINCIPAL) { return new Authentication() { public boolean authenticate(Credentials credentials) throws RepositoryException { return false; } public boolean canHandle(Credentials credentials) { return true; } }; } else { return new Authentication() { public boolean authenticate(Credentials credentials) throws RepositoryException { //Logic of authentication will work with your third party auth } public boolean canHandle(Credentials credentials) { //Logic if your custom handler can handle this request } }; } } @Override protected Principal getPrincipal(Credentials credentials) { //Method that will return Principal Object from your custom logic } @Override protected String getUserID(Credentials credentials) { //Logic to get UserID } @Override protected boolean impersonate(Principal principal, Credentials credentials) throws RepositoryException, LoginException { Authorizable authrz = userManager.getAuthorizable(principal); if (authrz == null || authrz.isGroup()) { return false; } Subject impersSubject = getImpersonatorSubject(credentials); User user = (User) authrz; if (user.getImpersonation().allows(impersSubject)) { return true; } else { throw new FailedLoginException("attempt to impersonate denied for " + principal.getName()); } } private static final String PARAM_AUTOCREATE_USER_PREFIX = "autocreate.user."; //All other supporting methods or anonymous classes for your custom Login Module } |