org.sonatype.security.DefaultSecuritySystem.java Source code

Java tutorial

Introduction

Here is the source code for org.sonatype.security.DefaultSecuritySystem.java

Source

/*
 * Sonatype Nexus (TM) Open Source Version
 * Copyright (c) 2008-2015 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
 *
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
 * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
 * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
 * Eclipse Foundation. All other trademarks are the property of their respective owners.
 */

package org.sonatype.security;

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

import javax.annotation.Nullable;
import javax.enterprise.inject.Typed;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.sonatype.configuration.validation.InvalidConfigurationException;
import org.sonatype.nexus.common.text.Strings2;
import org.sonatype.security.authentication.AuthenticationException;
import org.sonatype.security.authorization.AuthorizationException;
import org.sonatype.security.authorization.AuthorizationManager;
import org.sonatype.security.authorization.NoSuchAuthorizationManagerException;
import org.sonatype.security.authorization.Privilege;
import org.sonatype.security.authorization.Role;
import org.sonatype.security.configuration.SecurityConfigurationManager;
import org.sonatype.security.events.AuthorizationConfigurationChanged;
import org.sonatype.security.events.SecurityConfigurationChanged;
import org.sonatype.security.events.UserPrincipalsExpired;
import org.sonatype.security.usermanagement.InvalidCredentialsException;
import org.sonatype.security.usermanagement.NoSuchUserManagerException;
import org.sonatype.security.usermanagement.RoleIdentifier;
import org.sonatype.security.usermanagement.RoleMappingUserManager;
import org.sonatype.security.usermanagement.User;
import org.sonatype.security.usermanagement.UserManager;
import org.sonatype.security.usermanagement.UserNotFoundException;
import org.sonatype.security.usermanagement.UserSearchCriteria;
import org.sonatype.security.usermanagement.UserStatus;
import org.sonatype.sisu.goodies.common.ComponentSupport;
import org.sonatype.sisu.goodies.eventbus.EventBus;

import com.google.common.collect.Lists;
import com.google.common.eventbus.Subscribe;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * This implementation wraps a Shiro SecurityManager, and adds user management.
 */
@Singleton
@Typed(SecuritySystem.class)
@Named("default")
public class DefaultSecuritySystem extends ComponentSupport implements SecuritySystem {
    private SecurityConfigurationManager securityConfiguration;

    private RealmSecurityManager securityManager;

    private CacheManager cacheManager;

    private Map<String, UserManager> userManagers;

    private Map<String, Realm> realmMap;

    private Map<String, AuthorizationManager> authorizationManagers;

    private EventBus eventBus;

    private static final String ALL_ROLES_KEY = "all";

    private volatile boolean started;

    @Inject
    public DefaultSecuritySystem(final EventBus eventBus,
            final Map<String, AuthorizationManager> authorizationManagers, final Map<String, Realm> realmMap,
            final SecurityConfigurationManager securityConfiguration, final RealmSecurityManager securityManager,
            final CacheManager cacheManager, final Map<String, UserManager> userManagers) {
        this.eventBus = eventBus;
        this.authorizationManagers = authorizationManagers;
        this.realmMap = realmMap;
        this.securityConfiguration = securityConfiguration;
        this.securityManager = securityManager;
        this.cacheManager = cacheManager;

        this.eventBus.register(this);
        this.userManagers = userManagers;
        SecurityUtils.setSecurityManager(this.getSecurityManager());
        started = false;
    }

    public Subject login(AuthenticationToken token) throws AuthenticationException {
        try {
            Subject subject = this.getSubject();
            subject.login(token);
            return subject;
        } catch (org.apache.shiro.authc.AuthenticationException e) {
            throw new AuthenticationException(e.getMessage(), e);
        }
    }

    public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
        try {
            return this.getSecurityManager().authenticate(token);
        } catch (org.apache.shiro.authc.AuthenticationException e) {
            throw new AuthenticationException(e.getMessage(), e);
        }
    }

    // public Subject runAs( PrincipalCollection principal )
    // {
    // // TODO: we might need to bind this to the ThreadContext for this thread
    // // however if we do this we would need to unbind it so it doesn't leak
    // DelegatingSubject fakeLoggedInSubject = new DelegatingSubject( principal, true, null, null,
    // this.getApplicationSecurityManager() );
    //
    // // fake the login
    // ThreadContext.bind( fakeLoggedInSubject );
    // // this is un-bind when the user logs out.
    //
    // return fakeLoggedInSubject;
    // }

    public Subject getSubject() {
        // this gets the currently bound Subject to the thread
        return SecurityUtils.getSubject();
    }

    public void logout(Subject subject) {
        subject.logout();
    }

    public boolean isPermitted(PrincipalCollection principal, String permission) {
        return this.getSecurityManager().isPermitted(principal, permission);
    }

    public boolean[] isPermitted(PrincipalCollection principal, List<String> permissions) {
        return this.getSecurityManager().isPermitted(principal,
                permissions.toArray(new String[permissions.size()]));
    }

    public void checkPermission(PrincipalCollection principal, String permission) throws AuthorizationException {
        try {
            this.getSecurityManager().checkPermission(principal, permission);
        } catch (org.apache.shiro.authz.AuthorizationException e) {
            throw new AuthorizationException(e.getMessage(), e);
        }

    }

    public void checkPermission(PrincipalCollection principal, List<String> permissions)
            throws AuthorizationException {
        try {
            this.getSecurityManager().checkPermissions(principal,
                    permissions.toArray(new String[permissions.size()]));
        } catch (org.apache.shiro.authz.AuthorizationException e) {
            throw new AuthorizationException(e.getMessage(), e);
        }
    }

    public boolean hasRole(PrincipalCollection principals, String string) {
        return this.getSecurityManager().hasRole(principals, string);
    }

    private Collection<Realm> getRealmsFromConfigSource() {
        List<Realm> realms = new ArrayList<Realm>();

        List<String> realmIds = this.securityConfiguration.getRealms();

        for (String realmId : realmIds) {
            if (this.realmMap.containsKey(realmId)) {
                realms.add(this.realmMap.get(realmId));
            } else {
                log.debug("Failed to look up realm as a component, trying reflection");
                // If that fails, will simply use reflection to load
                try {
                    realms.add((Realm) getClass().getClassLoader().loadClass(realmId).newInstance());
                } catch (Exception e) {
                    log.error("Unable to lookup security realms", e);
                }
            }
        }

        return realms;
    }

    public Set<Role> listRoles() {
        Set<Role> roles = new HashSet<Role>();
        for (AuthorizationManager authzManager : this.authorizationManagers.values()) {
            Set<Role> tmpRoles = authzManager.listRoles();
            if (tmpRoles != null) {
                roles.addAll(tmpRoles);
            }
        }

        return roles;
    }

    public Set<Role> listRoles(String sourceId) throws NoSuchAuthorizationManagerException {
        if (ALL_ROLES_KEY.equalsIgnoreCase(sourceId)) {
            return this.listRoles();
        } else {
            AuthorizationManager authzManager = this.getAuthorizationManager(sourceId);
            return authzManager.listRoles();
        }
    }

    public Set<Privilege> listPrivileges() {
        Set<Privilege> privileges = new HashSet<Privilege>();
        for (AuthorizationManager authzManager : this.authorizationManagers.values()) {
            Set<Privilege> tmpPrivileges = authzManager.listPrivileges();
            if (tmpPrivileges != null) {
                privileges.addAll(tmpPrivileges);
            }
        }

        return privileges;
    }

    // *********************
    // * user management
    // *********************

    public User addUser(User user, String password)
            throws NoSuchUserManagerException, InvalidConfigurationException {
        // first save the user
        // this is the UserManager that owns the user
        UserManager userManager = getUserManager(user.getSource());

        if (!userManager.supportsWrite()) {
            throw new InvalidConfigurationException(
                    "UserManager: " + userManager.getSource() + " does not support writing.");
        }

        userManager.addUser(user, password);

        // then save the users Roles
        for (UserManager tmpUserManager : getUserManagers()) {
            // skip the user manager that owns the user, we already did that
            // these user managers will only save roles
            if (!tmpUserManager.getSource().equals(user.getSource())
                    && RoleMappingUserManager.class.isInstance(tmpUserManager)) {
                try {
                    RoleMappingUserManager roleMappingUserManager = (RoleMappingUserManager) tmpUserManager;
                    roleMappingUserManager.setUsersRoles(user.getUserId(), user.getSource(),
                            RoleIdentifier.getRoleIdentifiersForSource(user.getSource(), user.getRoles()));
                } catch (UserNotFoundException e) {
                    log.debug("User '" + user.getUserId() + "' is not managed by the usermanager: "
                            + tmpUserManager.getSource());
                }
            }
        }

        return user;
    }

    public User updateUser(User user)
            throws UserNotFoundException, NoSuchUserManagerException, InvalidConfigurationException {
        // first update the user
        // this is the UserManager that owns the user
        UserManager userManager = getUserManager(user.getSource());

        if (!userManager.supportsWrite()) {
            throw new InvalidConfigurationException(
                    "UserManager: " + userManager.getSource() + " does not support writing.");
        }

        final User oldUser = userManager.getUser(user.getUserId());
        userManager.updateUser(user);
        if (oldUser.getStatus() == UserStatus.active && user.getStatus() != oldUser.getStatus()) {
            // clear the realm authc caches as user got disabled
            eventBus.post(new UserPrincipalsExpired(user.getUserId(), user.getSource()));
        }

        // then save the users Roles
        for (UserManager tmpUserManager : getUserManagers()) {
            // skip the user manager that owns the user, we already did that
            // these user managers will only save roles
            if (!tmpUserManager.getSource().equals(user.getSource())
                    && RoleMappingUserManager.class.isInstance(tmpUserManager)) {
                try {
                    RoleMappingUserManager roleMappingUserManager = (RoleMappingUserManager) tmpUserManager;
                    roleMappingUserManager.setUsersRoles(user.getUserId(), user.getSource(),
                            RoleIdentifier.getRoleIdentifiersForSource(user.getSource(), user.getRoles()));
                } catch (UserNotFoundException e) {
                    log.debug("User '" + user.getUserId() + "' is not managed by the usermanager: "
                            + tmpUserManager.getSource());
                }
            }
        }

        // clear the realm authz caches as user might get roles changed
        eventBus.post(new AuthorizationConfigurationChanged());

        return user;
    }

    public void deleteUser(String userId) throws UserNotFoundException {
        User user = this.getUser(userId);
        try {
            this.deleteUser(userId, user.getSource());
        } catch (NoSuchUserManagerException e) {
            log.error("User manager returned user, but could not be found: " + e.getMessage(), e);
            throw new IllegalStateException("User manager returned user, but could not be found: " + e.getMessage(),
                    e);
        }
    }

    public void deleteUser(String userId, String source) throws UserNotFoundException, NoSuchUserManagerException {
        checkNotNull(userId, "User ID may not be null");

        Subject subject = getSubject();
        if (subject != null && subject.getPrincipal() != null && userId.equals(subject.getPrincipal().toString())) {
            throw new IllegalArgumentException("The user with user ID [" + userId
                    + "] cannot be deleted, as that is the user currently logged into the application.");
        }

        if (isAnonymousAccessEnabled() && userId.equals(getAnonymousUsername())) {
            throw new IllegalArgumentException("The user with user ID [" + userId
                    + "] cannot be deleted, since it is marked user used for Anonymous access in Server Administration. "
                    + "To delete this user, disable anonymous access or, "
                    + "change the anonymous username and password to another valid values!");
        }

        UserManager userManager = getUserManager(source);
        userManager.deleteUser(userId);

        // flush authc
        eventBus.post(new UserPrincipalsExpired(userId, source));
    }

    public Set<RoleIdentifier> getUsersRoles(String userId, String source)
            throws UserNotFoundException, NoSuchUserManagerException {
        User user = this.getUser(userId, source);
        return user.getRoles();
    }

    public void setUsersRoles(String userId, String source, Set<RoleIdentifier> roleIdentifiers)
            throws InvalidConfigurationException, UserNotFoundException {
        // TODO: this is a bit sticky, what we really want to do is just expose the RoleMappingUserManagers this way (i
        // think), maybe this is too generic

        boolean foundUser = false;

        for (UserManager tmpUserManager : getUserManagers()) {
            if (RoleMappingUserManager.class.isInstance(tmpUserManager)) {
                RoleMappingUserManager roleMappingUserManager = (RoleMappingUserManager) tmpUserManager;
                try {
                    foundUser = true;
                    roleMappingUserManager.setUsersRoles(userId, source, RoleIdentifier
                            .getRoleIdentifiersForSource(tmpUserManager.getSource(), roleIdentifiers));
                } catch (UserNotFoundException e) {
                    log.debug("User '" + userId + "' is not managed by the usermanager: "
                            + tmpUserManager.getSource());
                }
            }
        }

        if (!foundUser) {
            throw new UserNotFoundException(userId);
        }
        // clear the authz realm caches
        eventBus.post(new AuthorizationConfigurationChanged());
    }

    private User findUser(String userId, UserManager userManager) throws UserNotFoundException {
        log.trace("Finding user: {} in user-manager: {}", userId, userManager);

        User user = userManager.getUser(userId);
        if (user == null) {
            throw new UserNotFoundException(userId);
        }
        log.trace("Found user: {}", user);

        // add roles from other user managers
        this.addOtherRolesToUser(user);

        return user;
    }

    public User getUser(String userId) throws UserNotFoundException {
        log.trace("Finding user: {}", userId);

        for (UserManager userManager : orderUserManagers()) {
            try {
                return findUser(userId, userManager);
            } catch (UserNotFoundException e) {
                log.trace("User: '{}' was not found in: '{}'", userId, userManager, e);
            }
        }

        log.trace("User not found: {}", userId);
        throw new UserNotFoundException(userId);
    }

    public User getUser(String userId, String source) throws UserNotFoundException, NoSuchUserManagerException {
        log.trace("Finding user: {} in source: {}", userId, source);

        UserManager userManager = getUserManager(source);
        return findUser(userId, userManager);
    }

    public Set<User> listUsers() {
        Set<User> users = new HashSet<User>();

        for (UserManager tmpUserManager : getUserManagers()) {
            users.addAll(tmpUserManager.listUsers());
        }

        // now add all the roles to the users
        for (User user : users) {
            // add roles from other user managers
            this.addOtherRolesToUser(user);
        }

        return users;
    }

    public Set<User> searchUsers(UserSearchCriteria criteria) {
        Set<User> users = new HashSet<User>();

        // if the source is not set search all realms.
        if (Strings2.isEmpty(criteria.getSource())) {
            // search all user managers
            for (UserManager tmpUserManager : getUserManagers()) {
                Set<User> result = tmpUserManager.searchUsers(criteria);
                if (result != null) {
                    users.addAll(result);
                }
            }
        } else {
            try {
                users.addAll(getUserManager(criteria.getSource()).searchUsers(criteria));
            } catch (NoSuchUserManagerException e) {
                log.warn("UserManager: " + criteria.getSource() + " was not found.", e);
            }
        }

        // now add all the roles to the users
        for (User user : users) {
            // add roles from other user managers
            this.addOtherRolesToUser(user);
        }

        return users;
    }

    /**
     * We need to order the UserManagers the same way as the Realms are ordered. We need to be able to find a user
     * based
     * on the ID. This my never go away, but the current reason why we need it is:
     * https://issues.apache.org/jira/browse/KI-77 There is no (clean) way to resolve a realms roles into permissions.
     * take a look at the issue and VOTE!
     *
     * @return the list of UserManagers in the order (as close as possible) to the list of realms.
     */
    private List<UserManager> orderUserManagers() {
        List<UserManager> orderedLocators = new ArrayList<UserManager>();

        List<UserManager> unOrderdLocators = new ArrayList<UserManager>(getUserManagers());

        Map<String, UserManager> realmToUserManagerMap = new HashMap<String, UserManager>();

        for (UserManager userManager : getUserManagers()) {
            if (userManager.getAuthenticationRealmName() != null) {
                realmToUserManagerMap.put(userManager.getAuthenticationRealmName(), userManager);
            }
        }

        // get the sorted order of realms from the realm locator
        Collection<Realm> realms = this.getSecurityManager().getRealms();

        for (Realm realm : realms) {
            // now user the realm.name to find the UserManager
            if (realmToUserManagerMap.containsKey(realm.getName())) {
                UserManager userManager = realmToUserManagerMap.get(realm.getName());
                // remove from unorderd and add to orderd
                unOrderdLocators.remove(userManager);
                orderedLocators.add(userManager);
            }
        }

        // now add all the un-ordered ones to the ordered ones, this way they will be at the end of the ordered list
        orderedLocators.addAll(unOrderdLocators);

        return orderedLocators;
    }

    private void addOtherRolesToUser(User user) {
        // then save the users Roles
        for (UserManager tmpUserManager : getUserManagers()) {
            // skip the user manager that owns the user, we already did that
            // these user managers will only have roles
            if (!tmpUserManager.getSource().equals(user.getSource())
                    && RoleMappingUserManager.class.isInstance(tmpUserManager)) {
                try {
                    RoleMappingUserManager roleMappingUserManager = (RoleMappingUserManager) tmpUserManager;
                    Set<RoleIdentifier> roleIdentifiers = roleMappingUserManager.getUsersRoles(user.getUserId(),
                            user.getSource());
                    if (roleIdentifiers != null) {
                        user.addAllRoles(roleIdentifiers);
                    }
                } catch (UserNotFoundException e) {
                    log.debug("User '" + user.getUserId() + "' is not managed by the usermanager: "
                            + tmpUserManager.getSource());
                }
            }
        }
    }

    public AuthorizationManager getAuthorizationManager(String source) throws NoSuchAuthorizationManagerException {
        if (!this.authorizationManagers.containsKey(source)) {
            throw new NoSuchAuthorizationManagerException(
                    "AuthorizationManager with source: '" + source + "' could not be found.");
        }

        return this.authorizationManagers.get(source);
    }

    public String getAnonymousUsername() {
        return this.securityConfiguration.getAnonymousUsername();
    }

    public boolean isAnonymousAccessEnabled() {
        return this.securityConfiguration.isAnonymousAccessEnabled();
    }

    public void changePassword(String userId, String oldPassword, String newPassword)
            throws UserNotFoundException, InvalidCredentialsException, InvalidConfigurationException {
        // first authenticate the user
        try {
            UsernamePasswordToken authenticationToken = new UsernamePasswordToken(userId, oldPassword);
            if (this.getSecurityManager().authenticate(authenticationToken) == null) {
                throw new InvalidCredentialsException();
            }
        } catch (org.apache.shiro.authc.AuthenticationException e) {
            log.debug("User failed to change password reason: " + e.getMessage(), e);
            throw new InvalidCredentialsException();
        }

        // if that was good just change the password
        this.changePassword(userId, newPassword);
    }

    public void changePassword(String userId, String newPassword)
            throws UserNotFoundException, InvalidConfigurationException {
        User user = this.getUser(userId);

        try {
            UserManager userManager = getUserManager(user.getSource());
            userManager.changePassword(userId, newPassword);
        } catch (NoSuchUserManagerException e) {
            // this should NEVER happen
            log.warn("User '" + userId + "' with source: '" + user.getSource()
                    + "' but could not find the UserManager for that source.");
        }

        // flush authc
        eventBus.post(new UserPrincipalsExpired(userId, user.getSource()));
    }

    public List<String> getRealms() {
        return new ArrayList<String>(this.securityConfiguration.getRealms());
    }

    public void setRealms(List<String> realms) throws InvalidConfigurationException {
        this.securityConfiguration.setRealms(realms);
        this.securityConfiguration.save();

        // update the realms in the security manager
        this.setSecurityManagerRealms();
    }

    public void setAnonymousAccessEnabled(boolean enabled) {
        this.securityConfiguration.setAnonymousAccessEnabled(enabled);
        this.securityConfiguration.save();
    }

    public void setAnonymousUsername(String anonymousUsername) throws InvalidConfigurationException {
        User user = null;
        try {
            user = getUser(securityConfiguration.getAnonymousUsername());
        } catch (UserNotFoundException e) {
            // ignore
        }
        this.securityConfiguration.setAnonymousUsername(anonymousUsername);
        this.securityConfiguration.save();
        // flush authc, if anon existed before change
        if (user != null) {
            eventBus.post(new UserPrincipalsExpired(user.getUserId(), user.getSource()));
        }
    }

    public String getAnonymousPassword() {
        return this.securityConfiguration.getAnonymousPassword();
    }

    public void setAnonymousPassword(String anonymousPassword) throws InvalidConfigurationException {
        User user = null;
        try {
            user = getUser(securityConfiguration.getAnonymousUsername());
        } catch (UserNotFoundException e) {
            // ignore
        }
        this.securityConfiguration.setAnonymousPassword(anonymousPassword);
        this.securityConfiguration.save();
        if (user != null) {
            // flush authc, if anon exists
            eventBus.post(new UserPrincipalsExpired(user.getUserId(), user.getSource()));
        }
    }

    public synchronized void start() {
        if (started) {
            throw new IllegalStateException(
                    getClass().getName() + " was already started, same instance is not re-startable!");
        }
        // reload the config
        this.securityConfiguration.clearCache();

        // setup the CacheManager ( this could be injected if we where less coupled with ehcache)
        // The plexus wrapper can interpolate the config
        EhCacheManager ehCacheManager = new EhCacheManager();
        ehCacheManager.setCacheManager(cacheManager);
        this.getSecurityManager().setCacheManager(ehCacheManager);

        if (org.apache.shiro.util.Initializable.class.isInstance(this.getSecurityManager())) {
            ((org.apache.shiro.util.Initializable) this.getSecurityManager()).init();
        }
        this.setSecurityManagerRealms();
        started = true;
    }

    public synchronized void stop() {
        if (getSecurityManager().getRealms() != null) {
            for (Realm realm : getSecurityManager().getRealms()) {
                if (AuthenticatingRealm.class.isInstance(realm)) {
                    ((AuthenticatingRealm) realm).setAuthenticationCache(null);
                }
                if (AuthorizingRealm.class.isInstance(realm)) {
                    ((AuthorizingRealm) realm).setAuthorizationCache(null);
                }
            }
        }

        // we need to kill caches on stop
        getSecurityManager().destroy();
        // cacheManagerComponent.shutdown();
    }

    private void setSecurityManagerRealms() {
        Collection<Realm> realms = getRealmsFromConfigSource();
        log.debug("Security manager realms: {}", realms);
        getSecurityManager().setRealms(Lists.newArrayList(realms));
    }

    /**
     * Looks up registered {@link AuthenticatingRealm}s, and clears their authc caches if they
     * have it set.
     *
     * @since 2.8
     */
    private void clearAuthcRealmCaches() {
        // NOTE: we don't need to iterate all the Sec Managers, they use the same Realms, so one is fine.
        final Collection<Realm> realms = getSecurityManager().getRealms();
        if (realms != null) {
            for (Realm realm : realms) {
                if (realm instanceof AuthenticatingRealm) {
                    clearIfNonNull(((AuthenticatingRealm) realm).getAuthenticationCache());
                }
            }
        }
    }

    /**
     * Looks up registered {@link AuthorizingRealm}s, and clears their authz caches if they
     * have it set.
     *
     * @since 2.8
     */
    private void clearAuthzRealmCaches() {
        // NOTE: we don't need to iterate all the Sec Managers, they use the same Realms, so one is fine.
        final Collection<Realm> realms = getSecurityManager().getRealms();
        if (realms != null) {
            for (Realm realm : realms) {
                if (realm instanceof AuthorizingRealm) {
                    clearIfNonNull(((AuthorizingRealm) realm).getAuthorizationCache());
                }
            }
        }
    }

    /**
     * Clears Shiro cache if passed instance is not {@code null}.
     *
     * @since 2.8
     */
    private void clearIfNonNull(@Nullable final Cache cache) {
        if (cache != null) {
            cache.clear();
        }
    }

    private Collection<UserManager> getUserManagers() {
        return userManagers.values();
    }

    private UserManager getUserManager(final String source) throws NoSuchUserManagerException {
        if (!userManagers.containsKey(source)) {
            throw new NoSuchUserManagerException("UserManager with source: '" + source + "' could not be found.");
        }
        return userManagers.get(source);
    }

    // ==

    @Subscribe
    public void onEvent(final UserPrincipalsExpired evt) {
        // TODO: we could do this better, not flushing whole cache for single user being deleted
        clearAuthcRealmCaches();
    }

    @Subscribe
    public void onEvent(final AuthorizationConfigurationChanged evt) {
        // TODO: we could do this better, not flushing whole cache for single user roles being updated
        clearAuthzRealmCaches();
    }

    @Subscribe
    public void onEvent(final SecurityConfigurationChanged evt) {
        clearAuthcRealmCaches();
        clearAuthzRealmCaches();
        securityConfiguration.clearCache();
        setSecurityManagerRealms();
    }

    public RealmSecurityManager getSecurityManager() {
        return securityManager;
    }
}