org.apache.jackrabbit.core.security.JahiaLoginModule.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.jackrabbit.core.security.JahiaLoginModule.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.apache.jackrabbit.core.security;

import org.apache.commons.id.IdentifierGenerator;
import org.apache.commons.id.IdentifierGeneratorFactory;
import org.apache.jackrabbit.core.security.authentication.CredentialsCallback;
import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
import org.jahia.jaas.JahiaPrincipal;
import org.jahia.services.content.decorator.JCRUserNode;
import org.jahia.services.usermanager.JahiaGroupManagerService;
import org.jahia.services.usermanager.JahiaUserManagerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Credentials;
import javax.jcr.SimpleCredentials;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import java.security.Principal;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Digital Experience Manager specific implementation of the login module.
 * 
 * @author toto
 */
public class JahiaLoginModule implements LoginModule {
    private static final Logger logger = LoggerFactory.getLogger(JahiaLoginModule.class);

    public static final String SYSTEM = " system ";
    public static final String GUEST = " guest ";
    public static final String REALM_ATTRIBUTE = "org.jahia.realm";

    private static IdentifierGenerator idGen = IdentifierGeneratorFactory.newInstance().sessionIdGenerator();
    private static Map<String, Token> systemPass = new ConcurrentHashMap<String, Token>();

    private Subject subject;
    private Set<Principal> principals = new HashSet<Principal>();
    private CallbackHandler callbackHandler;

    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
            Map<String, ?> options) {
        this.subject = subject;
        this.callbackHandler = callbackHandler;
    }

    @Override
    public boolean login() throws LoginException {
        try {
            String name = null;
            char[] pass = null;
            String realm = null;
            String impersonatorName = null;
            char[] impersonatorPass = null;
            Callback[] callbacks = new Callback[] { new CredentialsCallback() };
            callbackHandler.handle(callbacks);
            Credentials credentials = ((CredentialsCallback) callbacks[0]).getCredentials();

            if (credentials instanceof SimpleCredentials) {
                SimpleCredentials simpleCredentials = (SimpleCredentials) credentials;
                name = simpleCredentials.getUserID();
                pass = simpleCredentials.getPassword();
                realm = (String) simpleCredentials.getAttribute(REALM_ATTRIBUTE);

                SimpleCredentials impersonatorCredentials = (SimpleCredentials) simpleCredentials
                        .getAttribute(SecurityConstants.IMPERSONATOR_ATTRIBUTE);
                if (impersonatorCredentials != null) {
                    // there were impersonator credentials supplied -> will use them
                    impersonatorName = impersonatorCredentials.getUserID();
                    impersonatorPass = impersonatorCredentials.getPassword();
                }
            } else {
                callbacks = new Callback[] { new NameCallback("name?"), new PasswordCallback("pass?", false) };
                callbackHandler.handle(callbacks);

                name = ((NameCallback) callbacks[0]).getName();
                pass = ((PasswordCallback) callbacks[1]).getPassword();
            }
            if (name != null) {
                if (SYSTEM.equals(name)) {
                    String key = new String(pass);
                    Token token = removeToken(name, key);
                    if (token != null) {
                        principals.add(new JahiaPrincipal(SYSTEM, realm, true, false));
                        principals.add(new SystemPrincipal());
                    }
                } else if (name.startsWith(SYSTEM)) {
                    String key = new String(pass);
                    Token token = removeToken(name, key);
                    if (token != null) {
                        principals.add(new JahiaPrincipal(name.substring(SYSTEM.length()), realm, true, false));
                        principals.add(new SystemPrincipal());
                    }
                } else if (GUEST.equals(name)) {
                    principals.add(new JahiaPrincipal(GUEST, null, false, true));
                    principals.add(new AnonymousPrincipal());
                } else {
                    String key = new String(impersonatorPass != null ? impersonatorPass : pass);
                    String lookupUser = impersonatorName != null ? impersonatorName : name;
                    Token token = removeToken(lookupUser, key);

                    boolean ok = token != null;
                    JCRUserNode user = null;
                    if (!ok) {
                        user = JahiaUserManagerService.getInstance().lookupUser(lookupUser);
                        ok = user != null && user.verifyPassword(key);
                    }
                    if (ok && impersonatorName != null) {
                        // ensure the impersonator is root
                        if (user == null) {
                            user = JahiaUserManagerService.getInstance().lookupUser(lookupUser);
                        }
                        if (user == null || !user.isRoot()) {
                            throw new FailedLoginException(
                                    "Only root user credentials can be used as an impersonator.");
                        }
                        // ensure the user exists
                        if (!JahiaUserManagerService.getInstance().userExists(name)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("User {} is not known, a the guest will be used instead", name,
                                        impersonatorName);
                            }
                            principals.add(new JahiaPrincipal(GUEST, null, false, true));
                            ok = false;
                        }
                    }

                    if (ok) {
                        principals.add(new JahiaPrincipal(name, realm, false, false));
                        if (realm == null) {
                            if (JahiaGroupManagerService.getInstance().isAdminMember(name, null, null)) {
                                principals.add(new AdminPrincipal(name));
                            }
                        }
                    }
                }
                if (principals.isEmpty()) {
                    throw new FailedLoginException();
                }
            }
        } catch (UnsupportedCallbackException e) {
            // ignore
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return !principals.isEmpty();
    }

    public static Token removeToken(String name, String key) {
        if (systemPass.get(key) != null && systemPass.get(key).username.equals(name)) {
            return systemPass.remove(key);
        }
        return null;
    }

    public static Token getToken(String name, String key) {
        if (systemPass.get(key) != null && systemPass.get(key).username.equals(name)) {
            return systemPass.get(key);
        }
        return null;
    }

    @Override
    public boolean commit() throws LoginException {
        if (principals.isEmpty()) {
            return false;
        } else {
            // add a principals (authenticated identities) to the Subject
            subject.getPrincipals().addAll(principals);
            return true;
        }
    }

    @Override
    public boolean abort() throws LoginException {
        if (principals.isEmpty()) {
            return false;
        } else {
            logout();
        }
        return true;
    }

    public boolean logout() throws LoginException {
        subject.getPrincipals().removeAll(principals);
        principals.clear();
        return true;
    }

    private static String getSystemPass(String user, List<String> deniedPathes) {
        String p = idGen.nextIdentifier().toString();
        systemPass.put(p, new Token(user, deniedPathes));
        return p;
    }

    public static Credentials getSystemCredentials() {
        return getSystemCredentials(null, null, null);
    }

    /**
     * @deprecated Use method with realm
     */
    @Deprecated
    public static Credentials getSystemCredentials(String username) {
        logger.warn("Getting system credentials with empty realm for " + username);
        return getSystemCredentials(username, null, null);
    }

    public static Credentials getSystemCredentials(String username, String realm) {
        return getSystemCredentials(username, realm, null);
    }

    /**
     * @deprecated Use method with realm
     */
    @Deprecated
    public static Credentials getSystemCredentials(String username, List<String> deniedPathes) {
        logger.warn("Getting system credentials with empty realm for " + username);
        return getSystemCredentials(username, null, deniedPathes);
    }

    public static Credentials getSystemCredentials(String username, String realm, List<String> deniedPathes) {
        if (username == null) {
            return new SimpleCredentials(JahiaLoginModule.SYSTEM,
                    getSystemPass(JahiaLoginModule.SYSTEM, deniedPathes).toCharArray());
        }
        String userID = JahiaLoginModule.SYSTEM + username;
        SimpleCredentials credentials = new SimpleCredentials(userID,
                getSystemPass(userID, deniedPathes).toCharArray());
        credentials.setAttribute(REALM_ATTRIBUTE, realm);
        return credentials;
    }

    public static Credentials getGuestCredentials() {
        return new SimpleCredentials(JahiaLoginModule.GUEST, new char[0]);
    }

    /**
     * @deprecated Use method with realm
     */
    @Deprecated
    public static Credentials getCredentials(String username) {
        logger.warn("Getting credentials with empty realm for " + username);
        return getCredentials(username, null, null);
    }

    public static Credentials getCredentials(String username, String realm) {
        return getCredentials(username, realm, null);
    }

    /**
     * @deprecated Use method with realm
     */
    @Deprecated
    public static Credentials getCredentials(String username, List<String> deniedPathes) {
        logger.warn("Getting credentials with empty realm for " + username);
        return getCredentials(username, null, deniedPathes);
    }

    public static Credentials getCredentials(String username, String realm, List<String> deniedPathes) {
        String userID = username;
        SimpleCredentials credentials = new SimpleCredentials(userID,
                getSystemPass(userID, deniedPathes).toCharArray());
        credentials.setAttribute(REALM_ATTRIBUTE, realm);
        return credentials;
    }

    public static class Token {
        public String username;
        public List<String> deniedPath;

        Token(String username, List<String> deniedPath) {
            this.username = username;
            this.deniedPath = deniedPath;
        }
    }
}