org.openiot.security.client.AccessControlUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.openiot.security.client.AccessControlUtil.java

Source

/**
 * Copyright (c) 2011-2014, OpenIoT
 *
 * This library is free software; you can redistribute it and/or
 * modify it either under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * (the "LGPL"). If you do not alter this
 * notice, a recipient may use your version of this file under the LGPL.
 *
 * You should have received a copy of the LGPL along with this library
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 * OF ANY KIND, either express or implied. See the LGPL  for
 * the specific language governing rights and limitations.
 *
 * Contact: OpenIoT mailto: info@openiot.eu
 */

package org.openiot.security.client;

import io.buji.pac4j.ClientRealm;
import io.buji.pac4j.ShiroWebContext;

import java.io.IOException;
import java.util.Collection;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.mgt.CachingSecurityManager;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.pac4j.core.exception.RequiresHttpAction;
import org.pac4j.oauth.client.BaseOAuth20Client;
import org.pac4j.oauth.client.CasOAuthWrapperClient;
import org.pac4j.oauth.profile.casoauthwrapper.CasOAuthWrapperProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Mehdi Riahi
 * 
 */
public abstract class AccessControlUtil {

    private static Logger logger = LoggerFactory.getLogger(AccessControlUtil.class);

    private static AccessControlUtilWeb instanceWeb;
    private static AccessControlUtilRest instanceRest;

    private ClientRealm clientRealm;

    private BaseOAuth20Client<?> client;

    private AuthorizationManager authorizationManager;

    /**
     * Returns a singleton instance of this class for web applications.
     * 
     * @return
     */
    public static AccessControlUtil getInstance() {
        if (instanceWeb == null)
            instanceWeb = new AccessControlUtilWeb();
        return instanceWeb;
    }

    /**
     * Returns a singleton instance of this class for RESTful applications.
     * 
     * @return
     */
    public static AccessControlUtil getRestInstance() {
        if (instanceRest == null)
            instanceRest = new AccessControlUtilRest();
        return instanceRest;
    }

    /**
     * Returns a singleton instance of this class for RESTful applications.
     * 
     * @param moduleName
     * @return
     */
    public static AccessControlUtil getRestInstance(String moduleName) {
        if (instanceRest == null)
            instanceRest = new AccessControlUtilRest(moduleName);
        return instanceRest;
    }

    /**
     * Returns a singleton instance of this class for RESTful applications.
     * 
     * @param moduleName
     * @param configDir
     *            The directory in which the config file is located
     * @return
     */
    public static AccessControlUtil getRestInstance(String moduleName, String configDir) {
        if (instanceRest == null)
            instanceRest = new AccessControlUtilRest(moduleName);
        return instanceRest;
    }

    /**
     * Authenticated the user and obtains a token. Should be used only for the REST client.
     * 
     * @param username
     * @param password
     * @return an OAuthorizationCredentials object containing the token or null in case of failure
     */
    public abstract OAuthorizationCredentials login(String username, String password);

    /**
     * Logs the user out and sends a request to delete the token. Should be used only for the REST
     * client.
     */
    public abstract void logout();

    /**
     * This method can be called by a servlet container to redirect the user to OpenIoT CAS login
     * page.
     * 
     * @param req
     * @param resp
     * @throws IOException
     */
    public abstract void redirectToLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException;

    /**
     * @param perm
     * @return true if the user has the specified permission
     */
    public boolean hasPermission(String perm) {
        return hasPermission(perm, getOAuthorizationCredentials());
    }

    /**
     * @param permStr
     * @param credentials
     * @return true if the user with the provided <code>credentials</code> has the specified
     *         permission.
     */
    public boolean hasPermission(String permStr, OAuthorizationCredentials credentials) {
        return getAuthorizationManager().hasPermission(permStr, credentials);
    }

    /**
     * @param permStr
     * @param targetClientId
     * @param credentials
     * @return true if the user with the provided <code>credentials</code> has the specified
     *         permission on service <code>targetClientId</code>
     */
    public boolean hasPermission(String permStr, String targetClientId, OAuthorizationCredentials credentials) {
        return getAuthorizationManager().hasPermission(permStr, targetClientId, credentials);
    }

    /**
     * @param role
     * @return true if the user has the specified role
     */
    public boolean hasRole(String role) {
        return hasRole(role, getOAuthorizationCredentials());
    }

    /**
     * @param role
     * @param credentials
     * @return true if the user with the provided <code>credentials</code> has the specified role.
     */
    public boolean hasRole(String role, OAuthorizationCredentials credentials) {
        return getAuthorizationManager().hasRole(role, credentials);
    }

    /**
     * @param role
     * @param targetClientId
     * @param credentials
     * @return true if the user with the provided <code>credentials</code> has the specified role on
     *         service <code>targetClientId</code>
     */
    public boolean hasRole(String role, String targetClientId, OAuthorizationCredentials credentials) {
        return getAuthorizationManager().hasRole(role, targetClientId, credentials);
    }

    /**
     * Sends a request to the server to check if the token is expired.
     * 
     * @param credentials
     * @return the expired token or <code>null</code> if non of the tokens in
     *         <code>credentials</code> are expired
     */
    public String getExpiredAccessToken(OAuthorizationCredentials credentials) {
        return getAuthorizationManager().getExpiredAccessToken(credentials);
    }

    /**
     * Clears the state information.
     */
    public void reset() {
        try {
            Subject subject = SecurityUtils.getSubject();
            if (subject.isAuthenticated())
                getAuthorizationManager().clearCache(subject.getPrincipals());
        } catch (UnavailableSecurityManagerException e) {
            logger.error("Error while reseting the cache", e);
        }
    }

    public AuthorizationManager getAuthorizationManager() {
        if (authorizationManager == null) {
            ACRealm acRealm = (ACRealm) getCasOAuthClientRealm();
            authorizationManager = new AuthorizationManager();
            authorizationManager.setClient(getClient());
            authorizationManager.setPermissionsURL(acRealm.getPermissionsURL());
            authorizationManager.setCacheManager(
                    ((CachingSecurityManager) SecurityUtils.getSecurityManager()).getCacheManager());
            acRealm.addClearCacheListener(authorizationManager);
        }
        return authorizationManager;
    }

    /**
     * @return an OAuthorizationCredentials object containing the user's token and the clientId if
     *         the user has logged in, otherwise returns <code>null</code>
     */
    public OAuthorizationCredentials getOAuthorizationCredentials() {
        final Subject subject = SecurityUtils.getSubject();
        if (!subject.isAuthenticated())
            return null;
        final CasOAuthWrapperProfile profile = subject.getPrincipals().oneByType(CasOAuthWrapperProfile.class);
        String accessToken = profile.getAccessToken();
        String clientId = getClient().getKey();
        String userId = profile.getId();
        return new OAuthorizationCredentials(userId, accessToken, clientId, null);
    }

    protected ClientRealm getCasOAuthClientRealm() {
        if (clientRealm == null) {
            SecurityManager securityManager = SecurityUtils.getSecurityManager();
            logger.debug("Security manager class :{} ", securityManager.getClass());
            RealmSecurityManager realmSecurityManager = (RealmSecurityManager) securityManager;
            Collection<Realm> realms = realmSecurityManager.getRealms();
            for (Realm realm : realms)
                if (realm instanceof ClientRealm) {
                    logger.debug("A realm of type {} was found", realm.getClass().getName());
                    clientRealm = (ClientRealm) realm;
                    break;
                }

        }
        return clientRealm;
    }

    public BaseOAuth20Client<?> getClient() {
        if (client == null) {
            client = (BaseOAuth20Client<?>) getCasOAuthClientRealm().getClients().findAllClients().get(0);
            logger.debug("Client is of type {}", client.getClass().getName());
        }

        return client;
    }

    private static class AccessControlUtilWeb extends AccessControlUtil implements SessionListener {

        public AccessControlUtilWeb() {
            DefaultSessionManager sessionManager = (DefaultSessionManager) ((SessionsSecurityManager) SecurityUtils
                    .getSecurityManager()).getSessionManager();
            sessionManager.getSessionListeners().add(this);
        }

        @Override
        public OAuthorizationCredentials login(String username, String password) {
            return null;
        }

        @Override
        public void logout() {
            // Do nothing
        }

        public void redirectToLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            try {
                String url = getLoginUrl(req, resp);
                logger.debug("redirecting to loginUrl: {} ", url);

                WebUtils.saveRequest(req);
                WebUtils.issueRedirect(req, resp, url);
            } catch (RequiresHttpAction e) {
                logger.debug("redurecting to loginUrl failed", e);
            }
        }

        public String getLoginUrl(HttpServletRequest req, HttpServletResponse resp) throws RequiresHttpAction {
            return getClient().getRedirectionUrl(new ShiroWebContext(req, resp), true);
        }

        @Override
        public void onStart(Session session) {
            resetCache(session);
        }

        @Override
        public void onStop(Session session) {
            // Do Nothing
        }

        @Override
        public void onExpiration(Session session) {
            resetCache(session);
        }

        private void resetCache(Session session) {
            Session subjectSession = SecurityUtils.getSubject().getSession(false);
            if (subjectSession != null && session.getId().equals(subjectSession.getId()))
                reset();
        }

    }
}