custom login module CQ / AEM (5.6 and less)

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
}

Comments