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; 020 021 022import org.apache.log4j.Logger; 023import org.apache.wiki.WikiContext; 024import org.apache.wiki.WikiEngine; 025import org.apache.wiki.WikiPage; 026import org.apache.wiki.WikiSession; 027import org.apache.wiki.api.exceptions.NoRequiredPropertyException; 028import org.apache.wiki.api.exceptions.WikiException; 029import org.apache.wiki.auth.acl.Acl; 030import org.apache.wiki.auth.acl.AclEntry; 031import org.apache.wiki.auth.acl.UnresolvedPrincipal; 032import org.apache.wiki.auth.authorize.Role; 033import org.apache.wiki.auth.permissions.AllPermission; 034import org.apache.wiki.auth.permissions.PagePermission; 035import org.apache.wiki.auth.user.UserDatabase; 036import org.apache.wiki.auth.user.UserProfile; 037import org.apache.wiki.event.WikiEventListener; 038import org.apache.wiki.event.WikiEventManager; 039import org.apache.wiki.event.WikiSecurityEvent; 040import org.apache.wiki.i18n.InternationalizationManager; 041import org.apache.wiki.preferences.Preferences; 042import org.apache.wiki.tags.WikiTagBase; 043import org.apache.wiki.util.ClassUtil; 044import org.freshcookies.security.policy.LocalPolicy; 045 046import javax.servlet.http.HttpServletResponse; 047import java.io.File; 048import java.io.IOException; 049import java.net.URL; 050import java.security.AccessControlException; 051import java.security.AccessController; 052import java.security.CodeSource; 053import java.security.Permission; 054import java.security.Principal; 055import java.security.PrivilegedAction; 056import java.security.ProtectionDomain; 057import java.security.cert.Certificate; 058import java.text.MessageFormat; 059import java.util.Arrays; 060import java.util.Map; 061import java.util.Properties; 062import java.util.ResourceBundle; 063import java.util.WeakHashMap; 064 065/** 066 * <p>Manages all access control and authorization; determines what authenticated 067 * users are allowed to do.</p> 068 * <p>Privileges in JSPWiki are expressed as Java-standard {@link java.security.Permission} 069 * classes. There are two types of permissions:</p> 070 * <ul> 071 * <li>{@link org.apache.wiki.auth.permissions.WikiPermission} - privileges that apply 072 * to an entire wiki instance: <em>e.g.,</em> editing user profiles, creating pages, creating groups</li> 073 * <li>{@link org.apache.wiki.auth.permissions.PagePermission} - privileges that apply 074 * to a single wiki page or range of pages: <em>e.g.,</em> reading, editing, renaming 075 * </ul> 076 * <p>Calling classes determine whether they are entitled to perform a particular action 077 * by constructing the appropriate permission first, then passing it and the current 078 * {@link org.apache.wiki.WikiSession} to the 079 * {@link #checkPermission(WikiSession, Permission)} method. If the session's 080 * Subject possesses the permission, the action is allowed.</p> 081 * <p>For WikiPermissions, the decision criteria is relatively simple: the caller either 082 * possesses the permission, as granted by the wiki security policy -- or not.</p> 083 * <p>For PagePermissions, the logic is exactly the same if the page being checked 084 * does not have an access control list. However, if the page does have an ACL, the 085 * authorization decision is made based the <em>union</em> of the permissions 086 * granted in the ACL and in the security policy. In other words, the user must 087 * be named in the ACL (or belong to a group or role that is named in the ACL) 088 * <em>and</em> be granted (at least) the same permission in the security policy. We 089 * do this to prevent a user from gaining more permissions than they already 090 * have, based on the security policy.</p> 091 * <p>See the {@link #checkPermission(WikiSession, Permission)} and 092 * {@link #hasRoleOrPrincipal(WikiSession, Principal)} methods for more information 093 * on the authorization logic.</p> 094 * @since 2.3 095 * @see AuthenticationManager 096 */ 097public class AuthorizationManager { 098 099 private static final Logger log = Logger.getLogger( AuthorizationManager.class ); 100 /** 101 * The default external Authorizer is the {@link org.apache.wiki.auth.authorize.WebContainerAuthorizer} 102 */ 103 public static final String DEFAULT_AUTHORIZER = "org.apache.wiki.auth.authorize.WebContainerAuthorizer"; 104 105 /** Property that supplies the security policy file name, in WEB-INF. */ 106 protected static final String POLICY = "jspwiki.policy.file"; 107 108 /** Name of the default security policy file, in WEB-INF. */ 109 protected static final String DEFAULT_POLICY = "jspwiki.policy"; 110 111 /** 112 * The property name in jspwiki.properties for specifying the external {@link Authorizer}. 113 */ 114 public static final String PROP_AUTHORIZER = "jspwiki.authorizer"; 115 116 private Authorizer m_authorizer = null; 117 118 /** Cache for storing ProtectionDomains used to evaluate the local policy. */ 119 private Map<Principal, ProtectionDomain> m_cachedPds = new WeakHashMap<Principal, ProtectionDomain>(); 120 121 private WikiEngine m_engine = null; 122 123 private LocalPolicy m_localPolicy = null; 124 125 /** 126 * Constructs a new AuthorizationManager instance. 127 */ 128 public AuthorizationManager() 129 { 130 } 131 132 /** 133 * Returns <code>true</code> or <code>false</code>, depending on 134 * whether a Permission is allowed for the Subject associated with 135 * a supplied WikiSession. The access control algorithm works this way: 136 * <ol> 137 * <li>The {@link org.apache.wiki.auth.acl.Acl} for the page is obtained</li> 138 * <li>The Subject associated with the current 139 * {@link org.apache.wiki.WikiSession} is obtained</li> 140 * <li>If the Subject's Principal set includes the Role Principal that is 141 * the administrator group, always allow the Permission</li> 142 * <li>For all permissions, check to see if the Permission is allowed according 143 * to the default security policy. If it isn't, deny the permission and halt 144 * further processing.</li> 145 * <li>If there is an Acl, get the list of Principals assigned this 146 * Permission in the Acl: these will be role, group or user Principals, or 147 * {@link org.apache.wiki.auth.acl.UnresolvedPrincipal}s (see below). 148 * Then iterate through the Subject's Principal set and determine whether 149 * the user (Subject) possesses any one of these specified Roles or 150 * Principals. The matching process delegates to 151 * {@link #hasRoleOrPrincipal(WikiSession, Principal)}. 152 * </ol> 153 * <p> 154 * Note that when iterating through the Acl's list of authorized Principals, 155 * it is possible that one or more of the Acl's Principal entries are of 156 * type <code>UnresolvedPrincipal</code>. This means that the last time 157 * the ACL was read, the Principal (user, built-in Role, authorizer Role, or 158 * wiki Group) could not be resolved: the Role was not valid, the user 159 * wasn't found in the UserDatabase, or the Group wasn't known to (e.g., 160 * cached) in the GroupManager. If an <code>UnresolvedPrincipal</code> is 161 * encountered, this method will attempt to resolve it first <em>before</em> 162 * checking to see if the Subject possesses this principal, by calling 163 * {@link #resolvePrincipal(String)}. If the (re-)resolution does not 164 * succeed, the access check for the principal will fail by definition (the 165 * Subject should never contain UnresolvedPrincipals). 166 * </p> 167 * <p> 168 * If security not set to JAAS, will return true. 169 * </p> 170 * @param session the current wiki session 171 * @param permission the Permission being checked 172 * @see #hasRoleOrPrincipal(WikiSession, Principal) 173 * @return the result of the Permission check 174 */ 175 public boolean checkPermission( WikiSession session, Permission permission ) 176 { 177 // 178 // A slight sanity check. 179 // 180 if ( session == null || permission == null ) 181 { 182 fireEvent( WikiSecurityEvent.ACCESS_DENIED, null, permission ); 183 return false; 184 } 185 186 Principal user = session.getLoginPrincipal(); 187 188 // Always allow the action if user has AllPermission 189 Permission allPermission = new AllPermission( m_engine.getApplicationName() ); 190 boolean hasAllPermission = checkStaticPermission( session, allPermission ); 191 if ( hasAllPermission ) 192 { 193 fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission ); 194 return true; 195 } 196 197 // If the user doesn't have *at least* the permission 198 // granted by policy, return false. 199 boolean hasPolicyPermission = checkStaticPermission( session, permission ); 200 if ( !hasPolicyPermission ) 201 { 202 fireEvent( WikiSecurityEvent.ACCESS_DENIED, user, permission ); 203 return false; 204 } 205 206 // If this isn't a PagePermission, it's allowed 207 if ( ! ( permission instanceof PagePermission ) ) 208 { 209 fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission ); 210 return true; 211 } 212 213 // 214 // If the page or ACL is null, it's allowed. 215 // 216 String pageName = ((PagePermission)permission).getPage(); 217 WikiPage page = m_engine.getPage( pageName ); 218 Acl acl = ( page == null) ? null : m_engine.getAclManager().getPermissions( page ); 219 if ( page == null || acl == null || acl.isEmpty() ) 220 { 221 fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission ); 222 return true; 223 } 224 225 // 226 // Next, iterate through the Principal objects assigned 227 // this permission. If the context's subject possesses 228 // any of these, the action is allowed. 229 230 Principal[] aclPrincipals = acl.findPrincipals( permission ); 231 232 log.debug( "Checking ACL entries..." ); 233 log.debug( "Acl for this page is: " + acl ); 234 log.debug( "Checking for principal: " + Arrays.toString( aclPrincipals ) ); 235 log.debug( "Permission: " + permission ); 236 237 for( Principal aclPrincipal : aclPrincipals ) 238 { 239 // If the ACL principal we're looking at is unresolved, 240 // try to resolve it here & correct the Acl 241 if ( aclPrincipal instanceof UnresolvedPrincipal ) 242 { 243 AclEntry aclEntry = acl.getEntry( aclPrincipal ); 244 aclPrincipal = resolvePrincipal( aclPrincipal.getName() ); 245 if ( aclEntry != null && !( aclPrincipal instanceof UnresolvedPrincipal ) ) 246 { 247 aclEntry.setPrincipal( aclPrincipal ); 248 } 249 } 250 251 if ( hasRoleOrPrincipal( session, aclPrincipal ) ) 252 { 253 fireEvent( WikiSecurityEvent.ACCESS_ALLOWED, user, permission ); 254 return true; 255 } 256 } 257 fireEvent( WikiSecurityEvent.ACCESS_DENIED, user, permission ); 258 return false; 259 } 260 261 /** 262 * <p>Determines if the Subject associated with a 263 * supplied WikiSession contains a desired Role or GroupPrincipal. 264 * The algorithm simply checks to see if the Subject possesses 265 * the Role or GroupPrincipal it in its Principal set. Note that 266 * any user (anonymous, asserted, authenticated) can possess 267 * a built-in role. But a user <em>must</em> be authenticated to 268 * possess a role other than one of the built-in ones. 269 * We do this to prevent privilege escalation.</p> 270 * <p>For all other cases, this method returns <code>false</code>.</p> 271 * <p>Note that this method does <em>not</em> consult the external 272 * Authorizer or GroupManager; it relies on the Principals that 273 * have been injected into the user's Subject at login time, or 274 * after group creation/modification/deletion.</p> 275 * @param session the current wiki session, which must be non-null. If null, 276 * the result of this method always returns <code>false</code> 277 * @param principal the Principal (role or group principal) to look 278 * for, which must be non-<code>null</code>. If <code>null</code>, 279 * the result of this method always returns <code>false</code> 280 * @return <code>true</code> if the Subject supplied with the WikiContext 281 * posesses the Role or GroupPrincipal, <code>false</code> otherwise 282 */ 283 public boolean isUserInRole( WikiSession session, Principal principal ) 284 { 285 if ( session == null || principal == null || 286 AuthenticationManager.isUserPrincipal( principal ) ) 287 { 288 return false; 289 } 290 291 // Any type of user can possess a built-in role 292 if ( principal instanceof Role && Role.isBuiltInRole( (Role)principal ) ) 293 { 294 return session.hasPrincipal( principal ); 295 } 296 297 // Only authenticated users can possess groups or custom roles 298 if ( session.isAuthenticated() && AuthenticationManager.isRolePrincipal( principal ) ) 299 { 300 return session.hasPrincipal( principal ); 301 } 302 return false; 303 } 304 305 /** 306 * Returns the current external {@link Authorizer} in use. This method 307 * is guaranteed to return a properly-initialized Authorizer, unless 308 * it could not be initialized. In that case, this method throws 309 * a {@link org.apache.wiki.auth.WikiSecurityException}. 310 * @throws org.apache.wiki.auth.WikiSecurityException if the Authorizer could 311 * not be initialized 312 * @return the current Authorizer 313 */ 314 public Authorizer getAuthorizer() throws WikiSecurityException 315 { 316 if ( m_authorizer != null ) 317 { 318 return m_authorizer; 319 } 320 throw new WikiSecurityException( "Authorizer did not initialize properly. Check the logs." ); 321 } 322 323 /** 324 * <p>Determines if the Subject associated with a supplied WikiSession contains 325 * a desired user Principal or built-in Role principal, OR is a member a 326 * Group or external Role. The rules are as follows:</p> 327 * <ol> 328 * <li>First, if desired Principal is a Role or GroupPrincipal, delegate to 329 * {@link #isUserInRole(WikiSession, Principal)} and 330 * return the result.</li> 331 * <li>Otherwise, we're looking for a user Principal, 332 * so iterate through the Principal set and see if 333 * any share the same name as the one we are looking for.</li> 334 * </ol> 335 * <p><em>Note: if the Principal parameter is a user principal, the session 336 * must be authenticated in order for the user to "possess it". Anonymous 337 * or asserted sessions will never posseess a named user principal.</em></p> 338 * @param session the current wiki session, which must be non-null. If null, 339 * the result of this method always returns <code>false</code> 340 * @param principal the Principal (role, group, or user principal) to look 341 * for, which must be non-null. If null, the result of this 342 * method always returns <code>false</code> 343 * @return <code>true</code> if the Subject supplied with the WikiContext 344 * posesses the Role, GroupPrincipal or desired 345 * user Principal, <code>false</code> otherwise 346 */ 347 protected boolean hasRoleOrPrincipal( WikiSession session, Principal principal ) 348 { 349 // If either parameter is null, always deny 350 if( session == null || principal == null ) 351 { 352 return false; 353 } 354 355 // If principal is role, delegate to isUserInRole 356 if( AuthenticationManager.isRolePrincipal( principal ) ) 357 { 358 return isUserInRole( session, principal ); 359 } 360 361 // We must be looking for a user principal, assuming that the user 362 // has been properly logged in. 363 // So just look for a name match. 364 if( session.isAuthenticated() && AuthenticationManager.isUserPrincipal( principal ) ) 365 { 366 String principalName = principal.getName(); 367 Principal[] userPrincipals = session.getPrincipals(); 368 for( Principal userPrincipal : userPrincipals ) 369 { 370 if( userPrincipal.getName().equals( principalName ) ) 371 { 372 return true; 373 } 374 } 375 } 376 return false; 377 } 378 379 /** 380 * Checks whether the current user has access to the wiki context, 381 * by obtaining the required Permission ({@link WikiContext#requiredPermission()}) 382 * and delegating the access check to {@link #checkPermission(WikiSession, Permission)}. 383 * If the user is allowed, this method returns <code>true</code>; 384 * <code>false</code> otherwise. If access is allowed, 385 * the wiki context will be added to the request as an attribute 386 * with the key name {@link org.apache.wiki.tags.WikiTagBase#ATTR_CONTEXT}. 387 * Note that this method will automatically redirect the user to 388 * a login or error page, as appropriate, if access fails. This is 389 * NOT guaranteed to be default behavior in the future. 390 * 391 * @param context wiki context to check if it is accesible 392 * @param response the http response 393 * @return the result of the access check 394 * @throws IOException In case something goes wrong 395 */ 396 public boolean hasAccess( WikiContext context, HttpServletResponse response ) throws IOException 397 { 398 return hasAccess( context, response, true ); 399 } 400 401 /** 402 * Checks whether the current user has access to the wiki context (and 403 * optionally redirects if not), by obtaining the required Permission ({@link WikiContext#requiredPermission()}) 404 * and delegating the access check to {@link #checkPermission(WikiSession, Permission)}. 405 * If the user is allowed, this method returns <code>true</code>; 406 * <code>false</code> otherwise. Also, the wiki context will be added to the request as attribute 407 * with the key name {@link org.apache.wiki.tags.WikiTagBase#ATTR_CONTEXT}. 408 * 409 * @param context wiki context to check if it is accesible 410 * @param response The servlet response object 411 * @param redirect If true, makes an automatic redirect to the response 412 * @return the result of the access check 413 * @throws IOException If something goes wrong 414 */ 415 public boolean hasAccess( WikiContext context, HttpServletResponse response, boolean redirect ) throws IOException 416 { 417 boolean allowed = checkPermission( context.getWikiSession(), context.requiredPermission() ); 418 ResourceBundle rb = Preferences.getBundle( context, InternationalizationManager.CORE_BUNDLE ); 419 420 // Stash the wiki context 421 if ( context.getHttpRequest() != null && context.getHttpRequest().getAttribute( WikiTagBase.ATTR_CONTEXT ) == null ) 422 { 423 context.getHttpRequest().setAttribute( WikiTagBase.ATTR_CONTEXT, context ); 424 } 425 426 // If access not allowed, redirect 427 if( !allowed && redirect ) 428 { 429 Principal currentUser = context.getWikiSession().getUserPrincipal(); 430 String pageurl = context.getPage().getName(); 431 if( context.getWikiSession().isAuthenticated() ) 432 { 433 log.info("User "+currentUser.getName()+" has no access - forbidden (permission=" + context.requiredPermission() + ")" ); 434 context.getWikiSession().addMessage( 435 MessageFormat.format( rb.getString("security.error.noaccess.logged"), context.getName()) ); 436 } 437 else 438 { 439 log.info("User "+currentUser.getName()+" has no access - redirecting (permission=" + context.requiredPermission() + ")"); 440 context.getWikiSession().addMessage( 441 MessageFormat.format( rb.getString("security.error.noaccess"), context.getName()) ); 442 } 443 response.sendRedirect( m_engine.getURL(WikiContext.LOGIN, pageurl, null, false ) ); 444 } 445 return allowed; 446 } 447 448 /** 449 * Initializes AuthorizationManager with an engine and set of properties. 450 * Expects to find property 'jspwiki.authorizer' with a valid Authorizer 451 * implementation name to take care of role lookup operations. 452 * @param engine the wiki engine 453 * @param properties the set of properties used to initialize the wiki engine 454 * @throws WikiException if the AuthorizationManager cannot be initialized 455 */ 456 public void initialize( final WikiEngine engine, final Properties properties ) throws WikiException { 457 m_engine = engine; 458 459 // 460 // JAAS authorization continues 461 // 462 m_authorizer = getAuthorizerImplementation( properties ); 463 m_authorizer.initialize( engine, properties ); 464 465 // Initialize local security policy 466 try { 467 final String policyFileName = properties.getProperty( POLICY, DEFAULT_POLICY ); 468 final URL policyURL = AuthenticationManager.findConfigFile( engine, policyFileName ); 469 470 if (policyURL != null) { 471 final File policyFile = new File( policyURL.toURI().getPath() ); 472 log.info("We found security policy URL: " + policyURL + " and transformed it to file " + policyFile.getAbsolutePath()); 473 m_localPolicy = new LocalPolicy( policyFile, engine.getContentEncoding().displayName() ); 474 m_localPolicy.refresh(); 475 log.info( "Initialized default security policy: " + policyFile.getAbsolutePath() ); 476 } else { 477 final String sb = "JSPWiki was unable to initialize the default security policy (WEB-INF/jspwiki.policy) file. " + 478 "Please ensure that the jspwiki.policy file exists in the default location. " + 479 "This file should exist regardless of the existance of a global policy file. " + 480 "The global policy file is identified by the java.security.policy variable. "; 481 final WikiSecurityException wse = new WikiSecurityException( sb ); 482 log.fatal( sb, wse ); 483 throw wse; 484 } 485 } catch ( final Exception e) { 486 log.error("Could not initialize local security policy: " + e.getMessage() ); 487 throw new WikiException( "Could not initialize local security policy: " + e.getMessage(), e ); 488 } 489 } 490 491 /** 492 * Attempts to locate and initialize a Authorizer to use with this manager. 493 * Throws a WikiException if no entry is found, or if one fails to 494 * initialize. 495 * @param props jspwiki.properties, containing a 496 * 'jspwiki.authorization.provider' class name 497 * @return a Authorizer used to get page authorization information 498 * @throws WikiException 499 */ 500 private Authorizer getAuthorizerImplementation( Properties props ) throws WikiException { 501 final String authClassName = props.getProperty( PROP_AUTHORIZER, DEFAULT_AUTHORIZER ); 502 return ( Authorizer )locateImplementation( authClassName ); 503 } 504 505 private Object locateImplementation( final String clazz ) throws WikiException { 506 if ( clazz != null ) { 507 try { 508 Class< ? > authClass = ClassUtil.findClass( "org.apache.wiki.auth.authorize", clazz ); 509 Object impl = authClass.newInstance(); 510 return impl; 511 } catch( ClassNotFoundException e ) { 512 log.fatal( "Authorizer " + clazz + " cannot be found", e ); 513 throw new WikiException( "Authorizer " + clazz + " cannot be found", e ); 514 } catch( InstantiationException e ) { 515 log.fatal( "Authorizer " + clazz + " cannot be created", e ); 516 throw new WikiException( "Authorizer " + clazz + " cannot be created", e ); 517 } catch( IllegalAccessException e ) { 518 log.fatal( "You are not allowed to access this authorizer class", e ); 519 throw new WikiException( "You are not allowed to access this authorizer class", e ); 520 } 521 } 522 523 throw new NoRequiredPropertyException( "Unable to find a " + PROP_AUTHORIZER + " entry in the properties.", 524 PROP_AUTHORIZER ); 525 } 526 527 /** 528 * Checks to see if the local security policy allows a particular static Permission. 529 * Do not use this method for normal permission checks; use 530 * {@link #checkPermission(WikiSession, Permission)} instead. 531 * @param principals the Principals to check 532 * @param permission the Permission 533 * @return the result 534 */ 535 protected boolean allowedByLocalPolicy( Principal[] principals, Permission permission ) 536 { 537 for ( Principal principal : principals ) 538 { 539 // Get ProtectionDomain for this Principal from cache, or create new one 540 ProtectionDomain pd = m_cachedPds.get( principal ); 541 if ( pd == null ) 542 { 543 ClassLoader cl = this.getClass().getClassLoader(); 544 CodeSource cs = new CodeSource( null, (Certificate[])null ); 545 pd = new ProtectionDomain( cs, null, cl, new Principal[]{ principal } ); 546 m_cachedPds.put( principal, pd ); 547 } 548 549 // Consult the local policy and get the answer 550 if ( m_localPolicy.implies( pd, permission ) ) 551 { 552 return true; 553 } 554 } 555 return false; 556 } 557 558 /** 559 * Determines whether a Subject possesses a given "static" Permission as 560 * defined in the security policy file. This method uses standard Java 2 561 * security calls to do its work. Note that the current access control 562 * context's <code>codeBase</code> is effectively <em>this class</em>, 563 * not that of the caller. Therefore, this method will work best when what 564 * matters in the policy is <em>who</em> makes the permission check, not 565 * what the caller's code source is. Internally, this method works by 566 * executing <code>Subject.doAsPrivileged</code> with a privileged action 567 * that simply calls {@link java.security.AccessController#checkPermission(Permission)}. 568 * @see AccessController#checkPermission(java.security.Permission) . A 569 * caught exception (or lack thereof) determines whether the privilege 570 * is absent (or present). 571 * @param session the WikiSession whose permission status is being queried 572 * @param permission the Permission the Subject must possess 573 * @return <code>true</code> if the Subject possesses the permission, 574 * <code>false</code> otherwise 575 */ 576 protected boolean checkStaticPermission( final WikiSession session, final Permission permission ) 577 { 578 Boolean allowed = (Boolean) WikiSession.doPrivileged( session, new PrivilegedAction<Boolean>() 579 { 580 public Boolean run() 581 { 582 try 583 { 584 // Check the JVM-wide security policy first 585 AccessController.checkPermission( permission ); 586 return Boolean.TRUE; 587 } 588 catch( AccessControlException e ) 589 { 590 // Global policy denied the permission 591 } 592 593 // Try the local policy - check each Role/Group and User Principal 594 if ( allowedByLocalPolicy( session.getRoles(), permission ) || 595 allowedByLocalPolicy( session.getPrincipals(), permission ) ) 596 { 597 return Boolean.TRUE; 598 } 599 return Boolean.FALSE; 600 } 601 } ); 602 return allowed.booleanValue(); 603 } 604 605 /** 606 * <p>Given a supplied string representing a Principal's name from an Acl, this 607 * method resolves the correct type of Principal (role, group, or user). 608 * This method is guaranteed to always return a Principal. 609 * The algorithm is straightforward:</p> 610 * <ol> 611 * <li>If the name matches one of the built-in {@link org.apache.wiki.auth.authorize.Role} names, 612 * return that built-in Role</li> 613 * <li>If the name matches one supplied by the current 614 * {@link org.apache.wiki.auth.Authorizer}, return that Role</li> 615 * <li>If the name matches a group managed by the 616 * current {@link org.apache.wiki.auth.authorize.GroupManager}, return that Group</li> 617 * <li>Otherwise, assume that the name represents a user 618 * principal. Using the current {@link org.apache.wiki.auth.user.UserDatabase}, find the 619 * first user who matches the supplied name by calling 620 * {@link org.apache.wiki.auth.user.UserDatabase#find(String)}.</li> 621 * <li>Finally, if a user cannot be found, manufacture 622 * and return a generic {@link org.apache.wiki.auth.acl.UnresolvedPrincipal}</li> 623 * </ol> 624 * @param name the name of the Principal to resolve 625 * @return the fully-resolved Principal 626 */ 627 public Principal resolvePrincipal( String name ) 628 { 629 // Check built-in Roles first 630 Role role = new Role(name); 631 if ( Role.isBuiltInRole( role ) ) 632 { 633 return role; 634 } 635 636 // Check Authorizer Roles 637 Principal principal = m_authorizer.findRole( name ); 638 if ( principal != null ) 639 { 640 return principal; 641 } 642 643 // Check Groups 644 principal = m_engine.getGroupManager().findRole( name ); 645 if ( principal != null ) 646 { 647 return principal; 648 } 649 650 // Ok, no luck---this must be a user principal 651 Principal[] principals = null; 652 UserProfile profile = null; 653 UserDatabase db = m_engine.getUserManager().getUserDatabase(); 654 try 655 { 656 profile = db.find( name ); 657 principals = db.getPrincipals( profile.getLoginName() ); 658 for (int i = 0; i < principals.length; i++) 659 { 660 principal = principals[i]; 661 if ( principal.getName().equals( name ) ) 662 { 663 return principal; 664 } 665 } 666 } 667 catch( NoSuchPrincipalException e ) 668 { 669 // We couldn't find the user... 670 } 671 // Ok, no luck---mark this as unresolved and move on 672 return new UnresolvedPrincipal( name ); 673 } 674 675 676 // events processing ....................................................... 677 678 /** 679 * Registers a WikiEventListener with this instance. 680 * @param listener the event listener 681 */ 682 public synchronized void addWikiEventListener( WikiEventListener listener ) 683 { 684 WikiEventManager.addWikiEventListener( this, listener ); 685 } 686 687 /** 688 * Un-registers a WikiEventListener with this instance. 689 * @param listener the event listener 690 */ 691 public synchronized void removeWikiEventListener( WikiEventListener listener ) 692 { 693 WikiEventManager.removeWikiEventListener( this, listener ); 694 } 695 696 /** 697 * Fires a WikiSecurityEvent of the provided type, user, 698 * and permission to all registered listeners. 699 * 700 * @see org.apache.wiki.event.WikiSecurityEvent 701 * @param type the event type to be fired 702 * @param user the user associated with the event 703 * @param permission the permission the subject must possess 704 */ 705 protected void fireEvent( int type, Principal user, Object permission ) 706 { 707 if ( WikiEventManager.isListening(this) ) 708 { 709 WikiEventManager.fireEvent(this,new WikiSecurityEvent(this,type,user,permission)); 710 } 711 } 712 713}