You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/02/13 06:54:24 UTC
svn commit: r627255 [11/41] - in
/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src: ./ com/ com/ecyrd/
com/ecyrd/jspwiki/ com/ecyrd/jspwiki/action/ com/ecyrd/jspwiki/attachment/
com/ecyrd/jspwiki/auth/ com/ecyrd/jspwiki/auth/acl/ com/ecyrd/jspwiki...
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/AuthorizationManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/AuthorizationManager.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/AuthorizationManager.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/AuthorizationManager.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,684 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Copyright (C) 2001-2003 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+
+import java.io.File;
+import java.net.URL;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.util.Map;
+import java.util.Properties;
+import java.util.WeakHashMap;
+
+import org.apache.log4j.Logger;
+import org.freshcookies.security.policy.LocalPolicy;
+import org.freshcookies.security.policy.PolicyException;
+
+import com.ecyrd.jspwiki.NoRequiredPropertyException;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.WikiPage;
+import com.ecyrd.jspwiki.WikiSession;
+import com.ecyrd.jspwiki.auth.acl.Acl;
+import com.ecyrd.jspwiki.auth.acl.AclEntry;
+import com.ecyrd.jspwiki.auth.acl.UnresolvedPrincipal;
+import com.ecyrd.jspwiki.auth.authorize.Role;
+import com.ecyrd.jspwiki.auth.permissions.AllPermission;
+import com.ecyrd.jspwiki.auth.permissions.PagePermission;
+import com.ecyrd.jspwiki.auth.user.UserDatabase;
+import com.ecyrd.jspwiki.auth.user.UserProfile;
+import com.ecyrd.jspwiki.event.WikiEventListener;
+import com.ecyrd.jspwiki.event.WikiEventManager;
+import com.ecyrd.jspwiki.event.WikiSecurityEvent;
+import com.ecyrd.jspwiki.util.ClassUtil;
+
+/**
+ * <p>Manages all access control and authorization; determines what authenticated
+ * users are allowed to do.</p>
+ * <p>Privileges in JSPWiki are expressed as Java-standard {@link java.security.Permission}
+ * classes. There are two types of permissions:</p>
+ * <ul>
+ * <li>{@link com.ecyrd.jspwiki.auth.permissions.WikiPermission} - privileges that apply
+ * to an entire wiki instance: <em>e.g.,</em> editing user profiles, creating pages, creating groups</li>
+ * <li>{@link com.ecyrd.jspwiki.auth.permissions.PagePermission} - privileges that apply
+ * to a single wiki page or range of pages: <em>e.g.,</em> reading, editing, renaming
+ * </ul>
+ * <p>Calling classes determine whether they are entitled to perform a particular action
+ * by constructing the appropriate permission first, then passing it and the current
+ * {@link com.ecyrd.jspwiki.WikiSession} to the
+ * {@link #checkPermission(WikiSession, Permission)} method. If the session's
+ * Subject possesses the permission, the action is allowed.</p>
+ * <p>For WikiPermissions, the decision criteria is relatively simple: the caller either
+ * possesses the permission, as granted by the wiki security policy -- or not.</p>
+ * <p>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 <em>union</em> 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)
+ * <em>and</em> 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.</p>
+ * <p>See the {@link #checkPermission(WikiSession, Permission)} and
+ * {@link #hasRoleOrPrincipal(WikiSession, Principal)} methods for more information
+ * on the authorization logic.</p>
+ * @author Andrew Jaquith
+ * @since 2.3
+ * @see AuthenticationManager
+ */
+public final class AuthorizationManager
+{
+ private static final Logger log = Logger.getLogger( AuthorizationManager.class );
+ /**
+ * The default external Authorizer is the {@link com.ecyrd.jspwiki.auth.authorize.WebContainerAuthorizer}
+ */
+ public static final String DEFAULT_AUTHORIZER = "com.ecyrd.jspwiki.auth.authorize.WebContainerAuthorizer";
+
+ /** Name of the default security policy file, in WEB-INF. */
+ protected static final String DEFAULT_POLICY = "jspwiki.policy";
+
+ /**
+ * The property name in jspwiki.properties for specifying the external {@link Authorizer}.
+ */
+ public static final String PROP_AUTHORIZER = "jspwiki.authorizer";
+
+ private Authorizer m_authorizer = null;
+
+ /** Cache for storing ProtectionDomains used to evaluate the local policy. */
+ private Map m_cachedPds = new WeakHashMap();
+
+ private WikiEngine m_engine = null;
+
+ private LocalPolicy m_localPolicy = null;
+
+ private boolean m_useJAAS = true;
+
+ /**
+ * Constructs a new AuthorizationManager instance.
+ */
+ public AuthorizationManager()
+ {
+ }
+
+ /**
+ * Returns <code>true</code> or <code>false</code>, depending on
+ * whether a Permission is allowed for the Subject associated with
+ * a supplied WikiSession. The access control algorithm works this way:
+ * <ol>
+ * <li>The {@link com.ecyrd.jspwiki.auth.acl.Acl} for the page is obtained</li>
+ * <li>The Subject associated with the current
+ * {@link com.ecyrd.jspwiki.WikiSession} is obtained</li>
+ * <li>If the Subject's Principal set includes the Role Principal that is
+ * the administrator group, always allow the Permission</li>
+ * <li>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.</li>
+ * <li>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
+ * {@link com.ecyrd.jspwiki.auth.acl.UnresolvedPrincipal}s (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
+ * {@link #hasRoleOrPrincipal(WikiSession, Principal)}.
+ * </ol>
+ * <p>
+ * 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 <code>UnresolvedPrincipal</code>. 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 <code>UnresolvedPrincipal</code> is
+ * encountered, this method will attempt to resolve it first <em>before</em>
+ * checking to see if the Subject possesses this principal, by calling
+ * {@link #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).
+ * </p>
+ * <p>
+ * If security not set to JAAS, will return true.
+ * </p>
+ * @param session the current wiki session
+ * @param permission the Permission being checked
+ * @see #hasRoleOrPrincipal(WikiSession, Principal)
+ * @return the result of the Permission check
+ */
+ public final boolean checkPermission( WikiSession session, Permission permission )
+ {
+ if( !m_useJAAS )
+ {
+ //
+ // Nobody can login, if JAAS is turned off.
+ //
+
+ if( permission == null || "login".equals( permission.getActions() ) )
+ return false;
+
+ return true;
+ }
+
+ //
+ // A slight sanity check.
+ //
+ if ( session == null || permission == null )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_DENIED, null, permission );
+ return false;
+ }
+
+ Principal user = session.getLoginPrincipal();
+
+ // Always allow the action if user has AllPermission
+ Permission allPermission = new AllPermission( m_engine.getApplicationName() );
+ boolean hasAllPermission = checkStaticPermission( session, allPermission );
+ if ( hasAllPermission )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission );
+ return true;
+ }
+
+ // If the user doesn't have *at least* the permission
+ // granted by policy, return false.
+ boolean hasPolicyPermission = checkStaticPermission( session, permission );
+ if ( !hasPolicyPermission )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_DENIED, user, permission );
+ return false;
+ }
+
+ // If this isn't a PagePermission, it's allowed
+ if ( ! ( permission instanceof PagePermission ) )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission );
+ return true;
+ }
+
+ //
+ // If the page or ACL is null, it's allowed.
+ //
+ String pageName = ((PagePermission)permission).getPage();
+ WikiPage page = m_engine.getPage( pageName );
+ Acl acl = ( page == null) ? null : m_engine.getAclManager().getPermissions( page );
+ if ( page == null || acl == null || acl.isEmpty() )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission );
+ return true;
+ }
+
+ //
+ // Next, iterate through the Principal objects assigned
+ // this permission. If the context's subject possesses
+ // any of these, the action is allowed.
+
+ Principal[] aclPrincipals = acl.findPrincipals( permission );
+
+ log.debug( "Checking ACL entries..." );
+ log.debug( "Acl for this page is: " + acl );
+ log.debug( "Checking for principal: " + String.valueOf(aclPrincipals) );
+ log.debug( "Permission: " + permission );
+
+ for( int i = 0; i < aclPrincipals.length; i++ )
+ {
+ Principal aclPrincipal = aclPrincipals[i];
+
+ // If the ACL principal we're looking at is unresolved,
+ // try to resolve it here & correct the Acl
+ if ( aclPrincipal instanceof UnresolvedPrincipal )
+ {
+ AclEntry aclEntry = acl.getEntry( aclPrincipal );
+ aclPrincipal = resolvePrincipal( aclPrincipal.getName() );
+ if ( aclEntry != null && !( aclPrincipal instanceof UnresolvedPrincipal ) )
+ {
+ aclEntry.setPrincipal( aclPrincipal );
+ }
+ }
+
+ if ( hasRoleOrPrincipal( session, aclPrincipal ) )
+ {
+ fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission );
+ return true;
+ }
+ }
+ fireEvent( WikiSecurityEvent.ACCESS_DENIED, user, permission );
+ return false;
+ }
+
+ /**
+ * <p>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. Note that
+ * any user (anyonymous, asserted, authenticated) can possess
+ * a built-in role. But a user <em>must</em> be authenticated to
+ * possess a role other than one of the built-in ones.
+ * We do this to prevent privilege escalation.</p>
+ * <p>For all other cases, this method returns <code>false</code>.</p>
+ * <p>Note that this method does <em>not</em> 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.</p>
+ * @param session the current wiki session, which must be non-null. If null,
+ * the result of this method always returns <code>false</code>
+ * @param principal the Principal (role or group principal) to look
+ * for, which must be non-<cor>null</code>. If <code>null</code>,
+ * the result of this method always returns <code>false</code>
+ * @return <code>true</code> if the Subject supplied with the WikiContext
+ * posesses the Role or GroupPrincipal, <code>false</code> otherwise
+ */
+ public final boolean isUserInRole( WikiSession session, Principal principal )
+ {
+ if ( session == null || principal == null ||
+ AuthenticationManager.isUserPrincipal( principal ) )
+ {
+ return false;
+ }
+
+ // Any type of user can possess a built-in role
+ if ( principal instanceof Role && Role.isBuiltInRole( (Role)principal ) )
+ {
+ return session.hasPrincipal( principal );
+ }
+
+ // Only authenticated users can posssess groups or custom roles
+ if ( session.isAuthenticated() && AuthenticationManager.isRolePrincipal( principal ) )
+ {
+ return session.hasPrincipal( principal );
+ }
+ return false;
+ }
+
+ /**
+ * Returns the current external {@link Authorizer} in use. This method
+ * is guaranteed to return a properly-initialized Authorizer, unless
+ * it could not be initialized. In that case, this method throws
+ * a {@link com.ecyrd.jspwiki.auth.WikiSecurityException}.
+ * @throws com.ecyrd.jspwiki.auth.WikiSecurityException if the Authorizer could
+ * not be initialized
+ * @return the current Authorizer
+ */
+ public final Authorizer getAuthorizer() throws WikiSecurityException
+ {
+ if ( m_authorizer != null )
+ {
+ return m_authorizer;
+ }
+ throw new WikiSecurityException( "Authorizer did not initialize properly. Check the logs." );
+ }
+
+ /**
+ * <p>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:</p>
+ * <ol>
+ * <li>First, if desired Principal is a Role or GroupPrincipal, delegate to
+ * {@link #isUserInRole(WikiSession, Principal)} and
+ * return the result.</li>
+ * <li>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.</li>
+ * </ol>
+ * <p><em>Note: if the Principal parameter is a user principal, the session
+ * must be authenticated in order for the user to "possess it". Anonymous
+ * or asserted sessions will never posseess a named user principal.</em></p>
+ * @param session the current wiki session, which must be non-null. If null,
+ * the result of this method always returns <code>false</code>
+ * @param 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 <code>false</code>
+ * @return <code>true</code> if the Subject supplied with the WikiContext
+ * posesses the Role, GroupPrincipal or desired
+ * user Principal, <code>false</code> otherwise
+ */
+ protected boolean hasRoleOrPrincipal( WikiSession session, Principal principal )
+ {
+ // If either parameter is null, always deny
+ if( session == null || principal == null )
+ {
+ return false;
+ }
+
+ // If principal is role, delegate to isUserInRole
+ if( AuthenticationManager.isRolePrincipal( principal ) )
+ {
+ return isUserInRole( session, principal );
+ }
+
+ // We must be looking for a user principal, assuming that the user
+ // has been properly logged in.
+ // So just look for a name match.
+ if( session.isAuthenticated() && AuthenticationManager.isUserPrincipal( principal ) )
+ {
+ String principalName = principal.getName();
+ Principal[] userPrincipals = session.getPrincipals();
+ for( int i = 0; i < userPrincipals.length; i++ )
+ {
+ Principal userPrincipal = userPrincipals[i];
+ if( userPrincipal.getName().equals( principalName ) )
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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.
+ * @param engine the wiki engine
+ * @param properties the set of properties used to initialize the wiki engine
+ * @throws WikiException if the AuthorizationManager cannot be initialized
+ */
+ public final void initialize( WikiEngine engine, Properties properties ) throws WikiException
+ {
+ m_engine = engine;
+
+ m_useJAAS = AuthenticationManager.SECURITY_JAAS.equals( properties.getProperty(AuthenticationManager.PROP_SECURITY, AuthenticationManager.SECURITY_JAAS ) );
+
+ if( !m_useJAAS ) return;
+
+ //
+ // JAAS authorization continues
+ //
+ m_authorizer = getAuthorizerImplementation( properties );
+ m_authorizer.initialize( engine, properties );
+
+ // Initialize local security policy
+ try
+ {
+ URL policyURL = AuthenticationManager.findConfigFile( engine, DEFAULT_POLICY );
+
+ if (policyURL != null)
+ {
+ File policyFile = new File( policyURL.getPath() );
+ m_localPolicy = new LocalPolicy( policyFile, engine.getContentEncoding() );
+ m_localPolicy.refresh();
+ log.info("Initialized default security policy: " + policyFile.getAbsolutePath());
+ }
+ else
+ {
+ StringBuffer sb = new StringBuffer("JSPWiki was unable to initialize the ");
+ sb.append("default security policy (WEB-INF/jspwiki.policy) file. ");
+ sb.append("Please ensure that the jspwiki.policy file exists in the default location. ");
+ sb.append("This file should exist regardless of the existance of a global policy file. ");
+ sb.append("The global policy file is identified by the java.security.policy variable. ");
+ WikiSecurityException wse = new WikiSecurityException(sb.toString());
+ log.fatal(sb.toString(), wse);
+ throw wse;
+ }
+ }
+ catch ( PolicyException e )
+ {
+ log.error("Could not initialize local security policy: " + e.getMessage() );
+ throw new WikiException( e.getMessage() );
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if JSPWiki's JAAS authorization system
+ * is used for authorization in addition to container controls.
+ * @return the result
+ */
+ protected boolean isJAASAuthorized()
+ {
+ return m_useJAAS;
+ }
+
+ /**
+ * Attempts to locate and initialize a Authorizer to use with this manager.
+ * Throws a WikiException if no entry is found, or if one fails to
+ * initialize.
+ * @param props jspwiki.properties, containing a
+ * 'jspwiki.authorization.provider' class name
+ * @return a Authorizer used to get page authorization information
+ * @throws WikiException
+ */
+ private final Authorizer getAuthorizerImplementation( Properties props ) throws WikiException
+ {
+ String authClassName = props.getProperty( PROP_AUTHORIZER, DEFAULT_AUTHORIZER );
+ return (Authorizer) locateImplementation( authClassName );
+ }
+
+ private final Object locateImplementation( String clazz ) throws WikiException
+ {
+ if ( clazz != null )
+ {
+ try
+ {
+ Class authClass = ClassUtil.findClass( "com.ecyrd.jspwiki.auth.authorize", clazz );
+ Object impl = authClass.newInstance();
+ return impl;
+ }
+ catch( ClassNotFoundException e )
+ {
+ log.fatal( "Authorizer " + clazz + " cannot be found", e );
+ throw new WikiException( "Authorizer " + clazz + " cannot be found" );
+ }
+ catch( InstantiationException e )
+ {
+ log.fatal( "Authorizer " + clazz + " cannot be created", e );
+ throw new WikiException( "Authorizer " + clazz + " cannot be created" );
+ }
+ catch( IllegalAccessException e )
+ {
+ log.fatal( "You are not allowed to access this authorizer class", e );
+ throw new WikiException( "You are not allowed to access this authorizer class" );
+ }
+ }
+
+ throw new NoRequiredPropertyException( "Unable to find a " + PROP_AUTHORIZER + " entry in the properties.",
+ PROP_AUTHORIZER );
+ }
+
+ /**
+ * Checks to see if the local security policy allows a particular static Permission.
+ * Do not use this method for normal permission checks; use
+ * {@link #checkPermission(WikiSession, Permission)} instead.
+ * @param principals the Principals to check
+ * @param permission the Permission
+ * @return the result
+ */
+ protected boolean allowedByLocalPolicy( Principal[] principals, Permission permission )
+ {
+ for ( int i = 0; i < principals.length; i++ )
+ {
+ // Get ProtectionDomain for this Principal from cache, or create new one
+ ProtectionDomain pd = (ProtectionDomain)m_cachedPds.get( principals[i] );
+ if ( pd == null )
+ {
+ ClassLoader cl = this.getClass().getClassLoader();
+ CodeSource cs = new CodeSource( null, (Certificate[])null );
+ pd = new ProtectionDomain( cs, null, cl, new Principal[]{ principals[i] } );
+ m_cachedPds.put( principals[i], pd );
+ }
+
+ // Consult the local policy and get the answer
+ if ( m_localPolicy.implies( pd, permission ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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 <code>codeBase</code> is effectively <em>this class</em>,
+ * not that of the caller. Therefore, this method will work best when what
+ * matters in the policy is <em>who</em> makes the permission check, not
+ * what the caller's code source is. Internally, this method works by
+ * excuting <code>Subject.doAsPrivileged</code> with a privileged action
+ * that simply calls {@link java.security.AccessController#checkPermission(Permission)}.
+ * @link AccessController#checkPermission(java.security.Permission). A
+ * caught exception (or lack thereof) determines whether the privilege
+ * is absent (or present).
+ * @param session the WikiSession whose permission status is being queried
+ * @param permission the Permission the Subject must possess
+ * @return <code>true</code> if the Subject posesses the permission,
+ * <code>false</code> otherwise
+ */
+ protected final boolean checkStaticPermission( final WikiSession session, final Permission permission )
+ {
+ if( !m_useJAAS ) return true;
+
+ Boolean allowed = (Boolean)WikiSession.doPrivileged( session, new PrivilegedAction()
+ {
+ public Object run()
+ {
+ try
+ {
+ // Check the JVM-wide security policy first
+ AccessController.checkPermission( permission );
+ return Boolean.TRUE;
+ }
+ catch( AccessControlException e )
+ {
+ // Global policy denied the permission
+ }
+
+ // Try the local policy - check each Role/Group and User Principal
+ if ( allowedByLocalPolicy( session.getRoles(), permission ) ||
+ allowedByLocalPolicy( session.getPrincipals(), permission ) )
+ {
+ return Boolean.TRUE;
+ }
+ return Boolean.FALSE;
+ }
+ } );
+ return allowed.booleanValue();
+ }
+
+ /**
+ * <p>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:</p>
+ * <ol>
+ * <li>If the name matches one of the built-in {@link com.ecyrd.jspwiki.auth.authorize.Role} names,
+ * return that built-in Role</li>
+ * <li>If the name matches one supplied by the current
+ * {@link com.ecyrd.jspwiki.auth.Authorizer}, return that Role</li>
+ * <li>If the name matches a group managed by the
+ * current {@link com.ecyrd.jspwiki.auth.authorize.GroupManager}, return that Group</li>
+ * <li>Otherwise, assume that the name represents a user
+ * principal. Using the current {@link com.ecyrd.jspwiki.auth.user.UserDatabase}, find the
+ * first user who matches the supplied name by calling
+ * {@link com.ecyrd.jspwiki.auth.user.UserDatabase#find(String)}.</li>
+ * <li>Finally, if a user cannot be found, manufacture
+ * and return a generic {@link com.ecyrd.jspwiki.auth.acl.UnresolvedPrincipal}</li>
+ * </ol>
+ * @param name the name of the Principal to resolve
+ * @return the fully-resolved Principal
+ */
+ public final Principal resolvePrincipal( String name )
+ {
+ if( !m_useJAAS )
+ {
+ return new UnresolvedPrincipal(name);
+ }
+
+ // Check built-in Roles first
+ Role role = new Role(name);
+ if ( Role.isBuiltInRole( role ) )
+ {
+ return role;
+ }
+
+ // Check Authorizer Roles
+ Principal principal = m_authorizer.findRole( name );
+ if ( principal != null )
+ {
+ return principal;
+ }
+
+ // Check Groups
+ principal = m_engine.getGroupManager().findRole( name );
+ if ( principal != null )
+ {
+ return principal;
+ }
+
+ // Ok, no luck---this must be a user principal
+ Principal[] principals = null;
+ UserProfile profile = null;
+ UserDatabase db = m_engine.getUserManager().getUserDatabase();
+ try
+ {
+ profile = db.find( name );
+ principals = db.getPrincipals( profile.getLoginName() );
+ for (int i = 0; i < principals.length; i++)
+ {
+ principal = principals[i];
+ if ( principal.getName().equals( name ) )
+ {
+ return principal;
+ }
+ }
+ }
+ catch( NoSuchPrincipalException e )
+ {
+ // We couldn't find the user...
+ }
+ // Ok, no luck---mark this as unresolved and move on
+ return new UnresolvedPrincipal( name );
+ }
+
+
+ // events processing .......................................................
+
+ /**
+ * Registers a WikiEventListener with this instance.
+ * @param listener the event listener
+ */
+ public final synchronized void addWikiEventListener( WikiEventListener listener )
+ {
+ WikiEventManager.addWikiEventListener( this, listener );
+ }
+
+ /**
+ * Un-registers a WikiEventListener with this instance.
+ * @param listener the event listener
+ */
+ public final synchronized void removeWikiEventListener( WikiEventListener listener )
+ {
+ WikiEventManager.removeWikiEventListener( this, listener );
+ }
+
+ /**
+ * Fires a WikiSecurityEvent of the provided type, user,
+ * and permission to all registered listeners.
+ *
+ * @see com.ecyrd.jspwiki.event.WikiSecurityEvent
+ * @param type the event type to be fired
+ * @param user the user associated with the event
+ * @param permission the permission the subject must possess
+ */
+ protected final void fireEvent( int type, Principal user, Object permission )
+ {
+ if ( WikiEventManager.isListening(this) )
+ {
+ WikiEventManager.fireEvent(this,new WikiSecurityEvent(this,type,user,permission));
+ }
+ }
+
+}
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/Authorizer.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/Authorizer.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/Authorizer.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/Authorizer.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,76 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+import java.security.Principal;
+import java.util.Properties;
+
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiSession;
+
+/**
+ * Interface for service providers of authorization information.
+ * @author Andrew Jaquith
+ * @since 2.3
+ */
+public interface Authorizer
+{
+
+ /**
+ * Returns an array of role Principals this Authorizer knows about.
+ * This method will always return an array; an implementing class may
+ * choose to return an zero-length array if it has no ability to identify
+ * the roles under its control.
+ * @return an array of Principals representing the roles
+ */
+ public Principal[] getRoles();
+
+ /**
+ * Looks up and returns a role Principal matching a given String.
+ * If a matching role cannot be found, this method returns <code>null</code>.
+ * Note that it may not always be feasible for an Authorizer
+ * implementation to return a role Principal.
+ * @param role the name of the role to retrieve
+ * @return the role Principal
+ */
+ public Principal findRole( String role );
+
+ /**
+ * Initializes the authorizer.
+ * @param engine the current wiki engine
+ * @param props the wiki engine initialization properties
+ * @throws WikiSecurityException if the Authorizer could not be initialized
+ */
+ public void initialize( WikiEngine engine, Properties props ) throws WikiSecurityException;
+
+ /**
+ * Determines whether the Subject associated with a WikiSession is in a
+ * particular role. This method takes two parameters: the WikiSession
+ * containing the subject and the desired role ( which may be a Role or a
+ * Group). If either parameter is <code>null</code>, this method must
+ * return <code>false</code>.
+ * @param session the current WikiSession
+ * @param role the role to check
+ * @return <code>true</code> if the user is considered to be in the role,
+ * <code>false</code> otherwise
+ */
+ public boolean isUserInRole( WikiSession session, Principal role );
+
+}
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/GroupPrincipal.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/GroupPrincipal.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/GroupPrincipal.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/GroupPrincipal.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,95 @@
+/*
+ * JSPWiki - a JSP-based WikiWiki clone. Copyright (C) 2001-2003 Janne Jalkanen
+ * (Janne.Jalkanen@iki.fi) This program is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version. This program is distributed
+ * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details. You should have
+ * received a copy of the GNU Lesser General Public License along with this
+ * program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+import java.security.Principal;
+
+/**
+ * Immutable Principal that represents a Group. GroupPrincipals are injected
+ * into a Subject's principal list at the time of authentication (login), and
+ * serve as proxies for Group objects for the purposes of making Java 2 security
+ * policy decisions. We add GroupPrincipals instead of the actual Groups because
+ * calling classes should never be able to obtain a mutable object (Group
+ * memberships can be changed by callers). Administrators who wish to grant
+ * privileges to specific wiki groups via the security policy file should always specify
+ * principals of type GroupPrincipal.
+ * @see com.ecyrd.jspwiki.auth.authorize.Group
+ * @author Andrew Jaquith
+ * @since 2.3.79
+ */
+public final class GroupPrincipal implements Principal
+{
+ private final String m_name;
+
+ /**
+ * Constructs a new GroupPrincipal object with a supplied name.
+ *
+ * @param group the wiki group; cannot be <code>null</code>
+ */
+ public GroupPrincipal( String group )
+ {
+ if ( group == null )
+ {
+ throw new IllegalArgumentException( "Group parameter cannot be null." );
+ }
+ m_name = group;
+ }
+
+ /**
+ * Returns the name of the group principal.
+ * @return the name
+ * @see java.security.Principal#getName()
+ */
+ public final String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Two GroupPrincipals are equal if their names are equal.
+ * @param obj the object to compare
+ * @return the result of the equality test
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public final boolean equals( Object obj )
+ {
+ if ( !( obj instanceof GroupPrincipal ) )
+ {
+ return false;
+ }
+ GroupPrincipal p = (GroupPrincipal)obj;
+ return p.m_name.equals( m_name );
+ }
+
+ /**
+ * Returns the hashcode for this object.
+ * @return the hash code
+ * @see java.lang.Object#hashCode()
+ */
+ public final int hashCode()
+ {
+ return m_name.hashCode();
+ }
+
+ /**
+ * Returns a string representation of this object.
+ * @return the string
+ * @see java.lang.Object#toString()
+ */
+ public final String toString()
+ {
+ return "[GroupPrincipal " + m_name + "]";
+ }
+
+}
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/NoSuchPrincipalException.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/NoSuchPrincipalException.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/NoSuchPrincipalException.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/NoSuchPrincipalException.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,40 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Copyright (C) 2001-2003 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+/**
+ * Thrown in some error situations where a WikiPrincipal object does not exist.
+ * @author Andrew Jaquith
+ * @since 2.3
+ */
+public final class NoSuchPrincipalException
+ extends WikiSecurityException
+{
+ private static final long serialVersionUID = 3257849895976186169L;
+
+ /**
+ * Constructs a new exception object with a supplied message.
+ * @param msg the message
+ */
+ public NoSuchPrincipalException( String msg )
+ {
+ super(msg);
+ }
+}
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PolicyLoader.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PolicyLoader.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PolicyLoader.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PolicyLoader.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,373 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+import java.io.File;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.Security;
+
+import javax.security.auth.login.Configuration;
+
+import org.apache.log4j.Logger;
+
+/**
+ * <p>
+ * Initializes JVM configurations for JAAS and Java 2 security policy. Callers
+ * can use the static methods in this class ({@link #isJaasConfigured()}
+ * and {@link #isSecurityPolicyConfigured()}) to inquire whether a JAAS
+ * login configuration exists, or whether a custom Java security policy is in
+ * use. Additional methods allow callers to set the JAAS and security policy
+ * configurations to supplied URLs ({@link #setJaasConfiguration(URL)}
+ * and {@link #setSecurityPolicy(URL)}).
+ * </p>
+ * <p>
+ * If either the JAAS configuration and security policy are set using methods in
+ * this class, the resulting configuration or policy is <i>global</i> to the
+ * JVM. Thus, in a multi-webapp scenario, this means that the first webapp to be
+ * loaded by the container wins. Thus, for containers hosting multiple wikis,
+ * the administrator will need to manually configure the
+ * <code>java.security.policy</code> and
+ * <code>java.security.auth.login.config properties</code>. In other words,
+ * multi-wiki deployments will always require manual (one-time) configuration.
+ * </p>
+ * <p>
+ * The security policy-related methods {@link #isSecurityPolicyConfigured()}
+ * and {@link #setSecurityPolicy(URL)}) assumes that the web container
+ * doesn't use a "double-equals" command-line assignment
+ * to override the security policy ( <i>e.g. </i>,
+ * <code>-Djava.security.policy==jspwiki.policy</code>). Note that Tomcat 4
+ * and higher, when run using the "-security" option, does this.
+ * </p>
+ * <p>
+ * To interoperate with <i>any</i> container running with a security manager, the
+ * container's JVM security policy should include a short set of permission
+ * grant similar to the following:
+ * </p>
+ * <blockquote><code>keystore "jspwiki.jks";<br/>
+ * ...<br/>
+ * grant signedBy "jspwiki" {<br/>
+ * permission java.security.SecurityPermission, "getPolicy";<br/>
+ * permission java.security.SecurityPermission, "setPolicy";<br/>
+ * permission java.util.PropertyPermission "java.security.auth.login.config", "write";<br/>
+ * permission java.util.PropertyPermission "java.security.policy", "read,write";<br/>
+ * permission javax.security.auth.AuthPermission, "getLoginConfiguration";<br/>
+ * permission javax.security.auth.AuthPermission, "setLoginConfiguration";<br/>
+ * };</code>
+ * </blockquote>
+ * <p>
+ * The <code>signedBy</code> value should match the alias of a digital
+ * certificate in the named keystore ( <i>e.g. </i>, <code>jspwiki.jks</code>).
+ * If the full path to the keystore is not suppled, it is assumed to be in the
+ * same directory as the policy file.
+ * </p>
+ *
+ * @author Andrew Jaquith
+ * @since 2.3
+ */
+public final class PolicyLoader
+{
+ protected static final Logger log = Logger.getLogger( PolicyLoader.class );
+
+ /**
+ * Private constructor to prevent direct instantiation.
+ */
+ private PolicyLoader()
+ {
+ }
+
+ /**
+ * <p>
+ * Returns <code>true</code> if the JAAS login configuration exists.
+ * Normally, JAAS is configured by setting the system property
+ * <code>java.security.auth.login.config</code> at JVM startup.
+ * </p>
+ * <p>
+ * This method attempts to perform a highly privileged operation. If the JVM
+ * runs with a SecurityManager, the following permission must be granted to
+ * the codesource containing this class:
+ * </p>
+ * <code><ul>
+ * <li>permission javax.security.auth.AuthPermission,
+ * "getLoginConfiguration"</li>
+ * </ul></code>
+ *
+ * @return <code>true</code> if
+ * {@link javax.security.auth.login.Configuration#getConfiguration()}
+ * is not <code>null</code> ; <code>false</code> otherwise.
+ * @throws SecurityException if the codesource containing this class posesses
+ * insufficient permmissions when running with a SecurityManager
+ */
+ public static final boolean isJaasConfigured() throws SecurityException
+ {
+ Boolean configured = (Boolean) AccessController
+ .doPrivileged(new PrivilegedAction() {
+
+ public Object run()
+ {
+ boolean isConfigured = false;
+ try
+ {
+ Configuration config = Configuration.getConfiguration();
+ isConfigured = config != null;
+ }
+ catch (SecurityException e) {}
+ return Boolean.valueOf(isConfigured);
+ }
+ });
+ return configured.booleanValue();
+ }
+
+ /**
+ * <p>
+ * Returns <code>true</code> if a custom Java security policy configuration
+ * exists. Normally, the Java security policy is configured by setting the
+ * system property <code>java.security.policy</code> at JVM startup.
+ * </p>
+ * <p>
+ * This method attempts to perform a highly privileged operation. If the JVM
+ * runs with a SecurityManager, the following permission must be granted to
+ * the codesource containing this class:
+ * </p>
+ * <code><ul>
+ * <li>permission java.util.PropertyPermission
+ * "java.security.policy", "read"</li>
+ * </ul></code>
+ *
+ * @return <code>true</code> if the system property
+ * <code>java.security.policy</code> is not <code>null</code>;
+ * <code>false</code> otherwise.
+ * @throws SecurityException if the codesource containing this class posesses
+ * insufficient permmissions when running with a SecurityManager
+ */
+ public static final boolean isSecurityPolicyConfigured() throws SecurityException
+ {
+ String policy = (String) AccessController
+ .doPrivileged(new PrivilegedAction() {
+
+ public Object run()
+ {
+ return System.getProperty("java.security.policy");
+ }
+ });
+
+ if ( policy != null )
+ {
+ log.info( "Java security policy already set to: " + policy + ". (Leaving it alone...)" );
+
+ //
+ // Do a bit of a sanity checks to help people who are not familiar with JAAS.
+ //
+ if( policy.startsWith("file:") ) policy = policy.substring("file:".length());
+
+ File f = new File(policy);
+
+ if( !f.exists() )
+ {
+ log.warn("You have set your 'java.security.policy' to point at '"+f.getAbsolutePath()+"', "+
+ "but that file does not seem to exist. I'll continue anyway, since this may be "+
+ "something specific to your servlet container. Just consider yourself warned." );
+ }
+
+ File jks = new File( f.getParentFile(), "jspwiki.jks" );
+
+ if( !jks.exists() || !jks.canRead() )
+ {
+ log.warn("I could not locate the JSPWiki keystore ('jspwiki.jks') in the same directory "+
+ "as your jspwiki.policy file. On many servlet containers, such as Tomcat, this "+
+ "needs to be done. If you keep having access right permissions, please try "+
+ "copying your WEB-INF/jspwiki.jks to "+f.getParentFile().getAbsolutePath() );
+ }
+ else
+ {
+ log.info("Found 'jspwiki.jks' from '"+f.getParentFile().getAbsolutePath()+"'. If you are having "+
+ "permission issues after an upgrade, please make sure that this file matches the one that "+
+ "came with your distribution archive.");
+ }
+
+ }
+ return policy != null;
+ }
+
+ /**
+ * Sets the JAAS login configuration file, overwriting the existing
+ * configuration. If the configuration file pointed to by the URL does not
+ * exist, a SecurityException is thrown.
+ * <p>
+ * This method attempts to perform several highly privileged operations. If
+ * the JVM runs with a SecurityManager, the following permissions must be
+ * granted to the codesource containing this class:
+ * </p>
+ * <code><ul>
+ * <li>permission java.util.PropertyPermission
+ * "java.security.auth.login.config", "write"</li>
+ * <li>permission javax.security.auth.AuthPermission,
+ * "getLoginConfiguration"</li>
+ * <li>permission javax.security.auth.AuthPermission,
+ * "setLoginConfiguration"</li>
+ * </ul></code>
+ *
+ * @param url the URL of the login configuration file. If the URL contains
+ * properties such as <code>${java.home}</code>, they will be
+ * expanded.
+ * @throws SecurityException if:
+ * <ul>
+ * <li>the supplied URL is <code>null</code></li>
+ * <li>properties cannot be expanded</li>
+ * <li>the codesource containing this class does not posesses
+ * sufficient permmissions when running with a SecurityManager</li>
+ * </ul>
+ */
+ public static final void setJaasConfiguration(final URL url)
+ throws SecurityException
+ {
+ if (url == null)
+ {
+ throw new SecurityException("URL for JAAS configuration cannot be null.");
+ }
+
+ // Get JAAS configuration class; default is Sun provider
+ String defaultConfigClass;
+ defaultConfigClass = (String)AccessController.doPrivileged(
+ new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return Security.getProperty("login.configuration.provider");
+ }
+ });
+
+ if (defaultConfigClass == null)
+ {
+ defaultConfigClass = "com.sun.security.auth.login.ConfigFile";
+ }
+
+ // Now, set the new config
+ final String config_class = defaultConfigClass;
+ AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run()
+ {
+ // Remove old policy, then set our config URL and instantiate new instance
+ try
+ {
+ Configuration.setConfiguration(null);
+ System.setProperty("java.security.auth.login.config", url.toExternalForm());
+ Configuration config = (Configuration)Class.forName(config_class).newInstance();
+ Configuration.setConfiguration(config);
+ return null;
+ }
+ catch (Exception e)
+ {
+ throw new SecurityException(e.getMessage());
+ }
+ }
+ });
+ }
+
+ /**
+ * <p>
+ * Sets the Java security policy, overwriting any custom policy settings. This
+ * method sets the value of the system property
+ * <code>java.security.policy</code> to the supplied URL, then calls
+ * {@link java.security.Policy#setPolicy(java.security.Policy)} with a
+ * newly-instantiated instance of
+ * <code>sun.security.provider.PolicyFile</code> (the J2SE default
+ * implementation). The new Policy, once set, reloads the default system
+ * policies enumerated by the <code>policy.url.<i>n</i></code> entries in
+ * <code><i>JAVA_HOME</i>/lib/security/java.policy</code>, followed by the
+ * user-supplied policy file.
+ * </p>
+ * <p>
+ * This method attempts to perform several highly privileged operations. If
+ * the JVM runs with a SecurityManager, the following permissions must be
+ * granted to the codesource containing this class:
+ * </p>
+ * <code><ul>
+ * <li>permission java.security.SecurityPermission, "getPolicy"
+ * </li>
+ * <li>permission java.security.SecurityPermission, "setPolicy"
+ * </li>
+ * <li>permission java.util.PropertyPermission}
+ * "java.security.policy", "write"</li>
+ * </ul></code>
+ *
+ * @param url the URL of the security policy file. If the URL contains
+ * properties such as <code>${java.home}</code>, they will be
+ * expanded.
+ * @throws SecurityException if:
+ * <ul>
+ * <li>the supplied URL is <code>null</code></li>
+ * <li>properties cannot be expanded</li>
+ * <li>the codesource containing this class does not posesses
+ * sufficient permmissions when running with a SecurityManager</li>
+ * <li>the JVM's current Policy implementation is not of type
+ * <code>sun.security.provider.PolicyFile</code></li>
+ * </ul>
+ */
+ public static final void setSecurityPolicy(final URL url) throws SecurityException
+ {
+ if (url == null)
+ {
+ throw new SecurityException("URL for security policy cannot be null.");
+ }
+
+ // Get policy class; default is Sun provider
+ String defaultPolicyClass;
+ defaultPolicyClass = (String)AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Object run()
+ {
+ return Security.getProperty("policy.provider");
+ }
+ });
+
+ if (defaultPolicyClass == null)
+ {
+ defaultPolicyClass = "sun.security.provider.PolicyFile";
+ }
+
+ // Now, set the new policy
+ final String policyClass = defaultPolicyClass;
+ AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run()
+ {
+ // Remove old policy, then set our policy URL and instantiate new instance
+ try
+ {
+ Policy.setPolicy(null);
+ System.setProperty("java.security.policy", url.toExternalForm());
+
+ Policy policy = (Policy)Class.forName(policyClass).newInstance();
+ Policy.setPolicy(policy);
+ return null;
+ }
+ catch (Exception e)
+ {
+ throw new SecurityException(e.getMessage());
+ }
+ }
+ });
+ }
+
+}
Propchange: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PolicyLoader.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PrincipalComparator.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PrincipalComparator.java?rev=627255&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PrincipalComparator.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/PrincipalComparator.java Tue Feb 12 21:53:55 2008
@@ -0,0 +1,50 @@
+/*
+ JSPWiki - a JSP-based WikiWiki clone.
+
+ Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package com.ecyrd.jspwiki.auth;
+
+import java.io.Serializable;
+import java.security.Principal;
+import java.text.Collator;
+import java.util.Comparator;
+
+/**
+ * Comparator class for sorting objects of type Principal.
+ * Used for sorting arrays or collections of Principals.
+ * @since 2.3
+ */
+public class PrincipalComparator
+ implements Comparator<Principal>, Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Compares two Principal objects.
+ * @param o1 the first Principal
+ * @param o2 the second Principal
+ * @return the result of the comparison
+ * @see java.util.Comparator#compare(Object, Object)
+ */
+ public int compare( Principal o1, Principal o2 )
+ {
+ Collator collator = Collator.getInstance();
+ return collator.compare( o1.getName(), o2.getName() );
+ }
+
+}