001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2007 JSPWiki development group
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.auth.permissions;
021:
022: import java.security.Permission;
023: import java.security.PermissionCollection;
024: import java.util.Arrays;
025:
026: /**
027: * <p> Permission to perform an global wiki operation, such as self-registering
028: * or creating new pages. Permission actions include: <code>createGroups</code>,
029: * <code>createPages</code>, <code>editPreferences</code>,
030: * <code>editProfile</code> and <code>login</code>. </p> <p>The target is
031: * a given wiki. The syntax for the target is the wiki name. "All wikis" can be
032: * specified using a wildcard (*). Page collections may also be specified using
033: * a wildcard. For pages, the wildcard may be a prefix, suffix, or all by
034: * itself. <p> Certain permissions imply others. Currently,
035: * <code>createGroups</code> implies <code>createPages</code>. </p>
036: * @author Andrew Jaquith
037: * @since 2.3
038: */
039: public final class WikiPermission extends Permission {
040: private static final long serialVersionUID = 1L;
041:
042: public static final String CREATE_GROUPS_ACTION = "createGroups";
043:
044: public static final String CREATE_PAGES_ACTION = "createPages";
045:
046: public static final String LOGIN_ACTION = "login";
047:
048: public static final String EDIT_PREFERENCES_ACTION = "editPreferences";
049:
050: public static final String EDIT_PROFILE_ACTION = "editProfile";
051:
052: public static final String WILDCARD = "*";
053:
054: protected static final int CREATE_GROUPS_MASK = 0x1;
055:
056: protected static final int CREATE_PAGES_MASK = 0x2;
057:
058: protected static final int EDIT_PREFERENCES_MASK = 0x4;
059:
060: protected static final int EDIT_PROFILE_MASK = 0x8;
061:
062: protected static final int LOGIN_MASK = 0x10;
063:
064: public static final WikiPermission CREATE_GROUPS = new WikiPermission(
065: WILDCARD, CREATE_GROUPS_ACTION);
066:
067: public static final WikiPermission CREATE_PAGES = new WikiPermission(
068: WILDCARD, CREATE_PAGES_ACTION);
069:
070: public static final WikiPermission LOGIN = new WikiPermission(
071: WILDCARD, LOGIN_ACTION);
072:
073: public static final WikiPermission EDIT_PREFERENCES = new WikiPermission(
074: WILDCARD, EDIT_PREFERENCES_ACTION);
075:
076: public static final WikiPermission EDIT_PROFILE = new WikiPermission(
077: WILDCARD, EDIT_PROFILE_ACTION);
078:
079: private final String m_actionString;
080:
081: private final String m_wiki;
082:
083: private final int m_mask;
084:
085: /**
086: * Creates a new WikiPermission for a specified set of actions.
087: * @param actions the actions for this permission
088: */
089: public WikiPermission(String wiki, String actions) {
090: super (wiki);
091: String[] pageActions = actions.toLowerCase().split(",");
092: Arrays.sort(pageActions, String.CASE_INSENSITIVE_ORDER);
093: m_mask = createMask(actions);
094: StringBuffer buffer = new StringBuffer();
095: for (int i = 0; i < pageActions.length; i++) {
096: buffer.append(pageActions[i]);
097: if (i < (pageActions.length - 1)) {
098: buffer.append(",");
099: }
100: }
101: m_actionString = buffer.toString();
102: m_wiki = (wiki == null) ? WILDCARD : wiki;
103: }
104:
105: /**
106: * Two WikiPermission objects are considered equal if their wikis and
107: * actions (after normalization) are equal.
108: * @param obj the object to test
109: * @return the result
110: * @see java.lang.Object#equals(java.lang.Object)
111: */
112: public final boolean equals(Object obj) {
113: if (!(obj instanceof WikiPermission)) {
114: return false;
115: }
116: WikiPermission p = (WikiPermission) obj;
117: return p.m_mask == m_mask && p.m_wiki != null
118: && p.m_wiki.equals(m_wiki);
119: }
120:
121: /**
122: * Returns the actions for this permission: "createGroups", "createPages",
123: * "editPreferences", "editProfile", or "login". The actions
124: * will always be sorted in alphabetic order, and will always appear in
125: * lower case.
126: * @return the actions
127: * @see java.security.Permission#getActions()
128: */
129: public final String getActions() {
130: return m_actionString;
131: }
132:
133: /**
134: * Returns the name of the wiki containing the page represented by this
135: * permission; may return the wildcard string.
136: * @return the wiki
137: */
138: public final String getWiki() {
139: return m_wiki;
140: }
141:
142: /**
143: * Returns the hash code for this WikiPermission.
144: * @see java.lang.Object#hashCode()
145: */
146: public final int hashCode() {
147: return m_mask
148: + ((13 * m_actionString.hashCode()) * 23 * m_wiki
149: .hashCode());
150: }
151:
152: /**
153: * WikiPermission can only imply other WikiPermissions; no other permission
154: * types are implied. One WikiPermission implies another if all of the other
155: * WikiPermission's actions are equal to, or a subset of, those for this
156: * permission.
157: * @param permission the permission which may (or may not) be implied by
158: * this instance
159: * @return <code>true</code> if the permission is implied,
160: * <code>false</code> otherwise
161: * @see java.security.Permission#implies(java.security.Permission)
162: */
163: public final boolean implies(Permission permission) {
164: // Permission must be a WikiPermission
165: if (!(permission instanceof WikiPermission)) {
166: return false;
167: }
168: WikiPermission p = (WikiPermission) permission;
169:
170: // See if the wiki is implied
171: boolean impliedWiki = PagePermission.isSubset(m_wiki, p.m_wiki);
172:
173: // Build up an "implied mask" for actions
174: int impliedMask = impliedMask(m_mask);
175:
176: // If actions aren't a proper subset, return false
177: return impliedWiki && (impliedMask & p.m_mask) == p.m_mask;
178: }
179:
180: /**
181: * Returns a new {@link AllPermissionCollection}.
182: * @see java.security.Permission#newPermissionCollection()
183: */
184: public PermissionCollection newPermissionCollection() {
185: return new AllPermissionCollection();
186: }
187:
188: /**
189: * Prints a human-readable representation of this permission.
190: * @see java.lang.Object#toString()
191: */
192: public final String toString() {
193: return "(\"" + this .getClass().getName() + "\",\"" + m_wiki
194: + "\",\"" + getActions() + "\")";
195: }
196:
197: /**
198: * Creates an "implied mask" based on the actions originally assigned: for
199: * example, <code>createGroups</code> implies <code>createPages</code>.
200: * @param mask the initial mask
201: * @return the implied mask
202: */
203: protected static final int impliedMask(int mask) {
204: if ((mask & CREATE_GROUPS_MASK) > 0) {
205: mask |= CREATE_PAGES_MASK;
206: }
207: return mask;
208: }
209:
210: /**
211: * Private method that creates a binary mask based on the actions specified.
212: * This is used by {@link #implies(Permission)}.
213: * @param actions the permission actions, separated by commas
214: * @return binary mask representing the permissions
215: */
216: protected static final int createMask(String actions) {
217: if (actions == null || actions.length() == 0) {
218: throw new IllegalArgumentException(
219: "Actions cannot be blank or null");
220: }
221: int mask = 0;
222: String[] actionList = actions.split(",");
223: for (int i = 0; i < actionList.length; i++) {
224: String action = actionList[i];
225: if (action.equalsIgnoreCase(CREATE_GROUPS_ACTION)) {
226: mask |= CREATE_GROUPS_MASK;
227: } else if (action.equalsIgnoreCase(CREATE_PAGES_ACTION)) {
228: mask |= CREATE_PAGES_MASK;
229: } else if (action.equalsIgnoreCase(LOGIN_ACTION)) {
230: mask |= LOGIN_MASK;
231: } else if (action.equalsIgnoreCase(EDIT_PREFERENCES_ACTION)) {
232: mask |= EDIT_PREFERENCES_MASK;
233: } else if (action.equalsIgnoreCase(EDIT_PROFILE_ACTION)) {
234: mask |= EDIT_PROFILE_MASK;
235: } else {
236: throw new IllegalArgumentException(
237: "Unrecognized action: " + action);
238: }
239: }
240: return mask;
241: }
242: }
|