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 */ 019package org.apache.wiki.auth.permissions; 020 021import java.io.Serializable; 022import java.security.Permission; 023import java.security.PermissionCollection; 024import 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 */ 038public 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 StringBuilder buffer = new StringBuilder(); 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}