com.ecyrd.jspwiki.auth
Class AuthorizationManager

java.lang.Object
  extended by com.ecyrd.jspwiki.auth.AuthorizationManager

public final class AuthorizationManager
extends Object

Manages all access control and authorization; determines what authenticated users are allowed to do.

Privileges in JSPWiki are expressed as Java-standard Permission classes. There are two types of permissions:

Calling classes determine whether they are entitled to perform a particular action by constructing the appropriate permission first, then passing it and the current WikiSession to the checkPermission(WikiSession, Permission) method. If the session's Subject possesses the permission, the action is allowed.

For WikiPermissions, the decision criteria is relatively simple: the caller either possesses the permission, as granted by the wiki security policy -- or not.

For PagePermissions, the logic is exactly the same if the page being checked does not have an access control list. However, if the page does have an ACL, the authorization decision is made based the union of the permissions granted in the ACL and in the security policy. In other words, the user must be named in the ACL (or belong to a group or role that is named in the ACL) and be granted (at least) the same permission in the security policy. We do this to prevent a user from gaining more permissions than they already have, based on the security policy.

See the checkPermission(WikiSession, Permission) and hasRoleOrPrincipal(WikiSession, Principal) methods for more information on the authorization logic.

Since:
2.3
Version:
$Revision: 1.37 $ $Date: 2006/05/28 23:21:35 $
Author:
Andrew Jaquith
See Also:
AuthenticationManager

Field Summary
static String DEFAULT_AUTHORIZER
          The default external Authorizer is the WebContainerAuthorizer
static String PROP_AUTHORIZER
          The property name in jspwiki.properties for specifying the external Authorizer.
 
Constructor Summary
AuthorizationManager()
          Constructs a new AuthorizationManager instance.
 
Method Summary
 void addWikiEventListener(WikiEventListener listener)
          Registers a WikiEventListener with this instance.
 boolean checkPermission(WikiSession session, Permission permission)
          Returns true or false, depending on whether a Permission is allowed for the Subject associated with a supplied WikiSession.
protected  boolean checkStaticPermission(Subject subject, Permission permission)
          Determines whether a Subject posesses a given "static" Permission as defined in the security policy file.
protected  void fireEvent(WikiSecurityEvent event)
          Fires a wiki event to all registered listeners.
protected  Authorizer getAuthorizer()
          Returns the current external Authorizer in use, which may be null.
 Principal[] getRoles(WikiSession session)
          Returns an array of Principal objects that represents the roles that the user associated with a WikiSession possesses.
protected  boolean hasRoleOrPrincipal(WikiSession session, Principal principal)
          Determines if the Subject associated with a supplied WikiSession contains a desired user Principal or built-in Role principal, OR is a member a Group or external Role.
 void initialize(WikiEngine engine, Properties properties)
          Initializes AuthorizationManager with an engine and set of properties.
 boolean isUserInRole(WikiSession session, Principal principal)
          Wrapper method that determines if the Subject associated with a supplied WikiSession contains a desired Role or GroupPrincipal.
 void removeWikiEventListener(WikiEventListener listener)
          Un-registers a WikiEventListener with this instance.
 Principal resolvePrincipal(String name)
          Given a supplied string representing a Principal's name from an Acl, this method resolves the correct type of Principal (role, group, or user).
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

DEFAULT_AUTHORIZER

public static final String DEFAULT_AUTHORIZER
The default external Authorizer is the WebContainerAuthorizer

See Also:
Constant Field Values

PROP_AUTHORIZER

public static final String PROP_AUTHORIZER
The property name in jspwiki.properties for specifying the external Authorizer.

See Also:
Constant Field Values
Constructor Detail

AuthorizationManager

public AuthorizationManager()
Constructs a new AuthorizationManager instance.

Method Detail

addWikiEventListener

public final void addWikiEventListener(WikiEventListener listener)
Registers a WikiEventListener with this instance.

Parameters:
listener - the event listener

checkPermission

public final boolean checkPermission(WikiSession session,
                                     Permission permission)
Returns true or false, depending on whether a Permission is allowed for the Subject associated with a supplied WikiSession. The access control algorithm works this way:
  1. The Acl for the page is obtained
  2. The Subject associated with the current WikiSession is obtained
  3. If the Subject's Principal set includes the Role Principal that is the administrator group, always allow the Permission
  4. For all permissions, check to see if the Permission is allowed according to the default security policy. If it isn't, deny the permission and halt further processing.
  5. If there is an Acl, get the list of Principals assigned this Permission in the Acl: these will be role, group or user Principals, or UnresolvedPrincipals (see below). Then iterate through the Subject's Principal set and determine whether the user (Subject) posesses any one of these specified Roles or Principals. The matching process delegates to hasRoleOrPrincipal(WikiSession, Principal).

Note that when iterating through the Acl's list of authorized Principals, it is possible that one or more of the Acl's Principal entries are of type UnresolvedPrincipal. This means that the last time the ACL was read, the Principal (user, built-in Role, authorizer Role, or wiki Group) could not be resolved: the Role was not valid, the user wasn't found in the UserDatabase, or the Group wasn't known to (e.g., cached) in the GroupManager. If an UnresolvedPrincipal is encountered, this method will attempt to resolve it first before checking to see if the Subject possesses this principal, by calling resolvePrincipal(String). If the (re-)resolution does not succeed, the access check for the principal will fail by definition (the Subject should never contain UnresolvedPrincipals).

If security not set to JAAS, will return true.

Parameters:
session - the current wiki session
permission - the Permission being checked
Returns:
the result of the Permission check
See Also:
hasRoleOrPrincipal(WikiSession, Principal)

getRoles

public final Principal[] getRoles(WikiSession session)
Returns an array of Principal objects that represents the roles that the user associated with a WikiSession possesses. The array is built by iterating through the Subject's Principal set and extracting all Role and GroupPrincipal objects into a list. The list is returned as an array sorted in the natural order implied by each Principal's getName method. Note that this method does not consult the external Authorizer or GroupManager; it relies on the Principals that have been injected into the user's Subject at login time, or after group creation/modification/deletion.

Parameters:
session - the wiki session
Returns:
an array of Principal objects corresponding to the roles the Subject possesses

isUserInRole

public final boolean isUserInRole(WikiSession session,
                                  Principal principal)
Wrapper method that determines if the Subject associated with a supplied WikiSession contains a desired Role or GroupPrincipal. The algorithm simply checks to see if the Subject possesses the Role or GroupPrincipal it in its Principal set. If the Principal is of type Group, it is converted to an equivalent GroupPrincipal first. For all other cases, this method returns false. Note that this method does not consult the external Authorizer or GroupManager; it relies on the Principals that have been injected into the user's Subject at login time, or after group creation/modification/deletion.

Parameters:
session - the current wiki session, which must be non-null. If null, the result of this method always returns false
principal - the Principal (role or group principal) to look for, which must be non-null. If null, the result of this method always returns false
Returns:
true if the Subject supplied with the WikiContext posesses the Role or GroupPrincipal, false otherwise

hasRoleOrPrincipal

protected final boolean hasRoleOrPrincipal(WikiSession session,
                                           Principal principal)

Determines if the Subject associated with a supplied WikiSession contains a desired user Principal or built-in Role principal, OR is a member a Group or external Role. The rules are as follows:

  1. First, see if the user possesses the role by delegating to isUserInRole(WikiSession, Principal). If the result is true, we're done. If the result is negative and the WikiSession is not authenticated, always return false. We do this to prevent privilege escalation.
  2. Otherwise, we're looking for a user Principal, so iterate through the Principal set and see if any share the same name as the one we are looking for.

Note: as implied by the first rule above, this method will always return false when the user isn't authenticated, and the principal/role being queried isn't a Role or GroupPrincipal. This is to prevent privilege escalation by non-authenticated users. Thus, to gain access to pages that name a specific user, that user is required to log in. Ditto for groups he or she belongs to. The exception is for ACLs that contain built-in roles; e.g., "allow Asserted users to view" is allowed.

A consequence of this rule is that ACLs that specify ALLOW Guest will not work for anonymous/asserted users (because Guest is a Principal, not a built-in Role). ACLs should specify ALLOW Anonymous instead.

Parameters:
session - the current wiki session, which must be non-null. If null, the result of this method always returns false
principal - the Principal (role, group, or user principal) to look for, which must be non-null. If null, the result of this method always returns false
Returns:
true if the Subject supplied with the WikiContext posesses the Role, GroupPrincipal or desired user Principal, false otherwise

initialize

public final void initialize(WikiEngine engine,
                             Properties properties)
                      throws WikiException
Initializes AuthorizationManager with an engine and set of properties. Expects to find property 'jspwiki.authorizer' with a valid Authorizer implementation name to take care of group lookup operations.

Throws:
WikiException

fireEvent

protected final void fireEvent(WikiSecurityEvent event)
Fires a wiki event to all registered listeners.

Parameters:
event - the event

getAuthorizer

protected final Authorizer getAuthorizer()
Returns the current external Authorizer in use, which may be null.

Returns:
the current Authorizer

checkStaticPermission

protected final boolean checkStaticPermission(Subject subject,
                                              Permission permission)
Determines whether a Subject posesses a given "static" Permission as defined in the security policy file. This method uses standard Java 2 security calls to do its work. Note that the current access control context's codeBase is effectively this class, not that of the caller. Therefore, this method will work best when what matters in the policy is who makes the permission check, not what the caller's code source is. Internally, this method works by excuting Subject.doAsPrivileged with a privileged action that simply calls AccessController.checkPermission(Permission).

Parameters:
subject - the Subject whose permission status is being queried
permission - the Permission the Subject must possess
Returns:
true if the Subject posesses the permission, false otherwise

removeWikiEventListener

public final void removeWikiEventListener(WikiEventListener listener)
Un-registers a WikiEventListener with this instance.

Parameters:
listener - the event listener

resolvePrincipal

public final Principal resolvePrincipal(String name)

Given a supplied string representing a Principal's name from an Acl, this method resolves the correct type of Principal (role, group, or user). This method is guaranteed to always return a Principal. The algorithm is straightforward:

  1. If the name matches one of the built-in Role names, return that built-in Role
  2. If the name matches one supplied by the current Authorizer, return that Role
  3. If the name matches a group managed by the current GroupManager, return that Group
  4. Otherwise, assume that the name represents a user principal. Using the current UserDatabase, find the first user who matches the supplied name by calling UserDatabase.find(String).
  5. Finally, if a user cannot be found, manufacture and return a generic UnresolvedPrincipal

Parameters:
name - the name of the Principal to resolve
Returns:
the fully-resolved Principal