Package org.jboss.seam.security

Source Code of org.jboss.seam.security.IdentityImpl

package org.jboss.seam.security;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpSession;

import org.jboss.seam.security.Authenticator.AuthenticationStatus;
import org.jboss.seam.security.events.AlreadyLoggedInEvent;
import org.jboss.seam.security.events.DeferredAuthenticationEvent;
import org.jboss.seam.security.events.LoggedInEvent;
import org.jboss.seam.security.events.LoginFailedEvent;
import org.jboss.seam.security.events.NotAuthorizedEvent;
import org.jboss.seam.security.events.NotLoggedInEvent;
import org.jboss.seam.security.events.PostAuthenticateEvent;
import org.jboss.seam.security.events.PostLoggedOutEvent;
import org.jboss.seam.security.events.PreAuthenticateEvent;
import org.jboss.seam.security.events.PreLoggedOutEvent;
import org.jboss.seam.security.events.QuietLoginEvent;
import org.jboss.seam.security.jaas.JaasAuthenticator;
import org.jboss.seam.security.management.IdmAuthenticator;
import org.jboss.seam.security.permission.PermissionMapper;
import org.jboss.seam.security.util.Strings;
import org.jboss.solder.beanManager.BeanManagerLocator;
import org.jboss.solder.literal.NamedLiteral;
import org.jboss.solder.logging.Logger;
import org.picketlink.idm.api.Group;
import org.picketlink.idm.api.Role;
import org.picketlink.idm.api.User;
import org.picketlink.idm.impl.api.model.SimpleGroup;
import org.picketlink.idm.impl.api.model.SimpleRole;
import org.picketlink.idm.impl.api.model.SimpleRoleType;

/**
* Identity implementation for authentication and authorization
*
* @author Shane Bryzak
*/
public
@Named("identity")
@SessionScoped
class IdentityImpl implements Identity, Serializable {
    private static final long serialVersionUID = 3751659008033189259L;

    protected static boolean securityEnabled = true;

    private static final Logger log = Logger.getLogger(IdentityImpl.class);

    @Inject BeanManager beanManager;

    @Inject private Credentials credentials;

    @Inject private PermissionMapper permissionMapper;

    @Inject Instance<RequestSecurityState> requestSecurityState;

    @Inject @Any Instance<Authenticator> authenticators;

    @Inject HttpSession session;

    private Authenticator activeAuthenticator;

    private User user;

    private Class<? extends Authenticator> authenticatorClass;
    private String authenticatorName;

    /**
     * Contains a group name to group type:role list mapping of roles assigned
     * during the authentication process
     */
    private Map<String, Map<String, List<String>>> preAuthenticationRoles = new HashMap<String, Map<String, List<String>>>();

    private Set<Role> activeRoles = new HashSet<Role>();

    /**
     * Map of group name:group type group memberships assigned during the
     * authentication process
     */
    private Map<String, List<String>> preAuthenticationGroups = new HashMap<String, List<String>>();

    private Set<Group> activeGroups = new HashSet<Group>();

    private transient ThreadLocal<Boolean> systemOp;

    /**
     * Flag that indicates we are in the process of authenticating
     */
    private boolean authenticating = false;

    public static boolean isSecurityEnabled() {
        return securityEnabled;
    }

    public static void setSecurityEnabled(boolean enabled) {
        securityEnabled = enabled;
    }

    public boolean isLoggedIn() {
        // If there is a user set, then the user is logged in.
        return user != null;
    }

    public Class<? extends Authenticator> getAuthenticatorClass() {
        return authenticatorClass;
    }

    public void setAuthenticatorClass(Class<? extends Authenticator> authenticatorClass) {
        this.authenticatorClass = authenticatorClass;
    }

    public String getAuthenticatorName() {
        return authenticatorName;
    }

    public void setAuthenticatorName(String authenticatorName) {
        this.authenticatorName = authenticatorName;
    }

    public boolean tryLogin() {
        if (!authenticating && getUser() == null && credentials.isSet() &&
                !requestSecurityState.get().isLoginTried()) {
            requestSecurityState.get().setLoginTried(true);
            quietLogin();
        }

        return isLoggedIn();
    }

    public String login() {
        try {
            if (isLoggedIn()) {
                // If authentication has already occurred during this request via a silent login,
                // and login() is explicitly called then we still want to raise the LOGIN_SUCCESSFUL event,
                // and then return.
                if (requestSecurityState.get().isSilentLogin()) {
                    beanManager.fireEvent(new LoggedInEvent(user));
                    return RESPONSE_LOGIN_SUCCESS;
                }

                beanManager.fireEvent(new AlreadyLoggedInEvent());
                return RESPONSE_LOGIN_SUCCESS;
            }

            boolean success = authenticate();

            if (success) {
                if (log.isDebugEnabled()) {
                    log.debug("Login successful");
                }
                beanManager.fireEvent(new LoggedInEvent(user));
                return RESPONSE_LOGIN_SUCCESS;
            }

            beanManager.fireEvent(new LoginFailedEvent(null));
            return RESPONSE_LOGIN_FAILED;
        } catch (Exception ex) {
            log.error("Login failed", ex);

            beanManager.fireEvent(new LoginFailedEvent(ex));

            return RESPONSE_LOGIN_EXCEPTION;
        }
    }

    public void quietLogin() {
        try {
            beanManager.fireEvent(new QuietLoginEvent());

            // Ensure that we haven't been authenticated as a result of the EVENT_QUIET_LOGIN event
            if (!isLoggedIn()) {
                if (credentials.isSet()) {
                    authenticate();

                    if (isLoggedIn()) {
                        requestSecurityState.get().setSilentLogin(true);
                    }
                }
            }
        } catch (Exception ex) {
            log.error("Error authenticating", ex);
            credentials.invalidate();
        }
    }

    protected boolean authenticate() throws AuthenticationException {
        if (authenticating) {
            authenticating = false;
            throw new IllegalStateException("Authentication already in progress.");
        }

        try {
            authenticating = true;

            user = null;

            preAuthenticate();

            activeAuthenticator = lookupAuthenticator();

            if (activeAuthenticator == null) {
                authenticating = false;
                throw new AuthenticationException("An Authenticator could not be located");
            }

            activeAuthenticator.authenticate();

            if (activeAuthenticator.getStatus() == null) {
                throw new AuthenticationException("Authenticator must return a valid authentication status");
            }

            switch (activeAuthenticator.getStatus()) {
                case SUCCESS:
                    postAuthenticate();
                    return true;
                case FAILURE:
                    authenticating = false;
                    return false;
            }

            return false;
        } catch (Exception ex) {
            authenticating = false;
            if (ex instanceof AuthenticationException) {
                throw (AuthenticationException) ex;
            } else {
                throw new AuthenticationException("Authentication failed.", ex);
            }
        }
    }

    /**
     * Clears any roles added by calling addRole() while not authenticated.
     * This method may be overridden by a subclass if different
     * pre-authentication logic should occur.
     */
    protected void preAuthenticate() {
        preAuthenticationRoles.clear();
        beanManager.fireEvent(new PreAuthenticateEvent());
    }

    protected void deferredAuthenticationObserver(@Observes DeferredAuthenticationEvent event) {
        if (event.isSuccess()) {
            postAuthenticate();
        } else {
            authenticating = false;
            activeAuthenticator = null;
        }
    }

    protected void postAuthenticate() {
        if (activeAuthenticator == null) {
            throw new IllegalStateException("activeAuthenticator is null");
        }

        try {
            activeAuthenticator.postAuthenticate();

            if (!activeAuthenticator.getStatus().equals(AuthenticationStatus.SUCCESS)) return;

            user = activeAuthenticator.getUser();

            if (user == null) {
                throw new AuthenticationException("Authenticator must provide a non-null User after successful authentication");
            }

            if (isLoggedIn()) {
                if (!preAuthenticationRoles.isEmpty()) {
                    for (String group : preAuthenticationRoles.keySet()) {
                        Map<String, List<String>> groupTypeRoles = preAuthenticationRoles.get(group);
                        for (String groupType : groupTypeRoles.keySet()) {
                            for (String roleType : groupTypeRoles.get(groupType)) {
                                addRole(roleType, group, groupType);
                            }
                        }
                    }
                    preAuthenticationRoles.clear();
                }

                if (!preAuthenticationGroups.isEmpty()) {
                    for (String group : preAuthenticationGroups.keySet()) {
                        for (String groupType : preAuthenticationGroups.get(group)) {
                            activeGroups.add(new SimpleGroup(group, groupType));
                        }
                    }
                    preAuthenticationGroups.clear();
                }
            }

            beanManager.fireEvent(new PostAuthenticateEvent());
        } finally {
            // Set credential to null whether authentication is successful or not
            activeAuthenticator = null;
            credentials.setCredential(null);
            authenticating = false;
        }
    }

    /**
     * Returns an Authenticator instance to be used for authentication. The default
     * implementation obeys the following business logic:
     * <p/>
     * 1. If the user has specified an authenticatorClass property, use it to
     * locate the Authenticator with that exact type
     * 2. If the user has specified an authenticatorName property, use it to
     * locate and return the Authenticator with that name
     * 3. If the authenticatorClass and authenticatorName haven't been specified,
     * and the user has provided their own custom Authenticator, return that one
     * 4. If the user hasn't provided a custom Authenticator, return IdmAuthenticator
     * and attempt to use the identity management API to authenticate
     *
     * @return
     */
    protected Authenticator lookupAuthenticator() throws AuthenticationException {
        if (authenticatorClass != null) {
            return authenticators.select(authenticatorClass).get();
        }

        if (!Strings.isEmpty(authenticatorName)) {
            Instance<Authenticator> selected = authenticators.select(new NamedLiteral(authenticatorName));
            if (selected.isAmbiguous()) {
                log.error("Multiple Authenticators found with configured name [" + authenticatorName + "]");
                return null;
            }

            if (selected.isUnsatisfied()) {
                log.error("No authenticator with name [" + authenticatorName + "] was found");
                return null;
            }

            return selected.get();
        }

        Authenticator selectedAuth = null;

        // Hack to workaround glassfish visibility issue
        BeanManager bm = new BeanManagerLocator().getBeanManager();

//    for (Authenticator auth : authenticators)
        for (Authenticator auth : getReferences(bm, Authenticator.class)) {
            // If the user has provided their own custom authenticator then use it -
            // a custom authenticator is one that isn't one of the known authenticators;
            // JaasAuthenticator, IdmAuthenticator, or any external authenticator, etc
            if (!JaasAuthenticator.class.isAssignableFrom(auth.getClass()) &&
                    !IdmAuthenticator.class.isAssignableFrom(auth.getClass()) &&
                    !isExternalAuthenticator(auth.getClass())) {
                selectedAuth = auth;
                break;
            }

            if (IdmAuthenticator.class.isAssignableFrom(auth.getClass())) {
                selectedAuth = auth;
            }
        }

        return selectedAuth;
    }


    private boolean isExternalAuthenticator(Class<? extends Authenticator> authClass) {
        Class<?> cls = authClass;

        while (cls != Object.class) {
            if (cls.getName().startsWith("org.jboss.seam.security.external.")) {
                return true;
            }
            cls = cls.getSuperclass();
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    private <T> Set<T> getReferences(final BeanManager manager, final Class<T> type, Annotation... qualifiers) {
        Set<Bean<?>> resolverBeans = manager.getBeans(type, qualifiers);
        if (resolverBeans.size() == 0) {
            return Collections.emptySet();
        }
        Set<T> refs = new LinkedHashSet<T>();
        for (Bean<?> bean : resolverBeans) {
            // FIXME when should the dependent context be cleaned up?
            CreationalContext<T> context = (CreationalContext<T>) manager.createCreationalContext(bean);
            if (context != null) {
                refs.add((T) manager.getReference(bean, type, context));
            }
        }
        return refs;
    }

    /**
     * Resets all security state and credentials
     */
    public void unAuthenticate() {
        user = null;
        credentials.clear();
        preAuthenticationRoles.clear();
        activeRoles.clear();
        preAuthenticationGroups.clear();
        activeGroups.clear();
    }

    public void logout() {
        if (isLoggedIn()) {
            PostLoggedOutEvent loggedOutEvent = new PostLoggedOutEvent(user);

            beanManager.fireEvent(new PreLoggedOutEvent());
            unAuthenticate();

            session.invalidate();

            beanManager.fireEvent(loggedOutEvent);
        }
    }

    public boolean hasRole(String roleType, String group, String groupType) {
        if (!securityEnabled) return true;
        if (systemOp != null && Boolean.TRUE.equals(systemOp.get())) return true;

        tryLogin();

        for (Role role : activeRoles) {
            if (role.getRoleType().getName().equals(roleType) &&
                    role.getGroup().getName().equals(group) &&
                    role.getGroup().getGroupType().equals(groupType)) {
                return true;
            }
        }

        return false;
    }

    public boolean addRole(String roleType, String group, String groupType) {
        if (roleType == null || "".equals(roleType) || group == null || "".equals(group)
                || groupType == null || "".equals(groupType)) return false;

        if (isLoggedIn()) {
            return activeRoles.add(new SimpleRole(new SimpleRoleType(roleType),
                    user, new SimpleGroup(group, groupType)));
        } else {
            List<String> roleTypes = null;

            Map<String, List<String>> groupTypes = preAuthenticationRoles.get(group);
            if (groupTypes != null) {
                roleTypes = groupTypes.get(groupType);
            } else {
                groupTypes = new HashMap<String, List<String>>();
                preAuthenticationRoles.put(group, groupTypes);
            }

            if (roleTypes == null) {
                roleTypes = new ArrayList<String>();
                groupTypes.put(groupType, roleTypes);
            }

            return roleTypes.add(roleType);
        }
    }

    public boolean inGroup(String name, String groupType) {
        for (Group group : activeGroups) {
            if (group.getName().equals(name) && group.getGroupType().equals(groupType)) return true;
        }

        return false;
    }

    public boolean addGroup(String name, String groupType) {
        if (name == null || "".equals(name) || groupType == null || "".equals(groupType)) {
            return false;
        }

        if (isLoggedIn()) {
            return activeGroups.add(new SimpleGroup(name, groupType));
        } else {
            List<String> groupTypes = null;
            if (preAuthenticationGroups.containsKey(name)) {
                groupTypes = preAuthenticationGroups.get(name);
            } else {
                groupTypes = new ArrayList<String>();
                preAuthenticationGroups.put(name, groupTypes);
            }

            return groupTypes.add(groupType);
        }
    }

    public void removeGroup(String name, String groupType) {
        for (Group group : activeGroups) {
            if (group.getName().equals(name) && group.getGroupType().equals(groupType)) {
                activeGroups.remove(group);
                return;
            }
        }
    }

    /**
     * Removes a role from the authenticated user
     *
     * @param role The name of the role to remove
     */
    public void removeRole(String roleType, String group, String groupType) {
        for (Role role : activeRoles) {
            if (role.getRoleType().getName().equals(roleType) &&
                    role.getGroup().getName().equals(group) &&
                    role.getGroup().getGroupType().equals(groupType)) {
                activeRoles.remove(role);
                return;
            }
        }
    }

    public void checkRole(String roleType, String group, String groupType) {
        tryLogin();

        if (!hasRole(roleType, group, groupType)) {
            if (!isLoggedIn()) {
                beanManager.fireEvent(new NotLoggedInEvent());
                throw new NotLoggedInException();
            } else {
                beanManager.fireEvent(new NotAuthorizedEvent());
                throw new AuthorizationException(String.format(
                        "Authorization check failed for role [%s:%s:%s]", roleType, group, groupType));
            }
        }
    }

    public void checkGroup(String group, String groupType) {
        tryLogin();

        if (!inGroup(group, groupType)) {
            if (!isLoggedIn()) {
                beanManager.fireEvent(new NotLoggedInEvent());
                throw new NotLoggedInException();
            } else {
                beanManager.fireEvent(new NotAuthorizedEvent());
                throw new AuthorizationException(String.format(
                        "Authorization check failed for group [%s:%s]", group, groupType));
            }
        }
    }

    public void checkPermission(Object target, String action) {
        if (systemOp != null && Boolean.TRUE.equals(systemOp.get())) return;

        tryLogin();

        if (!hasPermission(target, action)) {
            if (!isLoggedIn()) {
                beanManager.fireEvent(new NotLoggedInEvent());
                throw new NotLoggedInException();
            } else {
                beanManager.fireEvent(new NotAuthorizedEvent());
                throw new AuthorizationException(String.format(
                        "Authorization check failed for permission[%s,%s]", target, action));
            }
        }
    }

    public void filterByPermission(Collection<?> collection, String action) {
        permissionMapper.filterByPermission(collection, action);
    }

    public boolean hasPermission(Object target, String action) {
        if (!securityEnabled) return true;
        if (systemOp != null && Boolean.TRUE.equals(systemOp.get())) return true;
        if (permissionMapper == null) return false;
        if (target == null) return false;

        return permissionMapper.resolvePermission(target, action);
    }

    public synchronized void runAs(RunAsOperation operation) {
        User savedUser = getUser();

        if (systemOp == null) {
            systemOp = new ThreadLocal<Boolean>();
        }

        boolean savedSystemOp = systemOp.get();

        try {
            user = operation.getUser();

            systemOp.set(operation.isSystemOperation());

            operation.execute();
        } finally {
            systemOp.set(savedSystemOp);
            user = savedUser;
        }
    }

    public void checkRestriction(String expr) {
        // TODO Do we still need this method?

    }

    public User getUser() {
        return user;
    }

    public Set<Role> getRoles() {
        return Collections.unmodifiableSet(activeRoles);
    }

    public Set<Group> getGroups() {
        return Collections.unmodifiableSet(activeGroups);
    }

    public boolean isVerified() {
        // TODO Auto-generated method stub
        return false;
    }
}
TOP

Related Classes of org.jboss.seam.security.IdentityImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.