001 /*
002 Licensed to the Apache Software Foundation (ASF) under one
003 or more contributor license agreements. See the NOTICE file
004 distributed with this work for additional information
005 regarding copyright ownership. The ASF licenses this file
006 to you under the Apache License, Version 2.0 (the
007 "License"); you may not use this file except in compliance
008 with the License. You may obtain a copy of the License at
009
010 http://www.apache.org/licenses/LICENSE-2.0
011
012 Unless required by applicable law or agreed to in writing,
013 software distributed under the License is distributed on an
014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 KIND, either express or implied. See the License for the
016 specific language governing permissions and limitations
017 under the License.
018 */
019 package org.apache.wiki.auth.permissions;
020
021 import java.io.Serializable;
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 * @since 2.3
037 */
038 public final class WikiPermission extends Permission implements Serializable
039 {
040 private static final long serialVersionUID = 1L;
041
042 /** Name of the action for createGroups permission. */
043 public static final String CREATE_GROUPS_ACTION = "createGroups";
044
045 /** Name of the action for createPages permission. */
046 public static final String CREATE_PAGES_ACTION = "createPages";
047
048 /** Name of the action for login permission. */
049 public static final String LOGIN_ACTION = "login";
050
051 /** Name of the action for editPreferences permission. */
052 public static final String EDIT_PREFERENCES_ACTION = "editPreferences";
053
054 /** Name of the action for editProfile permission. */
055 public static final String EDIT_PROFILE_ACTION = "editProfile";
056
057 /** Value for a generic wildcard. */
058 public static final String WILDCARD = "*";
059
060 protected static final int CREATE_GROUPS_MASK = 0x1;
061
062 protected static final int CREATE_PAGES_MASK = 0x2;
063
064 protected static final int EDIT_PREFERENCES_MASK = 0x4;
065
066 protected static final int EDIT_PROFILE_MASK = 0x8;
067
068 protected static final int LOGIN_MASK = 0x10;
069
070 /** A static instance of the createGroups permission. */
071 public static final WikiPermission CREATE_GROUPS = new WikiPermission( WILDCARD, CREATE_GROUPS_ACTION );
072
073 /** A static instance of the createPages permission. */
074 public static final WikiPermission CREATE_PAGES = new WikiPermission( WILDCARD, CREATE_PAGES_ACTION );
075
076 /** A static instance of the login permission. */
077 public static final WikiPermission LOGIN = new WikiPermission( WILDCARD, LOGIN_ACTION );
078
079 /** A static instance of the editPreferences permission. */
080 public static final WikiPermission EDIT_PREFERENCES = new WikiPermission( WILDCARD, EDIT_PREFERENCES_ACTION );
081
082 /** A static instance of the editProfile permission. */
083 public static final WikiPermission EDIT_PROFILE = new WikiPermission( WILDCARD, EDIT_PROFILE_ACTION );
084
085 private final String m_actionString;
086
087 private final String m_wiki;
088
089 private final int m_mask;
090
091 /**
092 * Creates a new WikiPermission for a specified set of actions.
093 * @param actions the actions for this permission
094 * @param wiki The name of the wiki the permission belongs to.
095 */
096 public WikiPermission( String wiki, String actions )
097 {
098 super( wiki );
099 String[] pageActions = actions.toLowerCase().split( "," );
100 Arrays.sort( pageActions, String.CASE_INSENSITIVE_ORDER );
101 m_mask = createMask( actions );
102 StringBuffer buffer = new StringBuffer();
103 for( int i = 0; i < pageActions.length; i++ )
104 {
105 buffer.append( pageActions[i] );
106 if ( i < ( pageActions.length - 1 ) )
107 {
108 buffer.append( "," );
109 }
110 }
111 m_actionString = buffer.toString();
112 m_wiki = ( wiki == null ) ? WILDCARD : wiki;
113 }
114
115 /**
116 * Two WikiPermission objects are considered equal if their wikis and
117 * actions (after normalization) are equal.
118 * @param obj the object to test
119 * @return the result
120 * @see java.lang.Object#equals(java.lang.Object)
121 */
122 public boolean equals( Object obj )
123 {
124 if ( !( obj instanceof WikiPermission ) )
125 {
126 return false;
127 }
128 WikiPermission p = (WikiPermission) obj;
129 return p.m_mask == m_mask && p.m_wiki != null && p.m_wiki.equals( m_wiki );
130 }
131
132 /**
133 * Returns the actions for this permission: "createGroups", "createPages",
134 * "editPreferences", "editProfile", or "login". The actions
135 * will always be sorted in alphabetic order, and will always appear in
136 * lower case.
137 * @return the actions
138 * @see java.security.Permission#getActions()
139 */
140 public String getActions()
141 {
142 return m_actionString;
143 }
144
145 /**
146 * Returns the name of the wiki containing the page represented by this
147 * permission; may return the wildcard string.
148 * @return the wiki
149 */
150 public String getWiki()
151 {
152 return m_wiki;
153 }
154
155 /**
156 * Returns the hash code for this WikiPermission.
157 * @return {@inheritDoc}
158 */
159 public int hashCode()
160 {
161 return m_mask + ( ( 13 * m_actionString.hashCode() ) * 23 * m_wiki.hashCode() );
162 }
163
164 /**
165 * WikiPermission can only imply other WikiPermissions; no other permission
166 * types are implied. One WikiPermission implies another if all of the other
167 * WikiPermission's actions are equal to, or a subset of, those for this
168 * permission.
169 * @param permission the permission which may (or may not) be implied by
170 * this instance
171 * @return <code>true</code> if the permission is implied,
172 * <code>false</code> otherwise
173 * @see java.security.Permission#implies(java.security.Permission)
174 */
175 public boolean implies( Permission permission )
176 {
177 // Permission must be a WikiPermission
178 if ( !( permission instanceof WikiPermission ) )
179 {
180 return false;
181 }
182 WikiPermission p = (WikiPermission) permission;
183
184 // See if the wiki is implied
185 boolean impliedWiki = PagePermission.isSubset( m_wiki, p.m_wiki );
186
187 // Build up an "implied mask" for actions
188 int impliedMask = impliedMask( m_mask );
189
190 // If actions aren't a proper subset, return false
191 return impliedWiki && ( impliedMask & p.m_mask ) == p.m_mask;
192 }
193
194 /**
195 * Returns a new {@link AllPermissionCollection}.
196 * @return {@inheritDoc}
197 */
198 public PermissionCollection newPermissionCollection()
199 {
200 return new AllPermissionCollection();
201 }
202
203 /**
204 * Prints a human-readable representation of this permission.
205 * @return {@inheritDoc}
206 */
207 public String toString()
208 {
209 return "(\"" + this.getClass().getName() + "\",\"" + m_wiki + "\",\"" + getActions() + "\")";
210 }
211
212 /**
213 * Creates an "implied mask" based on the actions originally assigned: for
214 * example, <code>createGroups</code> implies <code>createPages</code>.
215 * @param mask the initial mask
216 * @return the implied mask
217 */
218 protected static int impliedMask( int mask )
219 {
220 if ( ( mask & CREATE_GROUPS_MASK ) > 0 )
221 {
222 mask |= CREATE_PAGES_MASK;
223 }
224 return mask;
225 }
226
227 /**
228 * Private method that creates a binary mask based on the actions specified.
229 * This is used by {@link #implies(Permission)}.
230 * @param actions the permission actions, separated by commas
231 * @return binary mask representing the permissions
232 */
233 protected static int createMask( String actions )
234 {
235 if ( actions == null || actions.length() == 0 )
236 {
237 throw new IllegalArgumentException( "Actions cannot be blank or null" );
238 }
239 int mask = 0;
240 String[] actionList = actions.split( "," );
241 for( int i = 0; i < actionList.length; i++ )
242 {
243 String action = actionList[i];
244 if ( action.equalsIgnoreCase( CREATE_GROUPS_ACTION ) )
245 {
246 mask |= CREATE_GROUPS_MASK;
247 }
248 else if ( action.equalsIgnoreCase( CREATE_PAGES_ACTION ) )
249 {
250 mask |= CREATE_PAGES_MASK;
251 }
252 else if ( action.equalsIgnoreCase( LOGIN_ACTION ) )
253 {
254 mask |= LOGIN_MASK;
255 }
256 else if ( action.equalsIgnoreCase( EDIT_PREFERENCES_ACTION ) )
257 {
258 mask |= EDIT_PREFERENCES_MASK;
259 }
260 else if ( action.equalsIgnoreCase( EDIT_PROFILE_ACTION ) )
261 {
262 mask |= EDIT_PROFILE_MASK;
263 }
264 else
265 {
266 throw new IllegalArgumentException( "Unrecognized action: " + action );
267 }
268 }
269 return mask;
270 }
271 }