/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.auth; import java.util.Set; import org.apache.shiro.SecurityUtils; import org.apache.shiro.ShiroException; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.Permission; import org.apache.shiro.authz.permission.PermissionResolver; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.ThreadContext; import com.opengamma.util.ArgumentChecker; /** * Main entry point to the authentication and authorization system. * <p> * This class is used instead of the standard Apache Shiro {@code SecurityUtils}. */ public final class AuthUtils { /** * The singleton permission resolver. */ private static final ShiroPermissionResolver s_permissionResolver = new ShiroPermissionResolver(); // always setup a security manager static { SecurityUtils.setSecurityManager(PermissiveSecurityManager.DEFAULT); } /** * Restricted constructor. */ private AuthUtils() { } //------------------------------------------------------------------------- /** * Returns the {@code PermissionResolver} that creates authorization {@code Permission} instances. * <p> * The authorization system is based on {@link Permission} instances. * A {@link PermissionResolver} is used as a factory to create {@code Permission} instances. * <p> * The permission resolver returned here is a singleton that provides the ability * to switch the permission implementation based on a prefix. * * @return the singleton {@code PermissionResolver}, not null */ public static ShiroPermissionResolver getPermissionResolver() { return s_permissionResolver; } //------------------------------------------------------------------------- /** * Gets the single shared security manager. * <p> * The shared security manager is used as a fallback when there is no manager * in the {@link ThreadContext}. * This will return a permissive security manager by default. * * @return the security manager, not null */ public static SecurityManager getSecurityManager() { return SecurityUtils.getSecurityManager(); } /** * Sets the single shared security manager. * <p> * The shared security manager is used as a fallback when there is no manager * in the {@link ThreadContext}. * This method can only be called if the current manager is permissive. * * @param securityManager the new security manager, not null */ public static void initSecurityManager(SecurityManager securityManager) { if (isPermissive()) { SecurityUtils.setSecurityManager(securityManager); } else { throw new ShiroException("A security manager cannot be changed once set"); } } /** * Initializes the authentication and authorization system to permissive mode. * Permissive mode has a logged on user with all permissions granted. * <p> * This is used during startup to deliberately select a mode of operation * where security is switched off. */ public static void initSecurityManagerPermissive() { initSecurityManager(new PermissiveSecurityManager()); } /** * Checks if the authentication and authorization system is in permissive mode. * Permissive mode has a logged on user with all permissions granted. * * @return true if permissive */ public static boolean isPermissive() { return getSecurityManager() instanceof PermissiveSecurityManager; } /** * Checks if the authentication and authorization system is still in the * default permissive mode. * * @return true if the security manager has not been set */ public static boolean isDefault() { return getSecurityManager() == PermissiveSecurityManager.DEFAULT; } //------------------------------------------------------------------------- /** * Returns the {@code Subject} available to the calling code, typically based on a thread-local. * <p> * This provides access to the {@code Subject}, which is the main class used to interact with * the authentication and authorization system. A {@code Subject} represents the 'user', which * may or may not be logged on, and may be an application rather than a human. * <p> * Methods are provided to login, logout, check permissions and check roles. * In addition, the {@code Subject} provides a session similar to {@code HttpSession}. * * @return the appropriate {@code Subject}, not null * @throws IllegalStateException if the subject or security manager cannot be obtained, * which is a configuration error */ public static Subject getSubject() { return SecurityUtils.getSubject(); } /** * Gets the user name from the {@code Subject} if logged in. * <p> * This returns the user name if the user has been logged in. * * @return the user name, null if not logged on * @throws IllegalStateException if the subject or security manager cannot be obtained, * which is a configuration error * @throws ClassCastException if the primary principal of the subject is not a user name */ public static String getUserName() { return (String) SecurityUtils.getSubject().getPrincipal(); } //------------------------------------------------------------------------- /** * Checks that the user has all the permissions necessary to see the entity. * * @param permissionable the entity to be checked, not null * @return true if permitted */ public static boolean isPermitted(Permissionable permissionable) { ArgumentChecker.notNull(permissionable, "entity"); Set<Permission> requiredPermissions = AuthUtils.getPermissionResolver().resolvePermissions(permissionable.getRequiredPermissions()); return AuthUtils.getSubject().isPermittedAll(requiredPermissions); } /** * Checks that the user has all the permissions necessary to see the entity. * * @param permissionable the entity to be checked, not null * @throws AuthorizationException if the user does not have permission */ public static void checkPermissions(Permissionable permissionable) { ArgumentChecker.notNull(permissionable, "entity"); Set<Permission> requiredPermissions = AuthUtils.getPermissionResolver().resolvePermissions(permissionable.getRequiredPermissions()); AuthUtils.getSubject().checkPermissions(requiredPermissions); } }