Package org.sonatype.security

Source Code of org.sonatype.security.DefaultSecuritySystem

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 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.Iterator;
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.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.email.NullSecurityEmailer;
import org.sonatype.security.email.SecurityEmailer;
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.PasswordGenerator;
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.UserManagerFacade;
import org.sonatype.security.usermanagement.UserNotFoundException;
import org.sonatype.security.usermanagement.UserSearchCriteria;
import org.sonatype.security.usermanagement.UserStatus;
import org.sonatype.sisu.goodies.eventbus.EventBus;

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 org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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
    implements SecuritySystem
{
  private static final Logger logger = LoggerFactory.getLogger(DefaultSecuritySystem.class);

  private SecurityConfigurationManager securityConfiguration;

  private RealmSecurityManager securityManager;

  private CacheManager cacheManager;

  private UserManagerFacade userManagerFacade;

  private Map<String, Realm> realmMap;

  private Map<String, AuthorizationManager> authorizationManagers;

  private PasswordGenerator passwordGenerator;

  private EventBus eventBus;

  private List<SecurityEmailer> securityEmailers;

  private SecurityEmailer securityEmailer;

  private static final String ALL_ROLES_KEY = "all";

  private volatile boolean started;

  @Inject
  public DefaultSecuritySystem(List<SecurityEmailer> securityEmailers,
                               EventBus eventBus,
                               PasswordGenerator passwordGenerator,
                               Map<String, AuthorizationManager> authorizationManagers,
                               Map<String, Realm> realmMap,
                               SecurityConfigurationManager securityConfiguration,
                               RealmSecurityManager securityManager,
                               CacheManager cacheManager,
                               UserManagerFacade userManagerFacade)
  {
    this.securityEmailers = securityEmailers;
    this.eventBus = eventBus;
    this.passwordGenerator = passwordGenerator;
    this.authorizationManagers = authorizationManagers;
    this.realmMap = realmMap;
    this.securityConfiguration = securityConfiguration;
    this.securityManager = securityManager;
    this.cacheManager = cacheManager;

    this.eventBus.register(this);
    this.userManagerFacade = userManagerFacade;
    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 {
        this.logger.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) {
          this.logger.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)
      throws NoSuchUserManagerException, InvalidConfigurationException
  {
    return this.addUser(user, this.generatePassword());
  }

  public User addUser(User user, String password)
      throws NoSuchUserManagerException, InvalidConfigurationException
  {
    // if the password is null, generate one
    if (password == null) {
      password = this.generatePassword();
    }

    // first save the user
    // this is the UserManager that owns the user
    UserManager userManager = userManagerFacade.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 : userManagerFacade.getUserManagers().values()) {
      // 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) {
          this.logger.debug("User '" + user.getUserId() + "' is not managed by the usermanager: "
              + tmpUserManager.getSource());
        }
      }
    }

    if (UserStatus.active.equals(user.getStatus())) {
      // don't forget to email the user (if the user being added is active)!
      getSecurityEmailer().sendNewUserCreated(user.getEmailAddress(), user.getUserId(), password);
    }

    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 = userManagerFacade.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 : userManagerFacade.getUserManagers().values()) {
      // 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) {
          this.logger.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) {
      this.logger.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 = userManagerFacade.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 : userManagerFacade.getUserManagers().values()) {
      if (RoleMappingUserManager.class.isInstance(tmpUserManager)) {
        RoleMappingUserManager roleMappingUserManager = (RoleMappingUserManager) tmpUserManager;
        try {
          foundUser = true;
          roleMappingUserManager.setUsersRoles(userId,
              source,
              RoleIdentifier.getRoleIdentifiersForSource(tmpUserManager.getSource(),
                  roleIdentifiers));
        }
        catch (UserNotFoundException e) {
          this.logger.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());
  }

  public User getUser(String userId)
      throws UserNotFoundException
  {
    List<UserManager> orderedUserManagers = this.orderUserManagers();
    for (UserManager userManager : orderedUserManagers) {
      try {
        return this.getUser(userId, userManager.getSource());
      }
      catch (UserNotFoundException e) {
        this.logger.debug("User: '" + userId + "' was not found in: '" + userManager.getSource() + "' ");
      }
      catch (NoSuchUserManagerException e) {
        // we should NEVER bet here
        this.logger.warn("UserManager: '" + userManager.getSource()
            + "' was not found, but is in the list of UserManagers", e);
      }
    }
    throw new UserNotFoundException(userId);
  }

  public User getUser(String userId, String source)
      throws UserNotFoundException, NoSuchUserManagerException
  {
    // first get the user
    // this is the UserManager that owns the user
    UserManager userManager = userManagerFacade.getUserManager(source);
    User user = userManager.getUser(userId);

    if (user == null) {
      throw new UserNotFoundException(userId);
    }

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

    return user;
  }

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

    for (UserManager tmpUserManager : userManagerFacade.getUserManagers().values()) {
      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 (StringUtils.isEmpty(criteria.getSource())) {
      // search all user managers
      for (UserManager tmpUserManager : userManagerFacade.getUserManagers().values()) {
        Set<User> result = tmpUserManager.searchUsers(criteria);
        if (result != null) {
          users.addAll(result);
        }
      }
    }
    else {
      try {
        users.addAll(userManagerFacade.getUserManager(criteria.getSource()).searchUsers(criteria));
      }
      catch (NoSuchUserManagerException e) {
        this.logger.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>(userManagerFacade.getUserManagers().values());

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

    for (UserManager userManager : userManagerFacade.getUserManagers().values()) {
      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 : userManagerFacade.getUserManagers().values()) {
      // 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) {
          this.logger.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) {
      this.logger.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 = userManagerFacade.getUserManager(user.getSource());
      userManager.changePassword(userId, newPassword);
    }
    catch (NoSuchUserManagerException e) {
      // this should NEVER happen
      this.logger.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 void forgotPassword(String userId, String email)
      throws UserNotFoundException, InvalidConfigurationException
  {
    UserSearchCriteria criteria = new UserSearchCriteria();
    criteria.setEmail(email);
    criteria.setUserId(userId);

    Set<User> users = this.searchUsers(criteria);

    boolean found = false;

    for (User user : users) {
      // TODO: criteria does not do exact matching
      if (user.getUserId().equalsIgnoreCase(userId.trim()) && user.getEmailAddress().equals(email)) {
        found = true;
        break;
      }
    }

    if (!found) {
      throw new UserNotFoundException(email);
    }

    resetPassword(userId);
  }

  public void forgotUsername(String email)
      throws UserNotFoundException
  {
    UserSearchCriteria criteria = new UserSearchCriteria();
    criteria.setEmail(email);

    Set<User> users = this.searchUsers(criteria);

    List<String> userIds = new ArrayList<String>();
    for (User user : users) {
      // ignore the anon user
      if (!user.getUserId().equalsIgnoreCase(this.getAnonymousUsername())
          && email.equalsIgnoreCase(user.getEmailAddress())) {
        userIds.add(user.getUserId());
      }
    }

    if (userIds.size() > 0) {

      this.getSecurityEmailer().sendForgotUsername(email, userIds);
    }
    else {
      throw new UserNotFoundException(email);
    }

  }

  public void resetPassword(String userId)
      throws UserNotFoundException, InvalidConfigurationException
  {
    String newClearTextPassword = this.generatePassword();

    User user = this.getUser(userId);

    this.changePassword(userId, newClearTextPassword);

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

    // send email
    this.getSecurityEmailer().sendResetPassword(user.getEmailAddress(), newClearTextPassword);

  }

  private String generatePassword() {
    return this.passwordGenerator.generatePassword(10, 10);
  }

  private SecurityEmailer getSecurityEmailer() {
    if (this.securityEmailer == null) {
      Iterator<SecurityEmailer> i = this.securityEmailers.iterator();
      if (i.hasNext()) {
        this.securityEmailer = i.next();
      }
      else {
        this.logger.error("Failed to find a SecurityEmailer");
        this.securityEmailer = new NullSecurityEmailer();
      }
    }
    return this.securityEmailer;
  }

  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() {
    getSecurityManager().setRealms(new ArrayList<Realm>(this.getRealmsFromConfigSource()));
  }

  /**
   * 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();
    }
  }

  // ==

  @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;
  }
}
TOP

Related Classes of org.sonatype.security.DefaultSecuritySystem

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.