| /* |
| 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 org.apache.wiki.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.wiki.WikiContext; |
| import org.apache.wiki.WikiEngine; |
| import org.apache.wiki.WikiInternalModule; |
| import org.apache.wiki.WikiSession; |
| import org.apache.wiki.api.exceptions.NoRequiredPropertyException; |
| import org.apache.wiki.api.exceptions.WikiException; |
| import org.apache.wiki.auth.AuthenticationManager; |
| import org.apache.wiki.auth.Authorizer; |
| import org.apache.wiki.auth.GroupPrincipal; |
| import org.apache.wiki.auth.NoSuchPrincipalException; |
| import org.apache.wiki.auth.WikiPrincipal; |
| import org.apache.wiki.auth.WikiSecurityException; |
| import org.apache.wiki.auth.user.UserProfile; |
| import org.apache.wiki.event.WikiEvent; |
| import org.apache.wiki.event.WikiEventListener; |
| import org.apache.wiki.event.WikiEventManager; |
| import org.apache.wiki.event.WikiSecurityEvent; |
| import org.apache.wiki.ui.InputValidator; |
| import org.apache.wiki.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> |
| * @since 2.4.19 |
| */ |
| public class GroupManager extends WikiInternalModule 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"; |
| |
| 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 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 org.apache.wiki.api.exceptions.WikiException}. The GroupDatabase |
| * is lazily initialized. |
| * @throws org.apache.wiki.auth.WikiException if the GroupDatabase could |
| * not be initialized |
| * @return the current GroupDatabase |
| * @since 2.3 |
| */ |
| public GroupDatabase getGroupDatabase() throws WikiException |
| { |
| 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 ); |
| m_groupDatabase = ClassUtil.getWikiProvider(GroupDatabase.class, m_engine, m_engine.getWikiProperties(), "org.apache.wiki.auth.authorize", dbClassName, null, true); |
| |
| // Class<?> dbClass = ClassUtil.findClass( "org.apache.wiki.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() : ""), cause ); |
| } |
| |
| 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 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(org.apache.wiki.WikiEngine, |
| * java.util.Properties) |
| * @see GroupDatabase#groups() |
| * @throws WikiSecurityException if GroupManager cannot be initialized |
| */ |
| public void initialize( WikiEngine engine, Properties props ) throws WikiSecurityException |
| { |
| m_engine = engine; |
| |
| try |
| { |
| m_groupDatabase = getGroupDatabase(); |
| } |
| catch ( WikiException e ) |
| { |
| throw new WikiSecurityException( e.getMessage(), e ); |
| } |
| |
| // 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 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 org.apache.wiki.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 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." ); |
| } |
| } |
| |
| // If passed members not empty, overwrite |
| String[] members = extractMembers( memberLine ); |
| if ( members.length > 0 ) |
| { |
| group.clear(); |
| for( String member : members ) |
| { |
| group.add( new WikiPrincipal( member ) ); |
| } |
| } |
| |
| return group; |
| } |
| |
| /** |
| * <p> |
| * Extracts group name and members from the HTTP request 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 context the current wiki context |
| * @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 |
| * @throws WikiSecurityException if the group name isn't allowed, or if |
| * <code>create</code> is <code>false</code> |
| * and the Group does not exist |
| */ |
| public Group parseGroup( WikiContext context, boolean create ) throws WikiSecurityException |
| { |
| // Extract parameters |
| HttpServletRequest request = context.getHttpRequest(); |
| String name = request.getParameter( "group" ); |
| String memberLine = request.getParameter( "members" ); |
| |
| // Create the named group; we pass on any NoSuchPrincipalExceptions |
| // that may be thrown if create == false, or WikiSecurityExceptions |
| Group group = parseGroup( name, memberLine, create ); |
| |
| // If no members, add the current user by default |
| if ( group.members().length == 0 ) |
| { |
| group.add( context.getWikiSession().getUserPrincipal() ); |
| } |
| |
| return group; |
| } |
| |
| /** |
| * Removes a named Group from the group database. If not found, throws a |
| * <code>NoSuchPrincipalException</code>. After removal, this method will |
| * commit the delete to the back-end group database. It will also fire a |
| * {@link org.apache.wiki.event.WikiSecurityEvent#GROUP_REMOVE} event with |
| * the GroupManager instance as the source and the Group as target. |
| * If <code>index</code> is <code>null</code>, this method throws |
| * an {@link IllegalArgumentException}. |
| * @param index the group to remove |
| * @throws WikiSecurityException if the Group cannot be removed by |
| * the back-end |
| * @see org.apache.wiki.auth.authorize.GroupDatabase#delete(Group) |
| */ |
| public void removeGroup( String index ) throws WikiSecurityException |
| { |
| if ( index == null ) |
| { |
| throw new IllegalArgumentException( "Group cannot be null." ); |
| } |
| |
| Group group = m_groups.get( new GroupPrincipal( index ) ); |
| if ( group == null ) |
| { |
| throw new NoSuchPrincipalException( "Group " + index + " not found" ); |
| } |
| |
| // Delete the group |
| // TODO: need rollback procedure |
| synchronized( m_groups ) |
| { |
| m_groups.remove( group.getPrincipal() ); |
| } |
| m_groupDatabase.delete( group ); |
| fireEvent( WikiSecurityEvent.GROUP_REMOVE, group ); |
| } |
| |
| /** |
| * <p> |
| * Saves the {@link Group} created by a user in a wiki session. This method |
| * registers the Group with the GroupManager and saves it to the back-end |
| * database. If an existing Group with the same name already exists, the new |
| * group will overwrite it. After saving the Group, the group database |
| * changes are committed. |
| * </p> |
| * <p> |
| * This method fires the following events: |
| * </p> |
| * <ul> |
| * <li><strong>When creating a new Group</strong>, this method fires a |
| * {@link org.apache.wiki.event.WikiSecurityEvent#GROUP_ADD} with the |
| * GroupManager instance as its source and the new Group as the target.</li> |
| * <li><strong>When overwriting an existing Group</strong>, this method |
| * fires a new {@link org.apache.wiki.event.WikiSecurityEvent#GROUP_REMOVE} |
| * with this GroupManager instance as the source, and the new Group as the |
| * target. It then fires a |
| * {@link org.apache.wiki.event.WikiSecurityEvent#GROUP_ADD} event with the |
| * same source and target.</li> |
| * </ul> |
| * <p> |
| * In addition, if the save or commit actions fail, this method will attempt |
| * to restore the older version of the wiki group if it exists. This will |
| * result in a <code>GROUP_REMOVE</code> event (for the new version of the |
| * Group) followed by a <code>GROUP_ADD</code> event (to indicate |
| * restoration of the old version). |
| * </p> |
| * <p> |
| * This method will register the new Group with the GroupManager. For example, |
| * {@link org.apache.wiki.auth.AuthenticationManager} attaches each |
| * WikiSession as a GroupManager listener. Thus, the act of registering a |
| * Group with <code>setGroup</code> means that all WikiSessions will |
| * automatically receive group add/change/delete events immediately. |
| * </p> |
| * @param session the wiki session, which may not be <code>null</code> |
| * @param group the Group, which may not be <code>null</code> |
| * @throws WikiSecurityException if the Group cannot be saved by the back-end |
| */ |
| public void setGroup( WikiSession session, Group group ) throws WikiSecurityException |
| { |
| // TODO: check for appropriate permissions |
| |
| // If group already exists, delete it; fire GROUP_REMOVE event |
| Group oldGroup = m_groups.get( group.getPrincipal() ); |
| if ( oldGroup != null ) |
| { |
| fireEvent( WikiSecurityEvent.GROUP_REMOVE, oldGroup ); |
| synchronized( m_groups ) |
| { |
| m_groups.remove( oldGroup.getPrincipal() ); |
| } |
| } |
| |
| // Copy existing modifier info & timestamps |
| if ( oldGroup != null ) |
| { |
| group.setCreator( oldGroup.getCreator() ); |
| group.setCreated( oldGroup.getCreated() ); |
| group.setModifier( oldGroup.getModifier() ); |
| group.setLastModified( oldGroup.getLastModified() ); |
| } |
| |
| // Add new group to cache; announce GROUP_ADD event |
| synchronized( m_groups ) |
| { |
| m_groups.put( group.getPrincipal(), group ); |
| } |
| fireEvent( WikiSecurityEvent.GROUP_ADD, group ); |
| |
| // Save the group to back-end database; if it fails, |
| // roll back to previous state. Note that the back-end |
| // MUST timestammp the create/modify fields in the Group. |
| try |
| { |
| m_groupDatabase.save( group, session.getUserPrincipal() ); |
| } |
| |
| // We got an exception! Roll back... |
| catch( WikiSecurityException e ) |
| { |
| if ( oldGroup != null ) |
| { |
| // Restore previous version, re-throw... |
| fireEvent( WikiSecurityEvent.GROUP_REMOVE, group ); |
| fireEvent( WikiSecurityEvent.GROUP_ADD, oldGroup ); |
| synchronized( m_groups ) |
| { |
| m_groups.put( oldGroup.getPrincipal(), oldGroup ); |
| } |
| throw new WikiSecurityException( e.getMessage() + " (rolled back to previous version).", e ); |
| } |
| // Re-throw security exception |
| throw new WikiSecurityException( e.getMessage(), e ); |
| } |
| } |
| |
| /** |
| * Validates a Group, and appends any errors to the session errors list. Any |
| * validation errors are added to the wiki session's messages collection |
| * (see {@link WikiSession#getMessages()}. |
| * @param context the current wiki context |
| * @param group the supplied Group |
| */ |
| public void validateGroup( WikiContext context, Group group ) |
| { |
| InputValidator validator = new InputValidator( MESSAGES_KEY, context ); |
| |
| // Name cannot be null or one of the restricted names |
| try |
| { |
| checkGroupName( context, group.getName() ); |
| } |
| catch( WikiSecurityException e ) |
| { |
| |
| } |
| |
| // Member names must be "safe" strings |
| Principal[] members = group.members(); |
| for( int i = 0; i < members.length; i++ ) |
| { |
| validator.validateNotNull( members[i].getName(), "Full name", InputValidator.ID ); |
| } |
| } |
| |
| /** |
| * Extracts carriage-return separated members into a Set of String objects. |
| * @param memberLine the list of members |
| * @return the list of members |
| */ |
| protected String[] extractMembers( String memberLine ) |
| { |
| Set<String> members = new HashSet<String>(); |
| if ( memberLine != null ) |
| { |
| StringTokenizer tok = new StringTokenizer( memberLine, "\n" ); |
| while( tok.hasMoreTokens() ) |
| { |
| String uid = tok.nextToken().trim(); |
| if ( uid != null && uid.length() > 0 ) |
| { |
| members.add( uid ); |
| } |
| } |
| } |
| return members.toArray( new String[members.size()] ); |
| } |
| |
| /** |
| * Checks if a String is blank or a restricted Group name, and if it is, |
| * appends an error to the WikiSession's message list. |
| * @param context the wiki context |
| * @param name the Group name to test |
| * @throws WikiSecurityException if <code>session</code> is |
| * <code>null</code> or the Group name is illegal |
| * @see Group#RESTRICTED_GROUPNAMES |
| */ |
| protected void checkGroupName( WikiContext context, String name ) throws WikiSecurityException |
| { |
| //TODO: groups cannot have the same name as a user |
| |
| // Name cannot be null |
| InputValidator validator = new InputValidator( MESSAGES_KEY, context ); |
| validator.validateNotNull( name, "Group name" ); |
| |
| // Name cannot be one of the restricted names either |
| if( ArrayUtils.contains( Group.RESTRICTED_GROUPNAMES, name ) ) |
| { |
| throw new WikiSecurityException( "The group name '" + name + "' is illegal. Choose another." ); |
| } |
| } |
| |
| |
| // events processing ....................................................... |
| |
| /** |
| * Registers a WikiEventListener with this instance. |
| * This is a convenience method. |
| * @param listener the event listener |
| */ |
| public synchronized void addWikiEventListener( WikiEventListener listener ) |
| { |
| WikiEventManager.addWikiEventListener( this, listener ); |
| } |
| |
| /** |
| * Un-registers a WikiEventListener with this instance. |
| * This is a convenience method. |
| * @param listener the event listener |
| */ |
| public synchronized void removeWikiEventListener( WikiEventListener listener ) |
| { |
| WikiEventManager.removeWikiEventListener( this, listener ); |
| } |
| |
| /** |
| * Fires a WikiSecurityEvent of the provided type, Principal and target Object |
| * to all registered listeners. |
| * |
| * @see org.apache.wiki.event.WikiSecurityEvent |
| * @param type the event type to be fired |
| * @param target the changed Object, which may be <code>null</code> |
| */ |
| protected void fireEvent( int type, Object target ) |
| { |
| if ( WikiEventManager.isListening(this) ) |
| { |
| WikiEventManager.fireEvent(this,new WikiSecurityEvent(this,type,target)); |
| } |
| } |
| |
| /** |
| * Listens for {@link org.apache.wiki.event.WikiSecurityEvent#PROFILE_NAME_CHANGED} |
| * events. If a user profile's name changes, each group is inspected. If an entry contains |
| * a name that has changed, it is replaced with the new one. No group events are emitted |
| * as a consequence of this method, because the group memberships are still the same; it is |
| * only the representations of the names within that are changing. |
| * @param event the incoming event |
| */ |
| public void actionPerformed(WikiEvent event) |
| { |
| if (! ( event instanceof WikiSecurityEvent ) ) |
| { |
| return; |
| } |
| |
| WikiSecurityEvent se = (WikiSecurityEvent)event; |
| if ( se.getType() == WikiSecurityEvent.PROFILE_NAME_CHANGED ) |
| { |
| WikiSession session = se.getSrc(); |
| UserProfile[] profiles = (UserProfile[])se.getTarget(); |
| Principal[] oldPrincipals = new Principal[] { |
| new WikiPrincipal( profiles[0].getLoginName() ), |
| new WikiPrincipal( profiles[0].getFullname() ), |
| new WikiPrincipal( profiles[0].getWikiName() ) }; |
| Principal newPrincipal = new WikiPrincipal( profiles[1].getFullname() ); |
| |
| // Examine each group |
| int groupsChanged = 0; |
| try |
| { |
| for ( Group group : m_groupDatabase.groups() ) |
| { |
| boolean groupChanged = false; |
| for ( Principal oldPrincipal : oldPrincipals ) |
| { |
| if ( group.isMember( oldPrincipal ) ) |
| { |
| group.remove( oldPrincipal ); |
| group.add( newPrincipal ); |
| groupChanged = true; |
| } |
| } |
| if ( groupChanged ) |
| { |
| setGroup( session, group ); |
| groupsChanged++; |
| } |
| } |
| } |
| catch ( WikiException e ) |
| { |
| // Oooo! This is really bad... |
| log.error( "Could not change user name in Group lists because of GroupDatabase error:" + e.getMessage() ); |
| } |
| log.info( "Profile name change for '" + newPrincipal.toString() + |
| "' caused " + groupsChanged + " groups to change also." ); |
| } |
| } |
| |
| } |