001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.authroles.authorization.strategies.role.metadata; 018 019import org.apache.wicket.Application; 020import org.apache.wicket.Component; 021import org.apache.wicket.MetaDataKey; 022import org.apache.wicket.authorization.Action; 023import org.apache.wicket.authroles.authorization.strategies.role.AbstractRoleAuthorizationStrategy; 024import org.apache.wicket.authroles.authorization.strategies.role.IRoleCheckingStrategy; 025import org.apache.wicket.authroles.authorization.strategies.role.Roles; 026import org.apache.wicket.request.component.IRequestableComponent; 027 028 029/** 030 * Strategy that uses the Wicket metadata facility to check authorization. The static 031 * <code>authorize</code> methods are for authorizing component actions and component instantiation 032 * by role. This class is the main entry point for users wanting to use the roles-based 033 * authorization of the wicket-auth-roles package based on wicket metadata. 034 * 035 * For instance, use like: 036 * 037 * <pre> 038 * MetaDataRoleAuthorizationStrategy.authorize(myPanel, RENDER, "ADMIN"); 039 * </pre> 040 * 041 * for actions on component instances, or: 042 * 043 * <pre> 044 * MetaDataRoleAuthorizationStrategy.authorize(AdminBookmarkablePage.class, "ADMIN"); 045 * </pre> 046 * 047 * for doing role based authorization for component instantation. 048 * 049 * @see org.apache.wicket.MetaDataKey 050 * 051 * @author Eelco Hillenius 052 * @author Jonathan Locke 053 */ 054public class MetaDataRoleAuthorizationStrategy extends AbstractRoleAuthorizationStrategy 055{ 056 /** 057 * Component meta data key for actions/roles information. Typically, you do not need to use this 058 * meta data key directly, but instead use one of the bind methods of this class. 059 */ 060 public static final MetaDataKey<ActionPermissions> ACTION_PERMISSIONS = new MetaDataKey<>() 061 { 062 private static final long serialVersionUID = 1L; 063 }; 064 065 /** 066 * Application meta data key for actions/roles information. Typically, you do not need to use 067 * this meta data key directly, but instead use one of the bind methods of this class. 068 */ 069 public static final MetaDataKey<InstantiationPermissions> INSTANTIATION_PERMISSIONS = new MetaDataKey<>() 070 { 071 private static final long serialVersionUID = 1L; 072 }; 073 074 /** Special role string for denying access to all */ 075 public static final String NO_ROLE = "wicket:NO_ROLE"; 076 077 /** 078 * Authorizes the given role to create component instances of type componentClass. This 079 * authorization is added to any previously authorized roles. 080 * 081 * @param <T> 082 * 083 * @param componentClass 084 * The component type that is subject for the authorization 085 * @param roles 086 * The comma separated roles that are authorized to create component instances of 087 * type componentClass 088 */ 089 public static <T extends Component> void authorize(final Class<T> componentClass, 090 final String roles) 091 { 092 final Application application = Application.get(); 093 InstantiationPermissions permissions = application.getMetaData(INSTANTIATION_PERMISSIONS); 094 if (permissions == null) 095 { 096 permissions = new InstantiationPermissions(); 097 application.setMetaData(INSTANTIATION_PERMISSIONS, permissions); 098 } 099 permissions.authorize(componentClass, new Roles(roles)); 100 } 101 102 /** 103 * Authorizes the given role to perform the given action on the given component. 104 * 105 * @param component 106 * The component that is subject to the authorization 107 * @param action 108 * The action to authorize 109 * @param roles 110 * The comma separated roles to authorize 111 */ 112 public static void authorize(final Component component, final Action action, 113 final String roles) 114 { 115 ActionPermissions permissions = component.getMetaData(ACTION_PERMISSIONS); 116 if (permissions == null) 117 { 118 permissions = new ActionPermissions(); 119 component.setMetaData(ACTION_PERMISSIONS, permissions); 120 } 121 permissions.authorize(action, new Roles(roles)); 122 } 123 124 /** 125 * Grants permission to all roles to create instances of the given component class. 126 * 127 * @param <T> 128 * 129 * @param componentClass 130 * The component class 131 */ 132 public static <T extends Component> void authorizeAll(final Class<T> componentClass) 133 { 134 Application application = Application.get(); 135 InstantiationPermissions authorizedRoles = application.getMetaData(INSTANTIATION_PERMISSIONS); 136 if (authorizedRoles != null) 137 { 138 authorizedRoles.authorizeAll(componentClass); 139 } 140 } 141 142 /** 143 * Grants permission to all roles to perform the given action on the given component. 144 * 145 * @param component 146 * The component that is subject to the authorization 147 * @param action 148 * The action to authorize 149 */ 150 public static void authorizeAll(Component component, final Action action) 151 { 152 ActionPermissions permissions = component.getMetaData(ACTION_PERMISSIONS); 153 if (permissions != null) 154 { 155 permissions.authorizeAll(action); 156 } 157 } 158 159 /** 160 * Removes permission for the given roles to create instances of the given component class. 161 * There is no danger in removing authorization by calling this method. If the last 162 * authorization grant is removed for a given componentClass, the internal role NO_ROLE will 163 * automatically be added, effectively denying access to all roles (if this was not done, all 164 * roles would suddenly have access since no authorization is equivalent to full access). 165 * 166 * @param <T> 167 * 168 * @param componentClass 169 * The component type 170 * @param roles 171 * The comma separated list of roles that are no longer to be authorized to create 172 * instances of type componentClass 173 */ 174 public static <T extends Component> void unauthorize(final Class<T> componentClass, 175 final String roles) 176 { 177 final InstantiationPermissions permissions = Application.get().getMetaData( 178 INSTANTIATION_PERMISSIONS); 179 if (permissions != null) 180 { 181 permissions.unauthorize(componentClass, new Roles(roles)); 182 } 183 } 184 185 /** 186 * Removes permission for the given role to perform the given action on the given component. 187 * There is no danger in removing authorization by calling this method. If the last 188 * authorization grant is removed for a given action, the internal role NO_ROLE will 189 * automatically be added, effectively denying access to all roles (if this was not done, all 190 * roles would suddenly have access since no authorization is equivalent to full access). 191 * 192 * @param component 193 * The component 194 * @param action 195 * The action 196 * @param roles 197 * The comma separated list of roles that are no longer allowed to perform the given 198 * action 199 */ 200 public static void unauthorize(final Component component, final Action action, 201 final String roles) 202 { 203 final ActionPermissions permissions = component.getMetaData(ACTION_PERMISSIONS); 204 if (permissions != null) 205 { 206 permissions.unauthorize(action, new Roles(roles)); 207 } 208 } 209 210 /** 211 * Grants authorization to instantiate the given class to just the role NO_ROLE, effectively 212 * denying all other roles. 213 * 214 * @param <T> 215 * 216 * @param componentClass 217 * The component class 218 */ 219 public static <T extends Component> void unauthorizeAll(Class<T> componentClass) 220 { 221 authorizeAll(componentClass); 222 authorize(componentClass, NO_ROLE); 223 } 224 225 /** 226 * Grants authorization to perform the given action to just the role NO_ROLE, effectively 227 * denying all other roles. 228 * 229 * @param component 230 * the component that is subject to the authorization 231 * @param action 232 * the action to authorize 233 */ 234 public static void unauthorizeAll(final Component component, final Action action) 235 { 236 authorizeAll(component, action); 237 authorize(component, action, NO_ROLE); 238 } 239 240 /** 241 * Construct. 242 * 243 * @param roleCheckingStrategy 244 * the authorizer object 245 */ 246 public MetaDataRoleAuthorizationStrategy(final IRoleCheckingStrategy roleCheckingStrategy) 247 { 248 super(roleCheckingStrategy); 249 } 250 251 /** 252 * Uses component level meta data to match roles for component action execution. 253 * 254 * @see org.apache.wicket.authorization.IAuthorizationStrategy#isActionAuthorized(org.apache.wicket.Component, 255 * org.apache.wicket.authorization.Action) 256 */ 257 @Override 258 public boolean isActionAuthorized(final Component component, final Action action) 259 { 260 if (component == null) 261 { 262 throw new IllegalArgumentException("argument component has to be not null"); 263 } 264 if (action == null) 265 { 266 throw new IllegalArgumentException("argument action has to be not null"); 267 } 268 269 final Roles roles = rolesAuthorizedToPerformAction(component, action); 270 if (roles != null) 271 { 272 return hasAny(roles); 273 } 274 return true; 275 } 276 277 /** 278 * Uses application level meta data to match roles for component instantiation. 279 * 280 * @see org.apache.wicket.authorization.IAuthorizationStrategy#isInstantiationAuthorized(java.lang.Class) 281 */ 282 @Override 283 public <T extends IRequestableComponent> boolean isInstantiationAuthorized( 284 final Class<T> componentClass) 285 { 286 if (componentClass == null) 287 { 288 throw new IllegalArgumentException("argument componentClass cannot be null"); 289 } 290 291 // as long as the interface does not use generics, we should check this 292 if (!Component.class.isAssignableFrom(componentClass)) 293 { 294 throw new IllegalArgumentException("argument componentClass must be of type " + 295 Component.class.getName()); 296 } 297 298 final Roles roles = rolesAuthorizedToInstantiate(componentClass); 299 if (roles != null) 300 { 301 return hasAny(roles); 302 } 303 return true; 304 } 305 306 /** 307 * Gets the roles for creation of the given component class, or null if none were registered. 308 * 309 * @param <T> 310 * 311 * @param componentClass 312 * the component class 313 * @return the roles that are authorized for creation of the componentClass, or null if no 314 * specific authorization was configured 315 */ 316 private static <T extends IRequestableComponent> Roles rolesAuthorizedToInstantiate( 317 final Class<T> componentClass) 318 { 319 final InstantiationPermissions permissions = Application.get().getMetaData( 320 INSTANTIATION_PERMISSIONS); 321 if (permissions != null) 322 { 323 return permissions.authorizedRoles(componentClass); 324 } 325 return null; 326 } 327 328 /** 329 * Gets the roles for the given action/component combination. 330 * 331 * @param component 332 * the component 333 * @param action 334 * the action 335 * @return the roles for the action as defined with the given component 336 */ 337 private static Roles rolesAuthorizedToPerformAction(final Component component, 338 final Action action) 339 { 340 final ActionPermissions permissions = component.getMetaData(ACTION_PERMISSIONS); 341 if (permissions != null) 342 { 343 return permissions.rolesFor(action); 344 } 345 return null; 346 } 347}