Return-Path: Delivered-To: apmail-incubator-jspwiki-commits-archive@locus.apache.org Received: (qmail 87588 invoked from network); 13 Feb 2008 05:56:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 13 Feb 2008 05:56:20 -0000 Received: (qmail 41889 invoked by uid 500); 13 Feb 2008 05:56:13 -0000 Delivered-To: apmail-incubator-jspwiki-commits-archive@incubator.apache.org Received: (qmail 41880 invoked by uid 500); 13 Feb 2008 05:56:13 -0000 Mailing-List: contact jspwiki-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: jspwiki-dev@incubator.apache.org Delivered-To: mailing list jspwiki-commits@incubator.apache.org Received: (qmail 41871 invoked by uid 99); 13 Feb 2008 05:56:13 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 12 Feb 2008 21:56:13 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 13 Feb 2008 05:55:34 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 73B761A986A; Tue, 12 Feb 2008 21:55:19 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r627255 [13/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... Date: Wed, 13 Feb 2008 05:54:24 -0000 To: jspwiki-commits@incubator.apache.org From: ajaquith@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080213055519.73B761A986A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiPrincipal.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiPrincipal.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiPrincipal.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiPrincipal.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,155 @@ +/* + JSPWiki - a JSP-based WikiWiki clone. + + Copyright (C) 2001-2004 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.Comparator; + +/** + * A lightweight, immutable Principal class. WikiPrincipals can be created with + * and optional "type" to denote what type of user profile Principal it represents + * (FULL_NAME, WIKI_NAME, LOGIN_NAME). Types are used to determine suitable + * user and login Principals in classes like WikiSession. However, the type + * property of a WikiPrincipal does not affect a WikiPrincipal's logical equality + * or hash code; two WikiPrincipals with the same name but different types are still + * considered equal. + * + * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.2 + */ +public final class WikiPrincipal implements Principal +{ + + /** + * Represents an anonymous user. WikiPrincipals may be + * created with an optional type designator: + * LOGIN_NAME, WIKI_NAME, FULL_NAME or UNSPECIFIED. + */ + public static final Principal GUEST = new WikiPrincipal( "Guest" ); + + /** WikiPrincipal type denoting a user's full name. */ + public static final String FULL_NAME = "fullName"; + + /** WikiPrincipal type denoting a user's login name. */ + public static final String LOGIN_NAME = "loginName"; + + /** WikiPrincipal type denoting a user's wiki name. */ + public static final String WIKI_NAME = "wikiName"; + + /** Generic WikiPrincipal of unspecified type. */ + public static final String UNSPECIFIED = "unspecified"; + + /** Static instance of Comparator that allows Principals to be sorted. */ + public static final Comparator COMPARATOR = new PrincipalComparator(); + + private final String m_name; + private final String m_type; + + /** + * Constructs a new WikiPrincipal with a given name and a type of + * {@link #UNSPECIFIED}. + * @param name the name of the Principal + */ + public WikiPrincipal( String name ) + { + this( name, UNSPECIFIED ); + } + + /** + * Constructs a new WikiPrincipal with a given name and optional type + * designator. If the supplied type parameter is not + * {@link #LOGIN_NAME}, {@link #FULL_NAME}, {@link #WIKI_NAME} + * or {@link #WIKI_NAME}, this method throws + * an {@link IllegalArgumentException}. + * @param name the name of the Principal + * @param type the type for this principal, which may be {@link #LOGIN_NAME}, + * {@link #FULL_NAME}, {@link #WIKI_NAME} or {@link #WIKI_NAME}. + */ + public WikiPrincipal( String name, String type ) + { + if ( name == null ) + { + throw new IllegalArgumentException( "Name cannot be null" ); + } + m_name = name; + if ( !FULL_NAME.equals(type) && !LOGIN_NAME.equals(type) && + !WIKI_NAME.equals(type) && !UNSPECIFIED.equals(type) ) + { + throw new IllegalArgumentException( "Principal type '" + type + "' is invalid."); + } + m_type = type; + } + + /** + * Returns the wiki name of the Principal. + * @return the name + */ + public final String getName() + { + return m_name; + } + + /** + * Two WikiPrincipals are considered equal if their + * names are equal (case-sensitive). + * @param obj the object to compare + * @return the result of the equality test + */ + public final boolean equals( Object obj ) + { + if ( obj == null || !( obj instanceof WikiPrincipal ) ) + { + return false; + } + return m_name.equals( ( (WikiPrincipal) obj ).getName() ); + } + + /** + * The hashCode() returned for the WikiPrincipal is the same as + * for its name. + * @return the hash code + */ + public final int hashCode() + { + return m_name.hashCode(); + } + + /** + * Returns the Principal "type": {@link #LOGIN_NAME}, {@link #FULL_NAME}, + * {@link #WIKI_NAME} or {@link #WIKI_NAME} + * @return the type + */ + public final String getType() + { + return m_type; + } + + /** + * Returns a human-readable representation of the object. + * @return the string representation + */ + public final String toString() + { + return "[WikiPrincipal (" + m_type + "): " + getName() + "]"; + } + + +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,44 @@ +/* + JSPWiki - a JSP-based WikiWiki clone. + + Copyright (C) 2001-2002 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 com.ecyrd.jspwiki.WikiException; + +/** + * Indicates an authentication or authorization + * error or exception. + * + * @author Erik Bunn + * @since 2.0 + */ +public class WikiSecurityException + extends WikiException +{ + private static final long serialVersionUID = 3617293441285764405L; + + /** + * Constructs an exception. + * @param msg the message to supply to the exception + */ + public WikiSecurityException( String msg ) + { + super(msg); + } +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/Acl.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/Acl.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/Acl.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/Acl.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,117 @@ +/* + JSPWiki - a JSP-based WikiWiki clone. + + Copyright (C) 2001-2002 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.acl; + +import java.security.Permission; +import java.security.Principal; +import java.util.Enumeration; + +/** + *

+ * Defines an access control list (ACL) for wiki pages. An Access Control List + * is a data structure used to guard access to resources. An ACL can be thought + * of as a data structure with multiple ACL entries. Each ACL entry, of + * interface type AclEntry, contains a set of positive permissions associated + * with a particular principal. (A principal represents an entity such as an + * individual user or a group). The ACL Entries in each ACL observe the + * following rules: + *

+ *
    + *
  • Each principal can have at most one ACL entry; that is, multiple ACL + * entries are not allowed for any principal. Each entry specifies the set of + * permissions that are to be granted
  • + *
  • If there is no entry for a particular principal, then the principal is + * considered to have a null (empty) permission set
  • + *
+ *

+ * This interface is a highly stripped-down derivation of the + * java.security.acl.Acl interface. In particular, the notion of an Acl "owner" + * has been eliminated, since JWPWiki pages do not have owners. An additional + * simplification compared to the standard Java package is that negative + * permissions have been eliminated. Instead, JSPWiki assumes a "default-deny" + * security stance: principals are granted no permissions by default, and + * posesses only those that have been explicitly granted to them. And finally, + * the getPermissions() and checkPermission() methods have been eliminated due + * to the complexities associated with resolving Role principal membership. + *

+ * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.3 + */ +public interface Acl +{ + /** + * Adds an ACL entry to this ACL. An entry associates a principal (e.g., an + * individual or a group) with a set of permissions. Each principal can have + * at most one positive ACL entry, specifying permissions to be granted to + * the principal. If there is already an ACL entry already in the ACL, false + * is returned. + * @param entry - the ACL entry to be added to this ACL + * @return true on success, false if an entry of the same type (positive or + * negative) for the same principal is already present in this ACL + */ + public boolean addEntry( AclEntry entry ); + + /** + * Returns an enumeration of the entries in this ACL. Each element in the + * enumeration is of type AclEntry. + * @return an enumeration of the entries in this ACL. + */ + public Enumeration entries(); + + /** + * Returns true, if this Acl is empty. + * @return the result + * @since 2.4.68 + */ + public boolean isEmpty(); + + /** + * Returns all Principal objects assigned a given Permission in the access + * control list. The Princiapls returned are those that have been granted + * either the supplied permission, or a permission implied by the supplied + * permission. Principals are not "expanded" if they are a role or group. + * @param permission the permission to search for + * @return an array of Principals posessing the permission + */ + public Principal[] findPrincipals( Permission permission ); + + /** + * Returns an AclEntry for a supplied Principal, or null if + * the Principal does not have a matching AclEntry. + * @param principal the principal to search for + * @return the AclEntry associated with the principal, or null + */ + public AclEntry getEntry( Principal principal ); + + /** + * Removes an ACL entry from this ACL. + * @param entry the ACL entry to be removed from this ACL + * @return true on success, false if the entry is not part of this ACL + */ + public boolean removeEntry( AclEntry entry ); + + /** + * Returns a string representation of the contents of this Acl. + * @return the string representation + */ + public String toString(); + +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntry.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntry.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntry.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntry.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,108 @@ +/* + 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.acl; + +import java.security.Permission; +import java.security.Principal; +import java.util.Enumeration; + +/** + *

+ * Represents one entry in an Access Control List (ACL). + *

+ *

+ * An ACL can be thought of as a data structure with multiple ACL entry objects. + * Each ACL entry object contains a set of positive page permissions associated + * with a particular principal. (A principal represents an entity such as an + * individual user, group, or role). Each principal can have at most one ACL + * entry; that is, multiple ACL entries are not allowed for any principal. + *

+ *

+ * This interface is functionally equivalent to the java.security.acl.AclEntry + * interface, minus negative permissions. + *

+ * @see Acl + * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.3 + */ +public interface AclEntry +{ + + /** + * Adds the specified permission to this ACL entry. The permission + * must be of type + * {@link com.ecyrd.jspwiki.auth.permissions.PagePermission}. Note: An entry + * can have multiple permissions. + * @param permission the permission to be associated with the principal in + * this entry + * @return true if the permission was added, + * false if the permission was + * already part of this entry's permission set, and false if + * the permission is not of type PagePermission + */ + public boolean addPermission(Permission permission); + + /** + * Checks if the specified permission is part of the permission set in this + * entry. + * @param permission the permission to be checked for. + * @return true if the permission is part of the permission set in this entry, + * false otherwise. + */ + public boolean checkPermission(Permission permission); + + /** + * Returns the principal for which permissions are granted by this + * ACL entry. Returns null if there is no principal set for this entry yet. + * @return the principal associated with this entry. + */ + public Principal getPrincipal(); + + /** + * Returns an enumeration of the permissions in this ACL entry. + * @return an enumeration of the permissions + */ + public Enumeration permissions(); + + /** + * Removes the specified permission from this ACL entry. + * @param permission the permission to be removed from this entry. + * @return true if the permission is removed, false if the permission was not + * part of this entry's permission set. + */ + public boolean removePermission(Permission permission); + + /** + * Specifies the principal for which permissions are granted or denied by + * this ACL entry. If a principal was already set for this ACL entry, false + * is returned, otherwise true is returned. + * @param user the principal to be set for this entry + * @return true if the principal is set, false if there was already a + * principal set for this entry + */ + public boolean setPrincipal(Principal user); + + /** + * Returns a string representation of the contents of this ACL entry. + * @return a string representation of the contents. + */ + public String toString(); +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntryImpl.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntryImpl.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntryImpl.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclEntryImpl.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,185 @@ +/* + 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.acl; + +import java.security.Permission; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Vector; + +import com.ecyrd.jspwiki.auth.permissions.PagePermission; + +/** + * Implementation of a JSPWiki AclEntry. + * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.3 + */ +public class AclEntryImpl implements AclEntry +{ + + private Vector m_permissions = new Vector(); + private Principal m_principal; + + /** + * Constructs a new AclEntryImpl instance. + */ + public AclEntryImpl() + { + } + + /** + * Adds the specified permission to this ACL entry. The permission + * must be of type + * {@link com.ecyrd.jspwiki.auth.permissions.PagePermission}. Note: An entry + * can have multiple permissions. + * @param permission the permission to be associated with the principal in + * this entry + * @return true if the permission was added, + * false if the permission was + * already part of this entry's permission set, and false if + * the permission is not of type PagePermission + */ + public synchronized boolean addPermission( Permission permission ) + { + if ( permission instanceof PagePermission && findPermission( permission ) == null ) + { + m_permissions.add( permission ); + return true; + } + + return false; + } + + /** + * Checks if the specified permission is part of the permission set in this + * entry. + * @param permission the permission to be checked for. + * @return true if the permission is part of the permission set in this entry, + * false otherwise. + */ + public boolean checkPermission( Permission permission ) + { + return findPermission( permission ) != null; + } + + /** + * Returns the principal for which permissions are granted by this + * ACL entry. Returns null if there is no principal set for this entry yet. + * @return the principal associated with this entry. + */ + public synchronized Principal getPrincipal() + { + return m_principal; + } + + /** + * Returns an enumeration of the permissions in this ACL entry. + * @return an enumeration of the permissions + */ + public Enumeration permissions() + { + return m_permissions.elements(); + } + + /** + * Removes the specified permission from this ACL entry. + * @param permission the permission to be removed from this entry. + * @return true if the permission is removed, false if the permission was not + * part of this entry's permission set. + */ + public synchronized boolean removePermission( Permission permission ) + { + Permission p = findPermission( permission ); + + if ( p != null ) + { + m_permissions.remove( p ); + return true; + } + + return false; + } + + /** + * Specifies the principal for which permissions are granted or denied by + * this ACL entry. If a principal was already set for this ACL entry, false + * is returned, otherwise true is returned. + * @param user the principal to be set for this entry + * @return true if the principal is set, false if there was already a + * principal set for this entry + */ + public synchronized boolean setPrincipal( Principal user ) + { + if ( m_principal != null || user == null ) + return false; + + m_principal = user; + + return true; + } + + /** + * Returns a string representation of the contents of this ACL entry. + * @return a string representation of the contents. + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + + Principal p = getPrincipal(); + + sb.append( "[AclEntry ALLOW " + ( p != null ? p.getName() : "null" ) ); + sb.append( " " ); + + for( Iterator i = m_permissions.iterator(); i.hasNext(); ) + { + Permission pp = (Permission) i.next(); + + sb.append( pp.toString() ); + sb.append( "," ); + } + + sb.append( "]" ); + + return sb.toString(); + } + + /** + * Looks through the permission list and finds a permission that matches the + * permission. + */ + private Permission findPermission( Permission p ) + { + for( Iterator i = m_permissions.iterator(); i.hasNext(); ) + { + Permission pp = (Permission) i.next(); + + if ( pp.implies( p ) ) + { + return pp; + } + } + + return null; + } +} + Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclImpl.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclImpl.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclImpl.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclImpl.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,212 @@ +/* + JSPWiki - a JSP-based WikiWiki clone. + + Copyright (C) 2001-2004 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.acl; + +import java.security.Permission; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Vector; + +/** + * JSPWiki implementation of an Access Control List. + * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.3 + */ +public class AclImpl implements Acl +{ + private final Vector m_entries = new Vector(); + + /** + * Constructs a new AclImpl instance. + */ + public AclImpl() + { + } + + /** + * Returns all Principal objects assigned a given Permission in the access + * control list. The Princiapls returned are those that have been granted + * either the supplied permission, or a permission implied by the supplied + * permission. Principals are not "expanded" if they are a role or group. + * @param permission the permission to search for + * @return an array of Principals posessing the permission + */ + public Principal[] findPrincipals( Permission permission ) + { + Vector principals = new Vector(); + Enumeration entries = entries(); + + while (entries.hasMoreElements()) + { + AclEntry entry = (AclEntry)entries.nextElement(); + Enumeration permissions = entry.permissions(); + while ( permissions.hasMoreElements() ) + { + Permission perm = (Permission)permissions.nextElement(); + if ( perm.implies( permission ) ) + { + principals.add( entry.getPrincipal() ); + } + } + } + return principals.toArray( new Principal[principals.size()] ); + } + + private boolean hasEntry( AclEntry entry ) + { + if( entry == null ) + { + return false; + } + + for( Iterator i = m_entries.iterator(); i.hasNext(); ) + { + AclEntry e = (AclEntry) i.next(); + + Principal ep = e.getPrincipal(); + Principal entryp = entry.getPrincipal(); + + if( ep == null || entryp == null ) + { + throw new IllegalArgumentException( "Entry is null; check code, please (entry="+entry+"; e="+e+")" ); + } + + if( ep.getName().equals( entryp.getName() ) ) + { + return true; + } + } + + return false; + } + + /** + * Adds an ACL entry to this ACL. An entry associates a principal (e.g., an + * individual or a group) with a set of permissions. Each principal can have + * at most one positive ACL entry, specifying permissions to be granted to + * the principal. If there is already an ACL entry already in the ACL, false + * is returned. + * @param entry - the ACL entry to be added to this ACL + * @return true on success, false if an entry of the same type (positive or + * negative) for the same principal is already present in this ACL + */ + public synchronized boolean addEntry( AclEntry entry ) + { + if( entry.getPrincipal() == null ) + { + throw new IllegalArgumentException( "Entry principal cannot be null" ); + } + + if( hasEntry( entry ) ) + { + return false; + } + + m_entries.add( entry ); + + return true; + } + + /** + * Removes an ACL entry from this ACL. + * @param entry the ACL entry to be removed from this ACL + * @return true on success, false if the entry is not part of this ACL + */ + public synchronized boolean removeEntry( AclEntry entry ) + { + return m_entries.remove( entry ); + } + + /** + * Returns an enumeration of the entries in this ACL. Each element in the + * enumeration is of type AclEntry. + * @return an enumeration of the entries in this ACL. + */ + public Enumeration entries() + { + return m_entries.elements(); + } + + /** + * Returns an AclEntry for a supplied Principal, or null if + * the Principal does not have a matching AclEntry. + * @param principal the principal to search for + * @return the AclEntry associated with the principal, or null + */ + public AclEntry getEntry( Principal principal ) + { + for( Enumeration e = m_entries.elements(); e.hasMoreElements(); ) + { + AclEntry entry = (AclEntry) e.nextElement(); + + if( entry.getPrincipal().getName().equals( principal.getName() ) ) + { + return entry; + } + } + + return null; + } + + /** + * Returns a string representation of the contents of this Acl. + * @return the string representation + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + + for( Enumeration myEnum = entries(); myEnum.hasMoreElements(); ) + { + AclEntry entry = (AclEntry) myEnum.nextElement(); + + Principal pal = entry.getPrincipal(); + + if( pal != null ) + sb.append( " user = "+pal.getName()+": " ); + else + sb.append( " user = null: " ); + + sb.append( "(" ); + for( Enumeration perms = entry.permissions(); perms.hasMoreElements(); ) + { + Permission perm = (Permission) perms.nextElement(); + sb.append( perm.toString() ); + } + sb.append( ")\n" ); + } + + return sb.toString(); + } + + /** + * Returns true, if this Acl is empty. + * @return the result + * @since 2.4.68 + */ + public boolean isEmpty() + { + return m_entries.isEmpty(); + } + +} + Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclManager.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclManager.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclManager.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/AclManager.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,77 @@ +/* + 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.acl; + +import java.util.Properties; + +import com.ecyrd.jspwiki.WikiEngine; +import com.ecyrd.jspwiki.WikiPage; +import com.ecyrd.jspwiki.auth.WikiSecurityException; + +/** + * Specifies how to parse and return ACLs from wiki pages. + * @author Andrew Jaquith + * @since 2.3 + */ +public interface AclManager +{ + + /** + * Initializes the AclManager with a supplied wiki engine and properties. + * @param engine the wiki engine + * @param props the initialization properties + */ + public void initialize( WikiEngine engine, Properties props ); + + /** + * A helper method for parsing textual AccessControlLists. The line is in + * form "(ALLOW) , , ". This + * method was moved from Authorizer. + * @param page The current wiki page. If the page already has an ACL, it + * will be used as a basis for this ACL in order to avoid the + * creation of a new one. + * @param ruleLine The rule line, as described above. + * @return A valid Access Control List. May be empty. + * @throws WikiSecurityException if the ruleLine was faulty somehow. + * @since 2.1.121 + */ + public Acl parseAcl( WikiPage page, String ruleLine ) throws WikiSecurityException; + + /** + * Returns the access control list for the page. + * If the ACL has not been parsed yet, it is done + * on-the-fly. If the page has a parent page, then that is tried also. + * This method was moved from Authorizer; + * it was consolidated with some code from AuthorizationManager. + * @param page the wiki page + * @since 2.2.121 + * @return the Acl representing permissions for the page + */ + public Acl getPermissions( WikiPage page ); + + /** + * Sets the access control list for the page and persists it. + * @param page the wiki page + * @param acl the access control list + * @since 2.5 + * @throws WikiSecurityException if the ACL cannot be set or persisted + */ + public void setPermissions( WikiPage page, Acl acl ) throws WikiSecurityException; +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/DefaultAclManager.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/DefaultAclManager.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/DefaultAclManager.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/DefaultAclManager.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,299 @@ +/* + 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.acl; + +import java.security.Permission; +import java.security.Principal; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Logger; + +import com.ecyrd.jspwiki.*; +import com.ecyrd.jspwiki.attachment.Attachment; +import com.ecyrd.jspwiki.auth.AuthorizationManager; +import com.ecyrd.jspwiki.auth.PrincipalComparator; +import com.ecyrd.jspwiki.auth.WikiSecurityException; +import com.ecyrd.jspwiki.auth.permissions.PagePermission; +import com.ecyrd.jspwiki.auth.permissions.PermissionFactory; +import com.ecyrd.jspwiki.providers.ProviderException; +import com.ecyrd.jspwiki.render.RenderingManager; + +/** + * Default implementation that parses Acls from wiki page markup. + * @author Andrew Jaquith + * @since 2.3 + */ +public class DefaultAclManager implements AclManager +{ + static Logger log = Logger.getLogger( DefaultAclManager.class ); + + private AuthorizationManager m_auth = null; + private WikiEngine m_engine = null; + private static final String PERM_REGEX = "(" + + PagePermission.COMMENT_ACTION + "|" + + PagePermission.DELETE_ACTION + "|" + + PagePermission.EDIT_ACTION + "|" + + PagePermission.MODIFY_ACTION + "|" + + PagePermission.RENAME_ACTION + "|" + + PagePermission.UPLOAD_ACTION + "|" + + PagePermission.VIEW_ACTION + ")"; + private static final String ACL_REGEX = "\\[\\{\\s*ALLOW\\s+" + PERM_REGEX + "\\s*(.*?)\\s*\\}\\]"; + + /** + * Identifies ACL strings in wiki text; the first group is the action (view, edit) and + * the second is the list of Principals separated by commas. The overall match is + * the ACL string from [{ to }]. + * */ + public static final Pattern ACL_PATTERN = Pattern.compile( ACL_REGEX ); + + /** + * Initializes the AclManager with a supplied wiki engine and properties. + * @param engine the wiki engine + * @param props the initialization properties + * @see com.ecyrd.jspwiki.auth.acl.AclManager#initialize(com.ecyrd.jspwiki.WikiEngine, + * java.util.Properties) + */ + public void initialize( WikiEngine engine, Properties props ) + { + m_auth = engine.getAuthorizationManager(); + m_engine = engine; + } + + /** + * A helper method for parsing textual AccessControlLists. The line is in + * form "ALLOW , , ". This + * method was moved from Authorizer. + * @param page The current wiki page. If the page already has an ACL, it + * will be used as a basis for this ACL in order to avoid the + * creation of a new one. + * @param ruleLine The rule line, as described above. + * @return A valid Access Control List. May be empty. + * @throws WikiSecurityException if the ruleLine was faulty somehow. + * @since 2.1.121 + */ + public Acl parseAcl( WikiPage page, String ruleLine ) throws WikiSecurityException + { + Acl acl = page.getAcl(); + if ( acl == null ) + acl = new AclImpl(); + + try + { + StringTokenizer fieldToks = new StringTokenizer( ruleLine ); + fieldToks.nextToken(); + String actions = fieldToks.nextToken(); + page.getName(); + + while( fieldToks.hasMoreTokens() ) + { + String principalName = fieldToks.nextToken( "," ).trim(); + Principal principal = m_auth.resolvePrincipal( principalName ); + AclEntry oldEntry = acl.getEntry( principal ); + + if ( oldEntry != null ) + { + log.debug( "Adding to old acl list: " + principal + ", " + actions ); + oldEntry.addPermission( PermissionFactory.getPagePermission( page, actions ) ); + } + else + { + log.debug( "Adding new acl entry for " + actions ); + AclEntry entry = new AclEntryImpl(); + + entry.setPrincipal( principal ); + entry.addPermission( PermissionFactory.getPagePermission( page, actions ) ); + + acl.addEntry( entry ); + } + } + + page.setAcl( acl ); + + log.debug( acl.toString() ); + } + catch( NoSuchElementException nsee ) + { + log.warn( "Invalid access rule: " + ruleLine + " - defaults will be used." ); + throw new WikiSecurityException( "Invalid access rule: " + ruleLine ); + } + catch( IllegalArgumentException iae ) + { + throw new WikiSecurityException( "Invalid permission type: " + ruleLine ); + } + + return acl; + } + + + /** + * Returns the access control list for the page. + * If the ACL has not been parsed yet, it is done + * on-the-fly. If the page has a parent page, then that is tried also. + * This method was moved from Authorizer; + * it was consolidated with some code from AuthorizationManager. + * This method is guaranteed to return a non-null Acl. + * @param page the page + * @since 2.2.121 + * @return the Acl representing permissions for the page + */ + public Acl getPermissions( WikiPage page ) + { + // + // Does the page already have cached ACLs? + // + Acl acl = page.getAcl(); + log.debug( "page="+page.getName()+"\n"+acl ); + + if( acl == null ) + { + // + // If null, try the parent. + // + if( page instanceof Attachment ) + { + WikiPage parent = m_engine.getPage( ((Attachment)page).getParentName() ); + + acl = getPermissions( parent ); + } + else + { + // + // Or, try parsing the page + // + WikiContext ctx = m_engine.getWikiActionBeanFactory().newViewActionBean( page ); + + ctx.setVariable( RenderingManager.VAR_EXECUTE_PLUGINS, Boolean.FALSE ); + + m_engine.getHTML( ctx, page ); + + page = m_engine.getPage( page.getName(), page.getVersion() ); + acl = page.getAcl(); + + if( acl == null ) + { + acl = new AclImpl(); + page.setAcl( acl ); + } + } + } + + return acl; + } + + /** + * Sets the access control list for the page and persists it by prepending + * it to the wiki page markup and saving the page. When this method is + * called, all other ACL markup in the page is removed. This method will forcibly + * expire locks on the wiki page if they exist. Any ProviderExceptions will be + * re-thrown as WikiSecurityExceptions. + * @param page the wiki page + * @param acl the access control list + * @since 2.5 + * @throws WikiSecurityException of the Acl cannot be set + */ + public void setPermissions( WikiPage page, Acl acl ) throws WikiSecurityException + { + PageManager pageManager = m_engine.getPageManager(); + + // Forcibly expire any page locks + PageLock lock = pageManager.getCurrentLock( page ); + if ( lock != null ) + { + pageManager.unlockPage( lock ); + } + + // Remove all of the existing ACLs. + String pageText = m_engine.getPureText( page ); + Matcher matcher = DefaultAclManager.ACL_PATTERN.matcher( pageText ); + String cleansedText = matcher.replaceAll( "" ); + String newText = DefaultAclManager.printAcl( page.getAcl() ) + cleansedText; + try + { + pageManager.putPageText( page, newText ); + } + catch ( ProviderException e ) + { + throw new WikiSecurityException( "Could not set Acl. Reason: ProviderExcpetion " + e.getMessage() ); + } + } + + /** + * Generates an ACL string for inclusion in a wiki page, based on a supplied Acl object. + * All of the permissions in this Acl are assumed to apply to the same page scope. + * The names of the pages are ignored; only the actions and principals matter. + * @param acl the ACL + * @return the ACL string + */ + protected static String printAcl( Acl acl ) + { + // Extract the ACL entries into a Map with keys == permissions, values == principals + Map> permissionPrincipals = new TreeMap>(); + Enumeration entries = acl.entries(); + while ( entries.hasMoreElements() ) + { + AclEntry entry = (AclEntry)entries.nextElement(); + Principal principal = entry.getPrincipal(); + Enumeration permissions = entry.permissions(); + while ( permissions.hasMoreElements() ) + { + Permission permission = (Permission)permissions.nextElement(); + List principals = permissionPrincipals.get( permission.getActions() ); + if ( principals == null ) + { + principals = new ArrayList(); + String action = permission.getActions(); + if ( action.indexOf(',') != -1 ) + { + throw new IllegalStateException( "AclEntry permission cannot have multiple targets." ); + } + permissionPrincipals.put( action, principals ); + } + principals.add( principal ); + } + } + + // Now, iterate through each permission in the map and generate an ACL string + + StringBuffer s = new StringBuffer(); + for ( Map.Entry> entry : permissionPrincipals.entrySet() ) + { + String action = entry.getKey(); + List principals = entry.getValue(); + Collections.sort( principals, new PrincipalComparator() ); + s.append( "[{ALLOW "); + s.append( action ); + s.append( " "); + for ( int i = 0; i < principals.size(); i++ ) + { + Principal principal = principals.get( i ); + s.append( principal.getName() ); + if ( i < ( principals.size() - 1 ) ) + { + s.append(","); + } + } + s.append( "}]\n"); + } + return s.toString(); + } + +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/UnresolvedPrincipal.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/UnresolvedPrincipal.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/UnresolvedPrincipal.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/acl/UnresolvedPrincipal.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,94 @@ +/* + 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.acl; + +import java.security.Principal; + +/** + * Represents a Principal, typically read from an ACL, that cannot + * be resolved based on the current state of the user database, group + * manager, and built-in role definitions. + * Creating a principal marked "unresolved" allows + * delayed resolution, which enables principals to be resolved + * lazily during a later access control check. Conceptuallly, + * UnresolvedPrincipal performs a function similar to + * {@link java.security.UnresolvedPermission}. + * + * @author Andrew Jaquith + * @since 2.3 + */ +public final class UnresolvedPrincipal implements Principal +{ + + private final String m_name; + + /** + * Constructs a new UnresolvedPrincipal instance. + * @param name the name of the Principal + */ + public UnresolvedPrincipal( String name ) + { + m_name = name; + } + + /** + * Returns the name of the principal. + * @return the name + * @see java.security.Principal#getName() + */ + public final String getName() + { + return m_name; + } + + /** + * Returns a String representation of the UnresolvedPrincipal. + * @return the String + */ + public final String toString() + { + return "[UnresolvedPrincipal: " + m_name + "]"; + } + + /** + * An unresolved principal is equal to another + * unresolved principal if their names match. + * @param obj the object to compare to this one + * @return the result of the equality test + * @see java.lang.Object#equals(java.lang.Object) + */ + public final boolean equals( Object obj ) + { + if ( obj instanceof UnresolvedPrincipal ) + { + return m_name.equals( ( (UnresolvedPrincipal) obj ).m_name ); + } + return false; + } + + /** + * The hashCode of this object is equal to the hash code of its name. + * @return the hash code + */ + public final int hashCode() + { + return m_name.hashCode(); + } +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/Group.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/Group.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/Group.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/Group.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,358 @@ +/* + * 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.authorize; + +import java.security.Principal; +import java.util.*; + +import com.ecyrd.jspwiki.auth.GroupPrincipal; + +/** + *

+ * Groups are a specialized type of ad-hoc role used by the wiki system. Unlike + * externally-provided roles (such as those provided by an LDAP server or web + * container), JSPWiki groups can be created dynamically by wiki users, without + * requiring special container privileges or administrator intervention. They + * are designed to provide a lightweight role-based access control system that + * complements existing role systems. + *

+ *

+ * Group names are case-insensitive, and have a few naming restrictions, which + * are enforced by the {@link GroupManager}: + *

+ *
    + *
  • Groups cannot have the same name as a built-in Role (e.g., "Admin", + * "Authenticated" etc.)
  • + *
  • Groups cannot have the same name as an existing user
  • + *
+ *

+ * Note: prior to JSPWiki 2.4.19, Group was an interface; it + * is now a concrete, final class. + *

+ *

+ * Groups are related to {@link GroupPrincipal}s. A GroupPrincipal, when + * injected into the Principal set of a WikiSession's Subject, means that the + * user is a member of a Group of the same name -- it is, in essence, an + * "authorization token." GroupPrincipals, unlike Groups, are thread-safe, + * lightweight and immutable. That's why we use them in Subjects rather than the + * Groups themselves. + *

+ * @author Janne Jalkanen + * @author Andrew Jaquith + * @since 2.3 + */ +public class Group +{ + + public static final String[] RESTRICTED_GROUPNAMES = new String[] + { "Anonymous", "All", "Asserted", "Authenticated" }; + + private final List m_members = new ArrayList(); + + private String m_creator = null; + + private Date m_created = null; + + private String m_modifier = null; + + private Date m_modified = null; + + private final String m_name; + + private final Principal m_principal; + + private final String m_wiki; + + private final String m_qualifiedName; + + /** + * Protected constructor to prevent direct instantiation except by other + * package members. Callers should use + * {@link GroupManager#parseGroup(String, String, boolean)} or + * {@link GroupManager#parseGroup(com.ecyrd.jspwiki.WikiContext, boolean)}. + * instead. + * @param name the name of the group + * @param wiki the wiki the group belongs to + */ + protected Group( String name, String wiki ) + { + m_name = name; + m_wiki = wiki; + m_principal = new GroupPrincipal( name ); + m_qualifiedName = wiki + ":" + name; + } + + /** + * Adds a Principal to the group. + * + * @param user the principal to add + * @return true if the operation was successful + */ + public synchronized boolean add( Principal user ) + { + if ( isMember( user ) ) + { + return false; + } + + m_members.add( user ); + return true; + } + + /** + * Clears all Principals from the group list. + */ + public synchronized void clear() + { + m_members.clear(); + } + + /** + * Two DefaultGroups are equal if they contain identical member Principals + * and have the same name. + * @param o the object to compare + * @return the comparison + */ + public boolean equals( Object o ) + { + if ( o == null || !( o instanceof Group ) ) + return false; + + Group g = (Group) o; // Just a shortcut. + + if ( g.m_members.size() != m_members.size() ) + return false; + + if ( getName() != null && !getName().equals( g.getName() ) ) + { + return false; + } + else if ( getName() == null && g.getName() != null ) + { + return false; + } + + for( Iterator i = m_members.iterator(); i.hasNext(); ) + { + if ( !( g.isMember( (Principal) i.next() ) ) ) + { + return false; + } + } + + return true; + } + + /** + * The hashcode is calculated as a XOR sum over all members of + * the Group. + * @return the hash code + */ + public int hashCode() + { + int hc = 0; + for( Iterator i = m_members.iterator(); i.hasNext(); ) + { + hc ^= i.next().hashCode(); + } + return hc; + } + + /** + * Returns the creation date. + * @return the creation date + */ + public synchronized Date getCreated() + { + return m_created; + } + + /** + * Returns the creator of this Group. + * @return the creator + */ + public final synchronized String getCreator() + { + return m_creator; + } + + /** + * Returns the last-modified date. + * @return the date and time of last modification + */ + public synchronized Date getLastModified() + { + return m_modified; + } + + /** + * Returns the name of the user who last modified this group. + * @return the modifier + */ + public final synchronized String getModifier() + { + return m_modifier; + } + + /** + * The name of the group. This is set in the class constructor. + * @return the name of the Group + */ + public String getName() + { + return m_name; + } + + /** + * The qualified name of the group, defined as the wiki plus the name, + * separated by a colon (e.g., MyWiki:MyGroup). + * @return the qualified name of the Group + */ + public String getQualifiedName() + { + return m_qualifiedName; + } + + /** + * Returns the GroupPrincipal that represents this Group. + * @return the group principal + */ + public Principal getPrincipal() + { + return m_principal; + } + + /** + * Returns the wiki name. + * @return the wiki name + */ + public String getWiki() + { + return m_wiki; + } + + /** + * Returns true if a Principal is a member of the group. + * Specifically, the Principal's getName() method must return + * the same value as one of the Principals in the group member list. The + * Principal's type does not need to match. + * @param principal the principal about whom membeship status is sought + * @return the result of the operation + */ + public boolean isMember( Principal principal ) + { + return findMember( principal.getName() ) != null; + } + + /** + * Returns the members of the group as an unmodifiable Set of Principal + * objects. + */ + public List getMembers() + { + return Collections.unmodifiableList(m_members); + } + + /** + * Returns the members of the group as an array of Principal objects. + * @return the members + * @deprecated + */ + public Principal[] members() + { + return m_members.toArray(new Principal[m_members.size()]); + } + + /** + * Removes a Principal from the group. + * + * @param user the principal to remove + * @return true if the operation was successful + */ + public synchronized boolean remove( Principal user ) + { + user = findMember( user.getName() ); + + if ( user == null ) + return false; + + m_members.remove( user ); + + return true; + } + + /** + * Sets the created date. + * @param date the creation date + */ + public synchronized void setCreated( Date date ) + { + m_created = date; + } + + /** + * Sets the creator of this Group. + * @param creator the creator + */ + public final synchronized void setCreator( String creator ) + { + this.m_creator = creator; + } + + /** + * Sets the last-modified date + * @param date the last-modified date + */ + public synchronized void setLastModified( Date date ) + { + m_modified = date; + } + + /** + * Sets the name of the user who last modified this group. + * @param modifier the modifier + */ + public final synchronized void setModifier( String modifier ) + { + this.m_modifier = modifier; + } + + /** + * Returns a string representation of the Group. + * @return the string + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append( "(Group " + getName() + ")" ); + return sb.toString(); + } + + private Principal findMember( String name ) + { + for( Iterator i = m_members.iterator(); i.hasNext(); ) + { + Principal member = (Principal) i.next(); + + if ( member.getName().equals( name ) ) + { + return member; + } + } + + return null; + } + +} Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/GroupDatabase.java URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/GroupDatabase.java?rev=627255&view=auto ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/GroupDatabase.java (added) +++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/src/com/ecyrd/jspwiki/auth/authorize/GroupDatabase.java Tue Feb 12 21:53:55 2008 @@ -0,0 +1,90 @@ +/* + * 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.authorize; + +import java.security.Principal; +import java.util.Properties; + +import com.ecyrd.jspwiki.NoRequiredPropertyException; +import com.ecyrd.jspwiki.WikiEngine; +import com.ecyrd.jspwiki.auth.NoSuchPrincipalException; +import com.ecyrd.jspwiki.auth.WikiSecurityException; + +/** + * Defines an interface for loading, persisting and storing wiki groups. + * @author Andrew Jaquith + * @since 2.4.22 + */ +public interface GroupDatabase +{ + /** + * No-op method that in previous versions of JSPWiki was intended to + * atomically commit changes to the user database. Now, the + * {@link #save(Group, Principal)} and {@link #delete(Group)} methods + * are atomic themselves. + * @throws WikiSecurityException never... + * @deprecated there is no need to call this method because the save and + * delete methods contain their own commit logic + */ + public void commit() throws WikiSecurityException; + + /** + * Looks up and deletes a {@link Group} from the group database. If the + * group database does not contain the supplied Group. this method throws a + * {@link NoSuchPrincipalException}. The method commits the results + * of the delete to persistent storage. + * @param group the group to remove + * @throws WikiSecurityException if the database does not contain the + * supplied group (thrown as {@link NoSuchPrincipalException}) or if + * the commit did not succeed + */ + public void delete( Group group ) throws WikiSecurityException; + + /** + * Initializes the group database based on values from a Properties object. + * @param engine the wiki engine + * @param props the properties used to initialize the group database + * @throws WikiSecurityException if the database could not be initialized successfully + * @throws NoRequiredPropertyException if a required property is not present + */ + public void initialize( WikiEngine engine, Properties props ) throws NoRequiredPropertyException, WikiSecurityException; + + /** + * Saves a Group to the group database. Note that this method must + * fail, and throw an IllegalArgumentException, if the + * proposed group is the same name as one of the built-in Roles: e.g., + * Admin, Authenticated, etc. The database is responsible for setting + * create/modify timestamps, upon a successful save, to the Group. + * The method commits the results of the delete to persistent storage. + * @param group the Group to save + * @param modifier the user who saved the Group + * @throws WikiSecurityException if the Group could not be saved successfully + */ + public void save( Group group, Principal modifier ) throws WikiSecurityException; + + /** + * Returns all wiki groups that are stored in the GroupDatabase as an array + * of Group objects. If the database does not contain any groups, this + * method will return a zero-length array. This method causes back-end + * storage to load the entire set of group; thus, it should be called + * infrequently (e.g., at initialization time). Note that this method should + * use the protected constructor {@link Group#Group(String, String)} rather + * than the various "parse" methods ({@link GroupManager#parseGroup(String, String, boolean)}) + * to construct the group. This is so as not to flood GroupManager's event + * queue with spurious events. + * @return the wiki groups + * @throws WikiSecurityException if the groups cannot be returned by the back-end + */ + public Group[] groups() throws WikiSecurityException; +}