📄 groupmanager.java
字号:
/* JSPWiki - a JSP-based WikiWiki clone. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package com.ecyrd.jspwiki.auth.authorize;import java.security.Principal;import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Properties;import java.util.Set;import java.util.StringTokenizer;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang.ArrayUtils;import org.apache.log4j.Logger;import com.ecyrd.jspwiki.NoRequiredPropertyException;import com.ecyrd.jspwiki.WikiContext;import com.ecyrd.jspwiki.WikiEngine;import com.ecyrd.jspwiki.WikiException;import com.ecyrd.jspwiki.WikiSession;import com.ecyrd.jspwiki.auth.*;import com.ecyrd.jspwiki.auth.user.UserProfile;import com.ecyrd.jspwiki.event.WikiEvent;import com.ecyrd.jspwiki.event.WikiEventListener;import com.ecyrd.jspwiki.event.WikiEventManager;import com.ecyrd.jspwiki.event.WikiSecurityEvent;import com.ecyrd.jspwiki.ui.InputValidator;import com.ecyrd.jspwiki.util.ClassUtil;/** * <p> * Facade class for storing, retrieving and managing wiki groups on behalf of * AuthorizationManager, JSPs and other presentation-layer classes. GroupManager * works in collaboration with a back-end {@link GroupDatabase}, which persists * groups to permanent storage. * </p> * <p> * <em>Note: prior to JSPWiki 2.4.19, GroupManager was an interface; it * is now a concrete, final class. The aspects of GroupManager which previously * extracted group information from storage (e.g., wiki pages) have been * refactored into the GroupDatabase interface.</em> * </p> * @author Andrew Jaquith * @since 2.4.19 */public final class GroupManager implements Authorizer, WikiEventListener{ /** Key used for adding UI messages to a user's WikiSession. */ public static final String MESSAGES_KEY = "group"; private static final String PROP_GROUPDATABASE = "jspwiki.groupdatabase"; static final Logger log = Logger.getLogger( GroupManager.class ); protected WikiEngine m_engine; protected WikiEventListener m_groupListener; private GroupDatabase m_groupDatabase = null; /** Map with GroupPrincipals as keys, and Groups as values */ private final Map<Principal, Group> m_groups = new HashMap<Principal, Group>(); /** * <p> * Returns a GroupPrincipal matching a given name. If a group cannot be * found, return <code>null</code>. * </p> * @param name Name of the group. This is case-sensitive. * @return A DefaultGroup instance. */ public Principal findRole( String name ) { try { Group group = getGroup( name ); return group.getPrincipal(); } catch( NoSuchPrincipalException e ) { return null; } } /** * Returns the Group matching a given name. If the group cannot be found, * this method throws a <code>NoSuchPrincipalException</code>. * @param name the name of the group to find * @return the group * @throws NoSuchPrincipalException if the group cannot be found */ public final Group getGroup( String name ) throws NoSuchPrincipalException { Group group = m_groups.get( new GroupPrincipal( name ) ); if ( group != null ) { return group; } throw new NoSuchPrincipalException( "Group " + name + " not found." ); } /** * Returns the current external {@link GroupDatabase} in use. This method * is guaranteed to return a properly-initialized GroupDatabase, unless * it could not be initialized. In that case, this method throws * a {@link com.ecyrd.jspwiki.WikiException}. The GroupDatabase * is lazily initialized. * @throws com.ecyrd.jspwiki.auth.WikiSecurityException if the GroupDatabase could * not be initialized * @return the current GroupDatabase * @since 2.3 */ public final GroupDatabase getGroupDatabase() throws WikiSecurityException { if ( m_groupDatabase != null ) { return m_groupDatabase; } String dbClassName = "<unknown>"; String dbInstantiationError = null; Throwable cause = null; try { Properties props = m_engine.getWikiProperties(); dbClassName = props.getProperty( PROP_GROUPDATABASE ); if ( dbClassName == null ) { dbClassName = XMLGroupDatabase.class.getName(); } log.info( "Attempting to load group database class " + dbClassName ); Class<?> dbClass = ClassUtil.findClass( "com.ecyrd.jspwiki.auth.authorize", dbClassName ); m_groupDatabase = (GroupDatabase) dbClass.newInstance(); m_groupDatabase.initialize( m_engine, m_engine.getWikiProperties() ); log.info( "Group database initialized." ); } catch( ClassNotFoundException e ) { log.error( "GroupDatabase class " + dbClassName + " cannot be found.", e ); dbInstantiationError = "Failed to locate GroupDatabase class " + dbClassName; cause = e; } catch( InstantiationException e ) { log.error( "GroupDatabase class " + dbClassName + " cannot be created.", e ); dbInstantiationError = "Failed to create GroupDatabase class " + dbClassName; cause = e; } catch( IllegalAccessException e ) { log.error( "You are not allowed to access group database class " + dbClassName + ".", e ); dbInstantiationError = "Access GroupDatabase class " + dbClassName + " denied"; cause = e; } catch( NoRequiredPropertyException e ) { log.error( "Missing property: " + e.getMessage() + "." ); dbInstantiationError = "Missing property: " + e.getMessage(); cause = e; } if( dbInstantiationError != null ) { throw new WikiSecurityException( dbInstantiationError + " Cause: " + (cause != null ? cause.getMessage() : "") ); } return m_groupDatabase; } /** * Returns an array of GroupPrincipals this GroupManager knows about. This * method will return an array of GroupPrincipal objects corresponding to * the wiki groups managed by this class. This method actually returns a * defensive copy of an internally stored hashmap. * @return an array of Principals representing the roles */ public final Principal[] getRoles() { return m_groups.keySet().toArray( new Principal[m_groups.size()] ); } /** * Initializes the group cache by initializing the group database and * obtaining a list of all of the groups it stores. * @param engine the wiki engine * @param props the properties used to initialize the wiki engine * @see GroupDatabase#initialize(com.ecyrd.jspwiki.WikiEngine, * java.util.Properties) * @see GroupDatabase#groups() * @throws WikiSecurityException if GroupManager cannot be initialized */ public final void initialize( WikiEngine engine, Properties props ) throws WikiSecurityException { m_engine = engine; try { m_groupDatabase = getGroupDatabase(); } catch ( WikiException e ) { throw new WikiSecurityException( e.getMessage() ); } // Load all groups from the database into the cache Group[] groups = m_groupDatabase.groups(); synchronized( m_groups ) { for( Group group : groups ) { // Add new group to cache; fire GROUP_ADD event m_groups.put( group.getPrincipal(), group ); fireEvent( WikiSecurityEvent.GROUP_ADD, group ); } } // Make the GroupManager listen for WikiEvents (WikiSecurityEvents for changed user profiles) engine.getUserManager().addWikiEventListener( this ); // Success! log.info( "Authorizer GroupManager initialized successfully; loaded " + groups.length + " group(s)." ); } /** * <p> * Determines whether the Subject associated with a WikiSession is in a * particular role. This method takes two parameters: the WikiSession * containing the subject and the desired role ( which may be a Role or a * Group). If either parameter is <code>null</code>, or if the user is * not authenticated, this method returns <code>false</code>. * </p> * <p> * With respect to this implementation, the supplied Principal must be a * GroupPrincipal. The Subject posesses the "role" if it the session is * authenticated <em>and</em> a Subject's principal is a member of the * corresponding Group. This method simply finds the Group in question, then * delegates to {@link Group#isMember(Principal)} for each of the principals * in the Subject's principal set. * </p> * @param session the current WikiSession * @param role the role to check * @return <code>true</code> if the user is considered to be in the role, * <code>false</code> otherwise */ public final boolean isUserInRole( WikiSession session, Principal role ) { // Always return false if session/role is null, or if // role isn't a GroupPrincipal if ( session == null || role == null || !( role instanceof GroupPrincipal ) || !session.isAuthenticated() ) { return false; } // Get the group we're examining Group group = m_groups.get( role ); if ( group == null ) { return false; } // Check each user principal to see if it belongs to the group for ( Principal principal : session.getPrincipals() ) { if ( AuthenticationManager.isUserPrincipal( principal ) && group.isMember( principal ) ) { return true; } } return false; } /** * <p> * Extracts group name and members from passed parameters and populates an * existing Group with them. The Group will either be a copy of an existing * Group (if one can be found), or a new, unregistered Group (if not). * Optionally, this method can throw a WikiSecurityException if the Group * does not yet exist in the GroupManager cache. * </p> * <p> * The <code>group</code> parameter in the HTTP request contains the Group * name to look up and populate. The <code>members</code> parameter * contains the member list. If these differ from those in the existing * group, the passed values override the old values. * </p> * <p> * This method does not commit the new Group to the GroupManager cache. To * do that, use {@link #setGroup(WikiSession, Group)}. * </p> * @param name the name of the group to construct * @param memberLine the line of text containing the group membership list * @param create whether this method should create a new, empty Group if one * with the requested name is not found. If <code>false</code>, * groups that do not exist will cause a * <code>NoSuchPrincipalException</code> to be thrown * @return a new, populated group * @see com.ecyrd.jspwiki.auth.authorize.Group#RESTRICTED_GROUPNAMES * @throws WikiSecurityException if the group name isn't allowed, or if * <code>create</code> is <code>false</code> * and the Group named <code>name</code> does not exist */ public final Group parseGroup( String name, String memberLine, boolean create ) throws WikiSecurityException { // If null name parameter, it's because someone's creating a new group if ( name == null ) { if ( create ) { name = "MyGroup"; } else { throw new WikiSecurityException( "Group name cannot be blank." ); } } else if ( ArrayUtils.contains( Group.RESTRICTED_GROUPNAMES, name ) ) { // Certain names are forbidden throw new WikiSecurityException( "Illegal group name: " + name ); } name = name.trim(); // Normalize the member line if ( InputValidator.isBlank( memberLine ) ) { memberLine = ""; } memberLine = memberLine.trim(); // Create or retrieve the group (may have been previously cached) Group group = new Group( name, m_engine.getApplicationName() ); try { Group existingGroup = getGroup( name ); // If existing, clone it group.setCreator( existingGroup.getCreator() ); group.setCreated( existingGroup.getCreated() ); group.setModifier( existingGroup.getModifier() ); group.setLastModified( existingGroup.getLastModified() ); for( Principal existingMember : existingGroup.members() ) { group.add( existingMember ); } } catch( NoSuchPrincipalException e ) { // It's a new group.... throw error if we don't create new ones if ( !create ) { throw new NoSuchPrincipalException( "Group '" + name + "' does not exist." ); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -