org.cgiar.ccafs.ap.security.APCustomRealm.java Source code

Java tutorial

Introduction

Here is the source code for org.cgiar.ccafs.ap.security.APCustomRealm.java

Source

/*****************************************************************
 * This file is part of CCAFS Planning and Reporting Platform.
 * CCAFS P&R 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.
 * CCAFS P&R 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 CCAFS P&R. If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************/

package org.cgiar.ccafs.ap.security;

import org.cgiar.ccafs.ap.config.APConstants;
import org.cgiar.ccafs.ap.data.manager.impl.LiaisonInstitutionManagerImpl;
import org.cgiar.ccafs.ap.data.model.LiaisonInstitution;
import org.cgiar.ccafs.security.authentication.Authenticator;
import org.cgiar.ccafs.security.data.manager.ProjectSpecificUserRoleManagerImpl;
import org.cgiar.ccafs.security.data.manager.UserManagerImpl;
import org.cgiar.ccafs.security.data.manager.UserRoleManagerImpl;
import org.cgiar.ccafs.security.data.model.ProjectUserRole;
import org.cgiar.ccafs.security.data.model.User;
import org.cgiar.ccafs.security.data.model.UserRole;
import org.cgiar.ccafs.utils.APConfig;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.name.Named;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Hernn David Carvajal
 * @author Hctor Fabio Tobn R. - CIAT/CCAFS
 */

public class APCustomRealm extends AuthorizingRealm {

    // Logger
    public static Logger LOG = LoggerFactory.getLogger(APCustomRealm.class);

    // Variables
    final AllowAllCredentialsMatcher credentialsMatcher = new AllowAllCredentialsMatcher();
    // private SimpleAuthorizationInfo authorizationInfo;
    private int userID;

    // Managers
    private UserManagerImpl userManager;
    private LiaisonInstitutionManagerImpl liaisonInstitutionManager;
    private UserRoleManagerImpl userRoleManager;
    private ProjectSpecificUserRoleManagerImpl projectSpecificUserRoleManager;
    private APConfig config;

    @Named("DB")
    Authenticator dbAuthenticator;

    @Named("LDAP")
    Authenticator ldapAuthenticator;
    Injector injector;

    @Inject
    public APCustomRealm(UserManagerImpl userManager, UserRoleManagerImpl userRoleManager,
            ProjectSpecificUserRoleManagerImpl projectSpecificUserRoleManager,
            @Named("DB") Authenticator dbAuthenticator, @Named("LDAP") Authenticator ldapAuthenticator,
            APConfig config, LiaisonInstitutionManagerImpl liaisonInstitutionManager) {
        super(new MemoryConstrainedCacheManager());
        this.userManager = userManager;
        this.userRoleManager = userRoleManager;
        this.projectSpecificUserRoleManager = projectSpecificUserRoleManager;
        this.dbAuthenticator = dbAuthenticator;
        this.ldapAuthenticator = ldapAuthenticator;
        this.liaisonInstitutionManager = liaisonInstitutionManager;
        injector = Guice.createInjector();
        this.config = config;
        this.setName("APCustomRealm");
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // identify account to log to
        UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
        final String username = userPassToken.getUsername();
        final String password = new String(userPassToken.getPassword());
        User user;
        boolean authenticated = false;

        // Get user info from db
        if (username.contains("@")) {
            user = userManager.getUserByEmail(username);
        } else {
            // if user is loggin with his username, we must attach the cgiar.org.
            user = userManager.getUserByUsername(username);
        }

        if (user == null) {
            LOG.info("doGetAuthenticationInfo() > No account found for user {}.", username);
            throw new UnknownAccountException();
        }

        if (!user.isActive()) {
            LOG.info("doGetAuthenticationInfo() > Account of user {} is NOT active.", username);
            throw new LockedAccountException();
        }

        if (user.isCcafsUser()) {
            authenticated = ldapAuthenticator.authenticate(user.getUsername(), password);
        } else {
            authenticated = dbAuthenticator.authenticate(user.getEmail(), password);
        }

        if (!authenticated) {
            throw new IncorrectCredentialsException();
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getId(), user.getPassword(),
                this.getName());
        return info;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        userID = (Integer) principals.getPrimaryPrincipal();
        List<UserRole> roles = userRoleManager.getUserRolesByUserID(String.valueOf(userID));
        List<Map<String, UserRole>> projectRoles = new ArrayList<>();
        List<Integer> liaisonInstitutionIDs = new ArrayList<>();

        if (roles.size() == 0) {
            roles.add(userRoleManager.getUserRole(8)); // Getting the Guest Role.
        }
        // Get the roles general to the platform
        for (UserRole role : roles) {
            authorizationInfo.addRole(role.getAcronym());
            switch (role.getId()) {
            case APConstants.ROLE_ADMIN:
                for (String permission : role.getPermissions()) {
                    authorizationInfo.addStringPermission(permission);
                }
                break;
            case APConstants.ROLE_FINANCING_PROJECT:
                for (String permission : role.getPermissions()) {
                    permission = permission.replace("projects:", "projects:*:");
                    authorizationInfo.addStringPermission(permission);
                }
                break;
            case APConstants.ROLE_MANAGEMENT_LIAISON:
            case APConstants.ROLE_COORDINATING_UNIT:
                projectRoles.add(userRoleManager.getManagementLiaisonProjects(userID));
                break;
            case APConstants.ROLE_PROJECT_LEADER:

                projectRoles.add(userRoleManager.getProjectLeaderProjects(userID));
                break;

            case APConstants.ROLE_EXTERNAL_EVALUATOR:

                projectRoles.add(userRoleManager.getProjectExternalEvaluator(userID));
                break;

            case APConstants.ROLE_PROGRAM_DIRECTOR_EVALUATOR:
                projectRoles.add(userRoleManager.getProjectProgramDirector(userID));
                break;

            case APConstants.ROLE_PROJECT_COORDINATOR:
                projectRoles.add(userRoleManager.getProjectCordinatorProjects(userID));
                break;
            case APConstants.ROLE_CONTACT_POINT:
                projectRoles.add(userRoleManager.getContactPointProjects(userID));
                liaisonInstitutionIDs.addAll(userRoleManager.getLiaisonInstitutionID(userID));
                break;

            case APConstants.ROLE_REGIONAL_PROGRAM_LEADER:
            case APConstants.ROLE_FLAGSHIP_PROGRAM_LEADER:
                liaisonInstitutionIDs.addAll(userRoleManager.getLiaisonInstitutionID(userID));

                for (Integer liaisonInstitutionID : liaisonInstitutionIDs) {
                    final LiaisonInstitution currentLiaisonInstitution = liaisonInstitutionManager
                            .getLiaisonInstitution(liaisonInstitutionID);
                    if (currentLiaisonInstitution.getIpProgram() == null) {
                        currentLiaisonInstitution.setIpProgram("1");
                    }
                    projectRoles.add(userRoleManager
                            .getProgramProjects(Integer.parseInt(currentLiaisonInstitution.getIpProgram())));
                }

                break;
            }
        }
        boolean addPermission = true;
        // Adding the permissions for each role exactly as they come from the database:
        for (UserRole role : roles) {
            for (String myPermission : role.getPermissions()) {
                addPermission = true;
                if (myPermission.startsWith("planning:projects:")) {
                    if ((config.isPlanningClosed() && !role.getId().equals(APConstants.ROLE_ADMIN))) {
                        addPermission = false;
                    }
                }
                if (myPermission.startsWith("reporting:projects:")) {
                    if ((config.isReportingClosed() && !role.getId().equals(APConstants.ROLE_ADMIN))) {
                        addPermission = false;
                    }
                }
                if (addPermission) {
                    authorizationInfo.addStringPermission(myPermission);
                }
            }
        }
        // Converting those general roles into specific for the PROJECTS where they are able to edit.
        for (Map<String, UserRole> mapRoles : projectRoles) {
            for (Map.Entry<String, UserRole> entry : mapRoles.entrySet()) {
                String projectID = entry.getKey();
                UserRole role = entry.getValue();

                for (String permission : role.getPermissions()) {

                    // Add the project identifier to the permission only if the permission is not at project level.
                    // The following permission will be ignored: planning:projects:5:description:update
                    // if (!permission.matches("((?:project:[\0-9]{1,10}:)")) {
                    if (permission.contains(":projects:")) {
                        permission = permission.replace("projects:", "projects:" + projectID + ":");

                    }

                    addPermission = true;
                    if (permission.startsWith("planning:projects:")) {
                        if ((config.isPlanningClosed() && !role.getId().equals(APConstants.ROLE_ADMIN))) {
                            addPermission = false;
                        }
                    }

                    if (permission.startsWith("reporting:projects:")) {
                        if ((config.isReportingClosed() && !role.getId().equals(APConstants.ROLE_ADMIN))) {
                            addPermission = false;
                        }
                    }

                    if (addPermission) {
                        authorizationInfo.addStringPermission(permission);
                    }
                    // }
                }
            }
        }
        if (authorizationInfo.getStringPermissions() != null) {
            // Converting those general roles into specific for the SYNTHESIS where they are able to edit.
            List<String> newPermissions = new ArrayList<>();
            for (String permission : authorizationInfo.getStringPermissions()) {
                for (int liaisonInstitutionID : liaisonInstitutionIDs) {
                    if (permission.startsWith("reporting:synthesis:")) {
                        newPermissions
                                .add(permission.replace("synthesis:", "synthesis:" + liaisonInstitutionID + ":"));
                    }
                }
            }
            authorizationInfo.addStringPermissions(newPermissions);
        }

        if (!config.isClosed()) {
            // Getting the specific roles based on the table project_roles.
            List<ProjectUserRole> projectSpecificUserRoles = projectSpecificUserRoleManager
                    .getProjectSpecificUserRoles(userID);
            // Adding the specific project roles to the user.
            for (ProjectUserRole projectUserRole : projectSpecificUserRoles) {
                for (String permission : projectUserRole.getUserRole().getPermissions()) {
                    if (permission.contains(":projects:")) {
                        permission = permission.replace("projects:",
                                "projects:" + projectUserRole.getProjectID() + ":");
                    }
                    authorizationInfo.addStringPermission(permission);
                }
            }
        }
        return authorizationInfo;
    }

    @Override
    public CredentialsMatcher getCredentialsMatcher() {
        return credentialsMatcher;
    }
}