org.opentestsystem.delivery.testreg.service.impl.TestRegUserDetailsServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.delivery.testreg.service.impl.TestRegUserDetailsServiceImpl.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System
 * Copyright (c) 2013 American Institutes for Research
 *
 * Distributed under the AIR Open Source License, Version 1.0
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/
package org.opentestsystem.delivery.testreg.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.opentestsystem.delivery.testreg.domain.Accommodation;
import org.opentestsystem.delivery.testreg.domain.Assessment;
import org.opentestsystem.delivery.testreg.domain.EligibleStudent;
import org.opentestsystem.delivery.testreg.domain.ExplicitEligibility;
import org.opentestsystem.delivery.testreg.domain.FormatType;
import org.opentestsystem.delivery.testreg.domain.Sb11Entity;
import org.opentestsystem.delivery.testreg.domain.Sb11NonEntity;
import org.opentestsystem.delivery.testreg.domain.Sb11SuperEntity;
import org.opentestsystem.delivery.testreg.domain.Student;
import org.opentestsystem.delivery.testreg.domain.StudentGroup;
import org.opentestsystem.delivery.testreg.domain.TestRegPermission;
import org.opentestsystem.delivery.testreg.domain.TestRegistrationBase;
import org.opentestsystem.delivery.testreg.domain.User;
import org.opentestsystem.delivery.testreg.domain.amqp.StudentSecurity;
import org.opentestsystem.delivery.testreg.persistence.StudentRepository;
import org.opentestsystem.delivery.testreg.service.Sb11EntityRepositoryService;
import org.opentestsystem.delivery.testreg.service.TestRegUberEntityRelationshipService;
import org.opentestsystem.delivery.testreg.service.TestRegUserDetailsService;
import org.opentestsystem.shared.progman.client.domain.TenantType;
import org.opentestsystem.shared.security.domain.SbacRole;
import org.opentestsystem.shared.security.domain.SbacUser;
import org.opentestsystem.shared.security.domain.permission.SbacPermissionEntity;
import org.opentestsystem.shared.security.domain.permission.UserRole;
import org.opentestsystem.shared.security.integration.PermissionClient;
import org.opentestsystem.shared.security.service.UserDetailsServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.stereotype.Service;

@Service
public class TestRegUserDetailsServiceImpl extends UserDetailsServiceImpl implements TestRegUserDetailsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestRegUserDetailsServiceImpl.class);

    private static final String ROLE_TO_ENTITY_CACHENAME = "roleToEntityCache";

    @Value("${component.name:}")
    private String componentName;

    @Autowired
    private TestRegUberEntityRelationshipService testRegUberEntityRelationshipService;

    @Resource
    private Sb11EntityRepositoryService sb11EntityService;

    @Autowired
    private StudentRepository studentRepository;

    @Resource
    private CacheManager cacheManager;

    @Autowired
    private PermissionClient permissionClient;

    @Override
    public Object loadUserBySAML(final SAMLCredential samlCred) throws UsernameNotFoundException {
        return super.loadUserBySAML(samlCred);
    }

    @Override
    public boolean hasAccess(final Object obj, final TestRegPermission testRegPermission) {
        boolean userHasAccess = true;
        long start = System.currentTimeMillis();
        if (obj instanceof TestRegistrationBase) {
            userHasAccess = hasAccess((TestRegistrationBase) obj, testRegPermission);
            LOGGER.trace("hasAccess took: " + (System.currentTimeMillis() - start));
        }
        return userHasAccess;
    }

    @Override
    public Collection<SbacRole> getCurrentUserSbacRoles(final boolean includeNonEffectiveRoles) {
        Collection<SbacRole> currentUserSbacRoles = getCurrentUser().getRoles();
        if (includeNonEffectiveRoles) {
            currentUserSbacRoles.addAll(getCurrentUser().getNonEffectiveRoles());
        }
        return currentUserSbacRoles;
    }

    @Override
    public Set<String> getCurrentUserSbacRoleNamesThatAreProtected(final boolean includeNonEffectiveRoles) {
        Set<String> currentUserSbacRoleNamesThatAreProtected = new HashSet<>();
        for (SbacRole sbacRole : getCurrentUserSbacRoles(includeNonEffectiveRoles)) {
            if (sbacRole.isProtected()) {
                currentUserSbacRoleNamesThatAreProtected.add(sbacRole.getRoleName());
            }
        }
        return currentUserSbacRoleNamesThatAreProtected;
    }

    @Override
    public List<String> getProtectedUserRoleNamesThatTheCurrentUserDoesNotHave() {
        List<String> protectedUserRoleNamesThatTheCurrentUserDoesNotHave = new ArrayList<>();
        Set<String> currentUserSbacRoleNamesThatAreProtected = getCurrentUserSbacRoleNamesThatAreProtected(true);
        for (UserRole userRole : permissionClient.getRoles()) {
            if (userRole.isProtected() && !currentUserSbacRoleNamesThatAreProtected.contains(userRole.getRole())) {
                protectedUserRoleNamesThatTheCurrentUserDoesNotHave.add(userRole.getRole());
            }
        }
        return protectedUserRoleNamesThatTheCurrentUserDoesNotHave;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Set<String> getMongoIdsOfEntitiesCurrentUserHasAccessTo() {
        return getMongoIdsOfEntitiesCurrentUserHasAccessTo(null);
    }

    @Override
    public Set<String> getMongoIdsOfEntitiesCurrentUserHasAccessTo(StudentSecurity studentSecurity) {
        String userName;
        Collection<SbacRole> sbacRoles;
        if (studentSecurity == null) {
            SbacUser sbacUser = getCurrentUser();
            userName = sbacUser.getUsername();
            sbacRoles = sbacUser.getRoles();
        } else {
            userName = studentSecurity.getUserName();
            sbacRoles = studentSecurity.getSbacRoles();
        }

        long start = System.currentTimeMillis();
        LOGGER.trace("*********** looking up all entities that current user has access to ***********");
        Cache roleToEntityCache = cacheManager.getCache(ROLE_TO_ENTITY_CACHENAME);
        Set<String> mongoIdsOfEntitiesUserHasAccessTo = null;
        if (roleToEntityCache != null) {
            ValueWrapper cacheGet = roleToEntityCache.get(userName);
            if (cacheGet != null) {
                mongoIdsOfEntitiesUserHasAccessTo = (Set<String>) cacheGet.get();
            }
        }

        if (mongoIdsOfEntitiesUserHasAccessTo == null) {
            LOGGER.trace("********* entity to role map cache does not exist, rebuild **************");
            mongoIdsOfEntitiesUserHasAccessTo = buildEntityToRoleMapForUser(userName, sbacRoles);
            if (cacheManager.getCache(ROLE_TO_ENTITY_CACHENAME) != null) {
                cacheManager.getCache(ROLE_TO_ENTITY_CACHENAME).put(userName, mongoIdsOfEntitiesUserHasAccessTo);
            }
        }

        LOGGER.trace("********* entity to role map cache exists **************");
        LOGGER.trace("getMongoIdsOfEntitiesCurrentUserHasAccessTo took: " + (System.currentTimeMillis() - start));
        return mongoIdsOfEntitiesUserHasAccessTo;
    }

    private synchronized Set<String> buildEntityToRoleMapForUser(final String userName,
            Collection<SbacRole> sbacRoles) {

        // We need to check right at the beginning to make sure that the user cache doesn't exist
        // it may have been created by a different thread while another was waiting for the
        // synchronize lock. If the cache does exist for the user, send it back, otherwise create it.

        Cache roleToEntitiesCache = cacheManager.getCache(ROLE_TO_ENTITY_CACHENAME);
        Set<String> mongoIdsOfEntitiesUserHasAccessTo = null;

        if (roleToEntitiesCache != null) {
            ValueWrapper cacheGet = roleToEntitiesCache.get(userName);
            if (cacheGet != null) {
                mongoIdsOfEntitiesUserHasAccessTo = (Set<String>) cacheGet.get();
            }
        }

        if (mongoIdsOfEntitiesUserHasAccessTo == null) {
            mongoIdsOfEntitiesUserHasAccessTo = new HashSet<>();
            Map<String, Set<String>> uberMap = testRegUberEntityRelationshipService.getUberEntityRelationshipMap();
            for (SbacRole sbacRole : sbacRoles) {
                String effectiveEntityMongoId = convertRoleToEffectiveEntityMongoId(sbacRole);
                if (effectiveEntityMongoId == null) {
                    LOGGER.error("unable to determine effectiveEntityMongoId from role: " + sbacRole);
                } else if (!uberMap.containsKey(effectiveEntityMongoId)) {
                    LOGGER.error("the effectiveEntityMongoId (" + effectiveEntityMongoId
                            + ") for this role wasn't found in the uber entity relationship map!");
                } else {

                    // recursive approach
                    // addAllChildMongoIds(effectiveEntityMongoId, mongoIdsOfEntitiesUserHasAccessTo, uberMap);

                    // non-recursive alternative
                    mongoIdsOfEntitiesUserHasAccessTo
                            .addAll(findAllChildrenMongoIds(effectiveEntityMongoId, uberMap));

                }
            }
        }

        return mongoIdsOfEntitiesUserHasAccessTo;
    }

    // we need to traverse all children of children (recursively)...
    @Deprecated
    private Set<String> addAllChildMongoIds(final String parentMongoId, final Set<String> allChildMongoIds,
            final Map<String, Set<String>> uberMap) {
        allChildMongoIds.add(parentMongoId);
        if (uberMap.containsKey(parentMongoId)) {
            for (String childMongoId : uberMap.get(parentMongoId)) {
                addAllChildMongoIds(childMongoId, allChildMongoIds, uberMap);
            }
        } else {
            LOGGER.warn("unable to find this entity mongo id in the uber map: " + parentMongoId);
        }
        return allChildMongoIds;
    }

    private Set<String> findAllChildrenMongoIds(final String parentMongoId,
            final Map<String, Set<String>> uberMap) {
        Set<String> childrenAlreadyLookedUp = new HashSet<>();
        Set<String> allChildrenMongoIds = new HashSet<>();
        allChildrenMongoIds.add(parentMongoId);
        while (!childrenAlreadyLookedUp.equals(allChildrenMongoIds)) {
            Set<String> newChildrenMongoIds = new HashSet<>();
            for (String child : allChildrenMongoIds) {
                if (!childrenAlreadyLookedUp.contains(child)) {
                    childrenAlreadyLookedUp.add(child);
                    newChildrenMongoIds.addAll(findChildren(child, uberMap));
                }
            }
            allChildrenMongoIds.addAll(newChildrenMongoIds);
        }
        return allChildrenMongoIds;
    }

    private Set<String> findChildren(final String parentMongoId, final Map<String, Set<String>> uberMap) {
        Set<String> childrenMongoIds = new HashSet<>();
        childrenMongoIds.add(parentMongoId);
        if (uberMap.containsKey(parentMongoId)) {
            childrenMongoIds.addAll(uberMap.get(parentMongoId));
        } else {
            LOGGER.warn("unable to find this entity mongo id in the uber map: " + parentMongoId);
        }
        return childrenMongoIds;
    }

    // Unfortunately we need to do this to match the String that is held in the UserRole.entity
    private String convertTenantTypeIntoMatchableString(final TenantType tenantType) {
        if (tenantType == TenantType.CLIENT) {
            return FormatType.CLIENT.name();
        } else if (tenantType == TenantType.STATE_GROUP) {
            return FormatType.GROUPOFSTATES.name();
        } else if (tenantType == TenantType.STATE) {
            return FormatType.STATE.name();
        } else if (tenantType == TenantType.DISTRICT_GROUP) {
            return FormatType.GROUPOFDISTRICTS.name();
        } else if (tenantType == TenantType.DISTRICT) {
            return FormatType.DISTRICT.name();
        } else if (tenantType == TenantType.INSTITUTION_GROUP) {
            return FormatType.GROUPOFINSTITUTIONS.name();
        } else if (tenantType == TenantType.INSTITUTION) {
            return FormatType.INSTITUTION.name();
        } else {
            throw new RuntimeException("can't convert tenantType string: " + tenantType);
        }
    }

    @Override
    public List<UserRole> getAllUserRolesForCurrentUser() {

        List<UserRole> userRoles = permissionClient.getRoles();

        /*
         * Loop over all TenantType values (in order from CLIENT downward) looking for the highest level at which the
         * current user has any accessibility. And then once we find that, we consider the rest of the levels
         * accessible.
         */
        boolean foundTenantTypeLevel = false;
        Set<String> accessibleEntityTypesAsString = new HashSet<>();
        for (TenantType tenantType : TenantType.values()) {
            if (!foundTenantTypeLevel) {
                for (SbacRole sbacRole : getCurrentUserSbacRoles(false)) {
                    if (sbacRole.getEffectiveEntity().getEntityType() == tenantType) {
                        foundTenantTypeLevel = true;
                    }
                }
            }
            if (foundTenantTypeLevel) {
                accessibleEntityTypesAsString.add(convertTenantTypeIntoMatchableString(tenantType));
            }
        }

        /*
         * Loop over the roles to filter out the roles that contain at least 1 permission that isn't within the current
         * user's accessibility. The matching of this is based on the format of a String so we need to match it in a
         * non-straight forward way.
         */
        List<UserRole> accessibleUserRoles = new ArrayList<>();
        Set<String> accessibleProtectedRolesAsString = getCurrentUserSbacRoleNamesThatAreProtected(false);
        for (UserRole userRole : userRoles) {
            boolean foundAccessableEntity = false;
            List<SbacPermissionEntity> userRoleEntitys = new ArrayList<SbacPermissionEntity>();
            for (SbacPermissionEntity entity : userRole.getAllowableEntities()) {
                if (accessibleEntityTypesAsString.contains(entity.getEntity())) {
                    foundAccessableEntity = true;
                    userRoleEntitys.add(entity);
                }
            }
            userRole.setAllowableEntities(userRoleEntitys);
            if (foundAccessableEntity) {
                if (!userRole.isProtected() || (userRole.isProtected()
                        && accessibleProtectedRolesAsString.contains(userRole.getRole()))) {
                    accessibleUserRoles.add(userRole);
                }
            }
        }

        return accessibleUserRoles;
    }

    // ============================================================================================

    private boolean hasAccess(final TestRegistrationBase testRegistrationBase,
            final TestRegPermission testRegPermission) {
        LOGGER.trace("checking for access to " + testRegistrationBase.toString() + " id: "
                + testRegistrationBase.getId());
        if (testRegistrationBase instanceof Sb11Entity) {
            return hasAccess((Sb11Entity) testRegistrationBase, testRegPermission);
        } else if (testRegistrationBase instanceof Sb11NonEntity) {
            return hasAccess((Sb11NonEntity) testRegistrationBase, testRegPermission);
        } else {
            throw new RuntimeException(
                    "TestRegistrationBase object (not Sb11Entity nor Sb11NonEntity) wasn't able to be properly checked for permission: "
                            + testRegistrationBase);
        }
    }

    @SuppressWarnings("unchecked")
    private boolean hasAccess(final Sb11Entity entity, final TestRegPermission testRegPermission) {

        // if entity.getId() is null this means that the entity is new
        // to get a mongo id to check, we need to get the mongo id of the parent
        // using the mongo id of the direct parent should be good enough to determine
        // if this entity is correctly in the hierarchy

        String mongoId = entity.getId();
        if (mongoId == null) {
            Sb11Entity parentEntity = null;
            if (Sb11SuperEntity.class.isAssignableFrom(entity.getParentEntityType().getEntityClass())) {
                parentEntity = sb11EntityService.findByEntityId(entity.getParentEntityId(),
                        (Class<Sb11SuperEntity>) entity.getParentEntityType().getEntityClass());
            } else {
                parentEntity = sb11EntityService.findByEntityIdAndStateAbbreviation(entity.getParentEntityId(),
                        entity.getStateAbbreviation(), entity.getParentEntityType().getEntityClass());
            }
            if (parentEntity != null) {
                mongoId = parentEntity.getId();
            }
        }

        return currentUserHasAccessToSb11Entity(mongoId, testRegPermission);
    }

    private boolean hasAccess(final Sb11NonEntity entity, final TestRegPermission testRegPermission) {
        if (entity instanceof Assessment) {
            return hasAccess((Assessment) entity, testRegPermission);
        } else if (entity instanceof User) {
            return hasAccess((User) entity, testRegPermission);
        } else if (entity instanceof Student) {
            return hasAccess((Student) entity, testRegPermission);
        } else if (entity instanceof Accommodation) {
            return hasAccess((Accommodation) entity, testRegPermission);
        } else if (entity instanceof StudentGroup) {
            return hasAccess((StudentGroup) entity, testRegPermission);
        } else if (entity instanceof ExplicitEligibility) {
            return hasAccess((ExplicitEligibility) entity, testRegPermission);
        } else if (entity instanceof EligibleStudent) {
            return hasAccess((EligibleStudent) entity, testRegPermission);
        } else {
            new AccessDeniedException("Sb11NonEntity object not properly checked for permission: " + entity);
        }
        return false;
    }

    // =====================================================================================
    // =====================================================================================

    private boolean hasAccess(final Assessment entity, final TestRegPermission testRegPermission) {
        return getCurrentUser().hasPermissionForTenant(testRegPermission.toSpringRoleName(), entity.getTenantId());
    }

    private boolean hasAccess(final User user, final TestRegPermission testRegPermission) {
        Map<String, UserRole> rolesMap = permissionClient.getRolesMap();
        if (user != null && user.getRoleAssociations() != null && user.getRoleAssociations().size() > 0) {
            Set<String> currentUserProtectedRoles = getCurrentUserSbacRoleNamesThatAreProtected(false);
            for (User.RoleAssociation roleAssociation : user.getRoleAssociations()) {
                //put null check in place just in case user has a role that is no longer in permissions (rolesMap)
                if (roleAssociation.getRole() == null || rolesMap.get(roleAssociation.getRole()) == null) {
                    break;
                }
                String childEntityMongoId = roleAssociation.getAssociatedEntityMongoId();
                if (!currentUserHasAccessToSb11Entity(childEntityMongoId, testRegPermission)) {
                    return false;
                }
                if (rolesMap.get(roleAssociation.getRole()).isProtected()
                        && !currentUserProtectedRoles.contains(roleAssociation.getRole())) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean hasAccess(final Student entity, final TestRegPermission testRegPermission) {
        String districtId = entity.getDistrictEntityMongoId();
        String institutionId = entity.getInstitutionEntityMongoId();
        if (districtId != null && !currentUserHasAccessToSb11Entity(districtId, testRegPermission)) {
            return false;
        }
        if (institutionId != null && !currentUserHasAccessToSb11Entity(institutionId, testRegPermission)) {
            return false;
        }
        return true;
    }

    private boolean hasAccess(final Accommodation accommodation, final TestRegPermission testRegPermission) {
        Student student = studentRepository.findByEntityIdAndStateAbbreviation(accommodation.getStudentId(),
                accommodation.getStateAbbreviation());
        String districtId = student.getDistrictEntityMongoId();
        String institutionId = student.getInstitutionEntityMongoId();
        if (districtId != null && !currentUserHasAccessToSb11Entity(districtId, testRegPermission)) {
            return false;
        }
        if (institutionId != null && !currentUserHasAccessToSb11Entity(institutionId, testRegPermission)) {
            return false;
        }
        return true;
    }

    private boolean hasAccess(final StudentGroup studentGroup, final TestRegPermission testRegPermission) {
        String districtId = studentGroup.getDistrictEntityMongoId();
        String institutionId = studentGroup.getInstitutionEntityMongoId();
        if (districtId != null && !currentUserHasAccessToSb11Entity(districtId, testRegPermission)) {
            return false;
        }
        if (institutionId != null && !currentUserHasAccessToSb11Entity(institutionId, testRegPermission)) {
            return false;
        }
        return true;
    }

    private boolean hasAccess(final ExplicitEligibility explicitEligibility,
            final TestRegPermission testRegPermission) {
        String districtId = explicitEligibility.getResponsibleDistrictMongoId();
        if (districtId != null && !currentUserHasAccessToSb11Entity(districtId, testRegPermission)) {
            return false;
        }
        Student student = studentRepository.findByEntityIdAndStateAbbreviation(explicitEligibility.getStudentId(),
                explicitEligibility.getStateAbbreviation());
        return hasAccess(student, testRegPermission);
    }

    private boolean hasAccess(final EligibleStudent eligibleStudent, final TestRegPermission testRegPermission) {
        return hasAccess(eligibleStudent.getStudent(), testRegPermission);
    }

    // =====================================================================================
    // =====================================================================================

    private boolean currentUserHasAccessToSb11Entity(final String entityMongoIdOfChild,
            final TestRegPermission testRegPermission) {
        SbacUser currentUser = getCurrentUser();
        Map<String, Set<String>> uberMap = testRegUberEntityRelationshipService.getUberEntityRelationshipMap();
        for (SbacRole sbacRole : currentUser.getRoles()) {
            if (sbacRole.hasPermission(testRegPermission.getTitle(), componentName)) {
                // LOGGER.debug("checking if " + componentName + " role '" + sbacRole.getRole()
                // + "' has access to permission '" + testRegPermission.name() + "'");
                String effectiveMongoId = convertRoleToEffectiveEntityMongoId(sbacRole);
                if (effectiveMongoId != null && checkTree(uberMap, effectiveMongoId, entityMongoIdOfChild)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public String convertRoleToEffectiveEntityMongoId(final SbacRole sbacRole) {
        Sb11Entity entity = convertRoleToEffectiveEntity(sbacRole);
        String effectiveMongoId = entity != null ? entity.getId() : null;
        if (effectiveMongoId == null) {
            LOGGER.error("unable to map this role (" + sbacRole.getRoleName() + ") to any of our entities!!!");
        }
        return effectiveMongoId;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Sb11Entity convertRoleToEffectiveEntity(final SbacRole sbacRole) {

        // gather info about this role
        TenantType effectiveEntityType = sbacRole.getEffectiveEntity().getEntityType();
        String effectiveEntityId = sbacRole.getEffectiveEntity().getEntityId();
        String effectiveEntityName = sbacRole.getEffectiveEntity().getEntityName();

        Sb11Entity entity = null;
        if (effectiveEntityType == TenantType.CLIENT || effectiveEntityType == TenantType.STATE_GROUP
                || effectiveEntityType == TenantType.STATE) {
            // in this situation we don't need a state abbreviation, and can lookup the entity simply by ID
            entity = sb11EntityService.findByEntityId(effectiveEntityId, effectiveEntityType);
        } else {
            /*
             * ----------------------------------------------------------------------------------------------------------
             * There exists a corner situation where we enter this code here! The problem is that the sbacRole doesn't
             * hold enough info to deterministically find the effectiveEntity in some cases. If no STATE exists in the
             * chain we have to attempt a lookup by other means. We essentially need the state abbreviation to do the
             * entity lookup since it is part of the composite key. But if we find only a single entity matching the id
             * and name, we can by pass this problem.
             * --------------------------------------------------------------------
             * --------------------------------------
             */
            String stateAbbreviation = sbacRole.getState().getEntityId();
            if (StringUtils.isNotEmpty(stateAbbreviation)) {
                // we got a little lucky and the state exists in the chain, so we can grab the state entity's ID (which
                // is a state abbrev.)
                entity = sb11EntityService.findByEntityIdAndStateAbbreviation(effectiveEntityId, stateAbbreviation,
                        effectiveEntityType);
            } else {
                // here's the problem... since we don't have a state abbrev., we need to try harder to find one...
                List<? extends Sb11Entity> possibleEntities = sb11EntityService.findAllByEntityIdAndEntityName(
                        effectiveEntityId, effectiveEntityName,
                        (Class<Sb11Entity>) convertTenantTypeToFormatType(effectiveEntityType)
                                .getTestRegistrationBaseClass());
                if (possibleEntities.size() == 1) {
                    // we got REALLY lucky, there was only one, so we can return it...
                    entity = possibleEntities.get(0);
                } else if (possibleEntities.size() > 1) {
                    LOGGER.error("unable to map sbacRole to effectiveEntity: we found more than 1 entity of type "
                            + effectiveEntityType.name() + " with id '" + effectiveEntityId + "' and name '"
                            + effectiveEntityName + "'");
                }
            }
        }

        if (entity == null) {
            // do not throw a runtime exception here, just log as error
            // throwing the exception causes it to bubble up to the UI causing confusion
            LOGGER.error("Problem looking up entity associated with this SbacRole (a state abbrev. is required): "
                    + sbacRole);
        }

        return entity;
    }

    // check if check if this parent entity is actually a parent to this child entity
    private boolean checkTree(final Map<String, Set<String>> uberMap, final String entityMongoIdOfParent,
            final String entityMongoIdOfChild) {
        boolean returnValue = true;
        if (!entityMongoIdOfParent.equals(entityMongoIdOfChild)) {
            if (uberMap.containsKey(entityMongoIdOfParent)) {
                Set<String> children = findAllChildrenMongoIds(entityMongoIdOfParent, uberMap);
                return children.contains(entityMongoIdOfParent);
            } else {
                LOGGER.warn("Unable to lookup entityMongoId (not found in uber map): " + entityMongoIdOfParent);
            }
        }
        return returnValue;
    }

    @Override
    public SbacUser getCurrentUser() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return (auth == null) ? null : (SbacUser) auth.getPrincipal();
    }

    @Override
    @CacheEvict(value = "roleToEntityCache", allEntries = true)
    public void evictRoleToEntityCache() {
        LOGGER.debug("********* Role to Entity Cache for all users should now be evicted **************");
    }

    @Override
    @CacheEvict(value = "roleToEntityCache", key = "#userName")
    public void evictRoleToEntityCacheForUser(String userName) {
        LOGGER.debug("********* Role to Entity Cache for user should now be evicted **************");
    }

    @Override
    @CacheEvict(value = "accessibleUsersCache", allEntries = true)
    public void evictAccessibleUsersCache() {
        LOGGER.debug("********* Accessible Users Cache for all users should now be evicted **************");
    }

    @Override
    @CacheEvict(value = "accessibleUsersCache", key = "#userName")
    public void evictAccessibleUsersCacheForUser(String userName) {
        LOGGER.debug("********* Accessible Users Cache for user should now be evicted **************");
    }

    private FormatType convertTenantTypeToFormatType(final TenantType tenantType) {
        switch (tenantType) {
        case CLIENT:
            return FormatType.CLIENT;
        case DISTRICT:
            return FormatType.DISTRICT;
        case DISTRICT_GROUP:
            return FormatType.GROUPOFDISTRICTS;
        case INSTITUTION:
            return FormatType.INSTITUTION;
        case INSTITUTION_GROUP:
            return FormatType.GROUPOFINSTITUTIONS;
        case STATE:
            return FormatType.STATE;
        case STATE_GROUP:
            return FormatType.GROUPOFSTATES;
        default:
            return null;
        }
    }

    // TODO Replace with a real implementation when the whole app-to-app auth with users is figured out
    @Override
    public boolean isElevatedAccessUser() {

        if (getCurrentUser() == null) {
            return true;
        }

        return false;
    }
}