001: /*
002: * JSPWiki - a JSP-based WikiWiki clone. Copyright (C) 2001-2003 Janne Jalkanen
003: * (Janne.Jalkanen@iki.fi) This program is free software; you can redistribute
004: * it and/or modify it under the terms of the GNU Lesser General Public License
005: * as published by the Free Software Foundation; either version 2.1 of the
006: * License, or (at your option) any later version. This program is distributed
007: * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
008: * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
009: * See the GNU Lesser General Public License for more details. You should have
010: * received a copy of the GNU Lesser General Public License along with this
011: * program; if not, write to the Free Software Foundation, Inc., 59 Temple
012: * Place, Suite 330, Boston, MA 02111-1307 USA
013: */
014: package com.ecyrd.jspwiki.auth.authorize;
015:
016: import java.security.Principal;
017: import java.util.HashMap;
018: import java.util.HashSet;
019: import java.util.Map;
020: import java.util.Properties;
021: import java.util.Set;
022: import java.util.StringTokenizer;
023:
024: import javax.servlet.http.HttpServletRequest;
025:
026: import org.apache.commons.lang.ArrayUtils;
027: import org.apache.log4j.Logger;
028:
029: import com.ecyrd.jspwiki.NoRequiredPropertyException;
030: import com.ecyrd.jspwiki.WikiContext;
031: import com.ecyrd.jspwiki.WikiEngine;
032: import com.ecyrd.jspwiki.WikiException;
033: import com.ecyrd.jspwiki.WikiSession;
034: import com.ecyrd.jspwiki.auth.*;
035: import com.ecyrd.jspwiki.auth.user.UserProfile;
036: import com.ecyrd.jspwiki.event.WikiEvent;
037: import com.ecyrd.jspwiki.event.WikiEventListener;
038: import com.ecyrd.jspwiki.event.WikiEventManager;
039: import com.ecyrd.jspwiki.event.WikiSecurityEvent;
040: import com.ecyrd.jspwiki.ui.InputValidator;
041: import com.ecyrd.jspwiki.util.ClassUtil;
042:
043: /**
044: * <p>
045: * Facade class for storing, retrieving and managing wiki groups on behalf of
046: * AuthorizationManager, JSPs and other presentation-layer classes. GroupManager
047: * works in collaboration with a back-end {@link GroupDatabase}, which persists
048: * groups to permanent storage.
049: * </p>
050: * <p>
051: * <em>Note: prior to JSPWiki 2.4.19, GroupManager was an interface; it
052: * is now a concrete, final class. The aspects of GroupManager which previously
053: * extracted group information from storage (e.g., wiki pages) have been
054: * refactored into the GroupDatabase interface.</em>
055: * </p>
056: * @author Andrew Jaquith
057: * @since 2.4.19
058: */
059: public final class GroupManager implements Authorizer,
060: WikiEventListener {
061: /** Key used for adding UI messages to a user's WikiSession. */
062: public static final String MESSAGES_KEY = "group";
063:
064: private static final String PROP_GROUPDATABASE = "jspwiki.groupdatabase";
065:
066: static final Logger log = Logger.getLogger(GroupManager.class);
067:
068: protected WikiEngine m_engine;
069:
070: protected WikiEventListener m_groupListener;
071:
072: private GroupDatabase m_groupDatabase = null;
073:
074: /** Map with GroupPrincipals as keys, and Groups as values */
075: private final Map m_groups = new HashMap();
076:
077: /**
078: * <p>
079: * Returns a GroupPrincipal matching a given name. If a group cannot be
080: * found, return <code>null</code>.
081: * </p>
082: * @param name Name of the group. This is case-sensitive.
083: * @return A DefaultGroup instance.
084: */
085: public Principal findRole(String name) {
086: try {
087: Group group = getGroup(name);
088: return group.getPrincipal();
089: } catch (NoSuchPrincipalException e) {
090: return null;
091: }
092: }
093:
094: /**
095: * Returns the Group matching a given name. If the group cannot be found,
096: * this method throws a <code>NoSuchPrincipalException</code>.
097: * @param name the name of the group to find
098: * @return the group
099: * @throws NoSuchPrincipalException if the group cannot be found
100: */
101: public final Group getGroup(String name)
102: throws NoSuchPrincipalException {
103: Group group = (Group) m_groups.get(new GroupPrincipal(name));
104: if (group != null) {
105: return group;
106: }
107: throw new NoSuchPrincipalException("Group " + name
108: + " not found.");
109: }
110:
111: /**
112: * Returns the current external {@link GroupDatabase} in use. This method
113: * is guaranteed to return a properly-initialized GroupDatabase, unless
114: * it could not be initialized. In that case, this method throws
115: * a {@link com.ecyrd.jspwiki.WikiException}. The GroupDatabase
116: * is lazily initialized.
117: * @throws com.ecyrd.jspwiki.auth.WikiSecurityException if the GroupDatabase could
118: * not be initialized
119: * @return the current GroupDatabase
120: * @since 2.3
121: */
122: public final GroupDatabase getGroupDatabase()
123: throws WikiSecurityException {
124: if (m_groupDatabase != null) {
125: return m_groupDatabase;
126: }
127:
128: String dbClassName = "<unknown>";
129: String dbInstantiationError = null;
130: Throwable cause = null;
131: try {
132: Properties props = m_engine.getWikiProperties();
133: dbClassName = props.getProperty(PROP_GROUPDATABASE);
134: if (dbClassName == null) {
135: dbClassName = XMLGroupDatabase.class.getName();
136: }
137: log.info("Attempting to load group database class "
138: + dbClassName);
139: Class dbClass = ClassUtil.findClass(
140: "com.ecyrd.jspwiki.auth.authorize", dbClassName);
141: m_groupDatabase = (GroupDatabase) dbClass.newInstance();
142: m_groupDatabase.initialize(m_engine, m_engine
143: .getWikiProperties());
144: log.info("Group database initialized.");
145: } catch (ClassNotFoundException e) {
146: log.error("GroupDatabase class " + dbClassName
147: + " cannot be found.", e);
148: dbInstantiationError = "Failed to locate GroupDatabase class "
149: + dbClassName;
150: cause = e;
151: } catch (InstantiationException e) {
152: log.error("GroupDatabase class " + dbClassName
153: + " cannot be created.", e);
154: dbInstantiationError = "Failed to create GroupDatabase class "
155: + dbClassName;
156: cause = e;
157: } catch (IllegalAccessException e) {
158: log.error(
159: "You are not allowed to access group database class "
160: + dbClassName + ".", e);
161: dbInstantiationError = "Access GroupDatabase class "
162: + dbClassName + " denied";
163: cause = e;
164: } catch (NoRequiredPropertyException e) {
165: log.error("Missing property: " + e.getMessage() + ".");
166: dbInstantiationError = "Missing property: "
167: + e.getMessage();
168: cause = e;
169: }
170:
171: if (dbInstantiationError != null) {
172: throw new WikiSecurityException(dbInstantiationError
173: + " Cause: "
174: + (cause != null ? cause.getMessage() : ""));
175: }
176:
177: return m_groupDatabase;
178: }
179:
180: /**
181: * Returns an array of GroupPrincipals this GroupManager knows about. This
182: * method will return an array of GroupPrincipal objects corresponding to
183: * the wiki groups managed by this class. This method actually returns a
184: * defensive copy of an internally stored hashmap.
185: * @return an array of Principals representing the roles
186: */
187: public final Principal[] getRoles() {
188: return (Principal[]) m_groups.keySet().toArray(
189: new Principal[m_groups.size()]);
190: }
191:
192: /**
193: * Initializes the group cache by initializing the group database and
194: * obtaining a list of all of the groups it stores.
195: * @param engine the wiki engine
196: * @param props the properties used to initialize the wiki engine
197: * @see GroupDatabase#initialize(com.ecyrd.jspwiki.WikiEngine,
198: * java.util.Properties)
199: * @see GroupDatabase#groups()
200: * @throws WikiSecurityException if GroupManager cannot be initialized
201: */
202: public final void initialize(WikiEngine engine, Properties props)
203: throws WikiSecurityException {
204: m_engine = engine;
205:
206: try {
207: m_groupDatabase = getGroupDatabase();
208: } catch (WikiException e) {
209: throw new WikiSecurityException(e.getMessage());
210: }
211:
212: // Load all groups from the database into the cache
213: Group[] groups = m_groupDatabase.groups();
214: synchronized (m_groups) {
215: for (int i = 0; i < groups.length; i++) {
216: Group group = groups[i];
217: // Add new group to cache; fire GROUP_ADD event
218: m_groups.put(group.getPrincipal(), group);
219: fireEvent(WikiSecurityEvent.GROUP_ADD, group);
220: }
221: }
222:
223: // Make the GroupManager listen for WikiEvents (WikiSecurityEvents for changed user profiles)
224: engine.getUserManager().addWikiEventListener(this );
225:
226: // Success!
227: log
228: .info("Authorizer GroupManager initialized successfully; loaded "
229: + groups.length + " group(s).");
230:
231: }
232:
233: /**
234: * <p>
235: * Determines whether the Subject associated with a WikiSession is in a
236: * particular role. This method takes two parameters: the WikiSession
237: * containing the subject and the desired role ( which may be a Role or a
238: * Group). If either parameter is <code>null</code>, or if the user is
239: * not authenticated, this method returns <code>false</code>.
240: * </p>
241: * <p>
242: * With respect to this implementation, the supplied Principal must be a
243: * GroupPrincipal. The Subject posesses the "role" if it the session is
244: * authenticated <em>and</em> a Subject's principal is a member of the
245: * corresponding Group. This method simply finds the Group in question, then
246: * delegates to {@link Group#isMember(Principal)} for each of the principals
247: * in the Subject's principal set.
248: * </p>
249: * @param session the current WikiSession
250: * @param role the role to check
251: * @return <code>true</code> if the user is considered to be in the role,
252: * <code>false</code> otherwise
253: */
254: public final boolean isUserInRole(WikiSession session,
255: Principal role) {
256: // Always return false if session/role is null, or if
257: // role isn't a GroupPrincipal
258: if (session == null || role == null
259: || !(role instanceof GroupPrincipal)
260: || !session.isAuthenticated()) {
261: return false;
262: }
263:
264: // Get the group we're examining
265: Group group = (Group) m_groups.get(role);
266: if (group == null) {
267: return false;
268: }
269:
270: // Check each user principal to see if it belongs to the group
271: Principal[] principals = session.getPrincipals();
272: for (int i = 0; i < principals.length; i++) {
273: if (AuthenticationManager.isUserPrincipal(principals[i])
274: && group.isMember(principals[i])) {
275: return true;
276: }
277: }
278: return false;
279: }
280:
281: /**
282: * <p>
283: * Extracts group name and members from passed parameters and populates an
284: * existing Group with them. The Group will either be a copy of an existing
285: * Group (if one can be found), or a new, unregistered Group (if not).
286: * Optionally, this method can throw a WikiSecurityException if the Group
287: * does not yet exist in the GroupManager cache.
288: * </p>
289: * <p>
290: * The <code>group</code> parameter in the HTTP request contains the Group
291: * name to look up and populate. The <code>members</code> parameter
292: * contains the member list. If these differ from those in the existing
293: * group, the passed values override the old values.
294: * </p>
295: * <p>
296: * This method does not commit the new Group to the GroupManager cache. To
297: * do that, use {@link #setGroup(WikiSession, Group)}.
298: * </p>
299: * @param name the name of the group to construct
300: * @param memberLine the line of text containing the group membership list
301: * @param create whether this method should create a new, empty Group if one
302: * with the requested name is not found. If <code>false</code>,
303: * groups that do not exist will cause a
304: * <code>NoSuchPrincipalException</code> to be thrown
305: * @return a new, populated group
306: * @see com.ecyrd.jspwiki.auth.authorize.Group#RESTRICTED_GROUPNAMES
307: * @throws WikiSecurityException if the group name isn't allowed, or if
308: * <code>create</code> is <code>false</code>
309: * and the Group named <code>name</code> does not exist
310: */
311: public final Group parseGroup(String name, String memberLine,
312: boolean create) throws WikiSecurityException {
313: // If null name parameter, it's because someone's creating a new group
314: if (name == null) {
315: if (create) {
316: name = "MyGroup";
317: } else {
318: throw new WikiSecurityException(
319: "Group name cannot be blank.");
320: }
321: } else if (ArrayUtils.contains(Group.RESTRICTED_GROUPNAMES,
322: name)) {
323: // Certain names are forbidden
324: throw new WikiSecurityException("Illegal group name: "
325: + name);
326: }
327: name = name.trim();
328:
329: // Normalize the member line
330: if (InputValidator.isBlank(memberLine)) {
331: memberLine = "";
332: }
333: memberLine = memberLine.trim();
334:
335: // Create or retrieve the group (may have been previously cached)
336: Group group = new Group(name, m_engine.getApplicationName());
337: try {
338: Group existingGroup = getGroup(name);
339:
340: // If existing, clone it
341: group.setCreator(existingGroup.getCreator());
342: group.setCreated(existingGroup.getCreated());
343: group.setModifier(existingGroup.getModifier());
344: group.setLastModified(existingGroup.getLastModified());
345: Principal[] existingMembers = existingGroup.members();
346: for (int i = 0; i < existingMembers.length; i++) {
347: group.add(existingMembers[i]);
348: }
349: } catch (NoSuchPrincipalException e) {
350: // It's a new group.... throw error if we don't create new ones
351: if (!create) {
352: throw new NoSuchPrincipalException("Group '" + name
353: + "' does not exist.");
354: }
355: }
356:
357: // If passed members not empty, overwrite
358: String[] members = extractMembers(memberLine);
359: if (members.length > 0) {
360: group.clear();
361: for (int i = 0; i < members.length; i++) {
362: group.add(new WikiPrincipal(members[i]));
363: }
364: }
365:
366: return group;
367: }
368:
369: /**
370: * <p>
371: * Extracts group name and members from the HTTP request and populates an
372: * existing Group with them. The Group will either be a copy of an existing
373: * Group (if one can be found), or a new, unregistered Group (if not).
374: * Optionally, this method can throw a WikiSecurityException if the Group
375: * does not yet exist in the GroupManager cache.
376: * </p>
377: * <p>
378: * The <code>group</code> parameter in the HTTP request contains the Group
379: * name to look up and populate. The <code>members</code> parameter
380: * contains the member list. If these differ from those in the existing
381: * group, the passed values override the old values.
382: * </p>
383: * <p>
384: * This method does not commit the new Group to the GroupManager cache. To
385: * do that, use {@link #setGroup(WikiSession, Group)}.
386: * </p>
387: * @param context the current wiki context
388: * @param create whether this method should create a new, empty Group if one
389: * with the requested name is not found. If <code>false</code>,
390: * groups that do not exist will cause a
391: * <code>NoSuchPrincipalException</code> to be thrown
392: * @return a new, populated group
393: * @throws WikiSecurityException if the group name isn't allowed, or if
394: * <code>create</code> is <code>false</code>
395: * and the Group does not exist
396: */
397: public final Group parseGroup(WikiContext context, boolean create)
398: throws WikiSecurityException {
399: // Extract parameters
400: HttpServletRequest request = context.getHttpRequest();
401: String name = request.getParameter("group");
402: String memberLine = request.getParameter("members");
403:
404: // Create the named group; we pass on any NoSuchPrincipalExceptions
405: // that may be thrown if create == false, or WikiSecurityExceptions
406: Group group = parseGroup(name, memberLine, create);
407:
408: // If no members, add the current user by default
409: if (group.members().length == 0) {
410: group.add(context.getWikiSession().getUserPrincipal());
411: }
412:
413: return group;
414: }
415:
416: /**
417: * Removes a named Group from the group database. If not found, throws a
418: * <code>NoSuchPrincipalException</code>. After removal, this method will
419: * commit the delete to the back-end group database. It will also fire a
420: * {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#GROUP_REMOVE} event with
421: * the GroupManager instance as the source and the Group as target.
422: * If <code>index</code> is <code>null</code>, this method throws
423: * an {@link IllegalArgumentException}.
424: * @param index the group to remove
425: * @throws WikiSecurityException if the Group cannot be removed by
426: * the back-end
427: * @see com.ecyrd.jspwiki.auth.authorize.GroupDatabase#delete(Group)
428: */
429: public final void removeGroup(String index)
430: throws WikiSecurityException {
431: if (index == null) {
432: throw new IllegalArgumentException("Group cannot be null.");
433: }
434:
435: Group group = (Group) m_groups.get(new GroupPrincipal(index));
436: if (group == null) {
437: throw new NoSuchPrincipalException("Group " + index
438: + " not found");
439: }
440:
441: // Delete the group
442: // TODO: need rollback procedure
443: synchronized (m_groups) {
444: m_groups.remove(group.getPrincipal());
445: }
446: m_groupDatabase.delete(group);
447: fireEvent(WikiSecurityEvent.GROUP_REMOVE, group);
448: }
449:
450: /**
451: * <p>
452: * Saves the {@link Group} created by a user in a wiki session. This method
453: * registers the Group with the GroupManager and saves it to the back-end
454: * database. If an existing Group with the same name already exists, the new
455: * group will overwrite it. After saving the Group, the group database
456: * changes are committed.
457: * </p>
458: * <p>
459: * This method fires the following events:
460: * </p>
461: * <ul>
462: * <li><strong>When creating a new Group</strong>, this method fires a
463: * {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#GROUP_ADD} with the
464: * GroupManager instance as its source and the new Group as the target.</li>
465: * <li><strong>When overwriting an existing Group</strong>, this method
466: * fires a new {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#GROUP_REMOVE}
467: * with this GroupManager instance as the source, and the new Group as the
468: * target. It then fires a
469: * {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#GROUP_ADD} event with the
470: * same source and target.</li>
471: * </ul>
472: * <p>
473: * In addition, if the save or commit actions fail, this method will attempt
474: * to restore the older version of the wiki group if it exists. This will
475: * result in a <code>GROUP_REMOVE</code> event (for the new version of the
476: * Group) followed by a <code>GROUP_ADD</code> event (to indicate
477: * restoration of the old version).
478: * </p>
479: * <p>
480: * This method will register the new Group with the GroupManager. For example,
481: * {@link com.ecyrd.jspwiki.auth.AuthenticationManager} attaches each
482: * WikiSession as a GroupManager listener. Thus, the act of registering a
483: * Group with <code>setGroup</code> means that all WikiSessions will
484: * automatically receive group add/change/delete events immediately.
485: * </p>
486: * @param session the wiki session, which may not be <code>null</code>
487: * @param group the Group, which may not be <code>null</code>
488: * @throws WikiSecurityException if the Group cannot be saved by the back-end
489: */
490: public final void setGroup(WikiSession session, Group group)
491: throws WikiSecurityException {
492: // TODO: check for appropriate permissions
493:
494: // If group already exists, delete it; fire GROUP_REMOVE event
495: Group oldGroup = (Group) m_groups.get(group.getPrincipal());
496: if (oldGroup != null) {
497: fireEvent(WikiSecurityEvent.GROUP_REMOVE, oldGroup);
498: synchronized (m_groups) {
499: m_groups.remove(oldGroup.getPrincipal());
500: }
501: }
502:
503: // Copy existing modifier info & timestamps
504: if (oldGroup != null) {
505: group.setCreator(oldGroup.getCreator());
506: group.setCreated(oldGroup.getCreated());
507: group.setModifier(oldGroup.getModifier());
508: group.setLastModified(oldGroup.getLastModified());
509: }
510:
511: // Add new group to cache; announce GROUP_ADD event
512: synchronized (m_groups) {
513: m_groups.put(group.getPrincipal(), group);
514: }
515: fireEvent(WikiSecurityEvent.GROUP_ADD, group);
516:
517: // Save the group to back-end database; if it fails,
518: // roll back to previous state. Note that the back-end
519: // MUST timestammp the create/modify fields in the Group.
520: try {
521: m_groupDatabase.save(group, session.getUserPrincipal());
522: }
523:
524: // We got an exception! Roll back...
525: catch (WikiSecurityException e) {
526: if (oldGroup != null) {
527: // Restore previous version, re-throw...
528: fireEvent(WikiSecurityEvent.GROUP_REMOVE, group);
529: fireEvent(WikiSecurityEvent.GROUP_ADD, oldGroup);
530: synchronized (m_groups) {
531: m_groups.put(oldGroup.getPrincipal(), oldGroup);
532: }
533: throw new WikiSecurityException(e.getMessage()
534: + " (rolled back to previous version).");
535: }
536: // Re-throw security exception
537: throw new WikiSecurityException(e.getMessage());
538: }
539: }
540:
541: /**
542: * Validates a Group, and appends any errors to the session errors list. Any
543: * validation errors are added to the wiki session's messages collection
544: * (see {@link WikiSession#getMessages()}.
545: * @param context the current wiki context
546: * @param group the supplied Group
547: */
548: public final void validateGroup(WikiContext context, Group group) {
549: WikiSession session = context.getWikiSession();
550: InputValidator validator = new InputValidator(MESSAGES_KEY,
551: session);
552:
553: // Name cannot be null or one of the restricted names
554: try {
555: checkGroupName(session, group.getName());
556: } catch (WikiSecurityException e) {
557:
558: }
559:
560: // Member names must be "safe" strings
561: Principal[] members = group.members();
562: for (int i = 0; i < members.length; i++) {
563: validator.validateNotNull(members[i].getName(),
564: "Full name", InputValidator.ID);
565: }
566: }
567:
568: /**
569: * Extracts carriage-return separated members into a Set of String objects.
570: * @param memberLine the list of members
571: * @return the list of members
572: */
573: protected final String[] extractMembers(String memberLine) {
574: Set members = new HashSet();
575: if (memberLine != null) {
576: StringTokenizer tok = new StringTokenizer(memberLine, "\n");
577: while (tok.hasMoreTokens()) {
578: String uid = tok.nextToken().trim();
579: if (uid != null && uid.length() > 0) {
580: members.add(uid);
581: }
582: }
583: }
584: return (String[]) members.toArray(new String[members.size()]);
585: }
586:
587: /**
588: * Checks if a String is blank or a restricted Group name, and if it is,
589: * appends an error to the WikiSession's message list.
590: * @param session the wiki session
591: * @param name the Group name to test
592: * @throws WikiSecurityException if <code>session</code> is
593: * <code>null</code> or the Group name is illegal
594: * @see Group#RESTRICTED_GROUPNAMES
595: */
596: protected final void checkGroupName(WikiSession session, String name)
597: throws WikiSecurityException {
598: //TODO: groups cannot have the same name as a user
599:
600: if (session == null) {
601: throw new WikiSecurityException("Session cannot be null.");
602: }
603:
604: // Name cannot be null
605: InputValidator validator = new InputValidator(MESSAGES_KEY,
606: session);
607: validator.validateNotNull(name, "Group name");
608:
609: // Name cannot be one of the restricted names either
610: if (ArrayUtils.contains(Group.RESTRICTED_GROUPNAMES, name)) {
611: throw new WikiSecurityException("The group name '" + name
612: + "' is illegal. Choose another.");
613: }
614: }
615:
616: // events processing .......................................................
617:
618: /**
619: * Registers a WikiEventListener with this instance.
620: * This is a convenience method.
621: * @param listener the event listener
622: */
623: public final synchronized void addWikiEventListener(
624: WikiEventListener listener) {
625: WikiEventManager.addWikiEventListener(this , listener);
626: }
627:
628: /**
629: * Un-registers a WikiEventListener with this instance.
630: * This is a convenience method.
631: * @param listener the event listener
632: */
633: public final synchronized void removeWikiEventListener(
634: WikiEventListener listener) {
635: WikiEventManager.removeWikiEventListener(this , listener);
636: }
637:
638: /**
639: * Fires a WikiSecurityEvent of the provided type, Principal and target Object
640: * to all registered listeners.
641: *
642: * @see com.ecyrd.jspwiki.event.WikiSecurityEvent
643: * @param type the event type to be fired
644: * @param target the changed Object, which may be <code>null</code>
645: */
646: protected final void fireEvent(int type, Object target) {
647: if (WikiEventManager.isListening(this )) {
648: WikiEventManager.fireEvent(this , new WikiSecurityEvent(
649: this , type, target));
650: }
651: }
652:
653: /**
654: * Listens for {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#PROFILE_NAME_CHANGED}
655: * events. If a user profile's name changes, each group is inspected. If an entry contains
656: * a name that has changed, it is replaced with the new one. No group events are emitted
657: * as a consequence of this method, because the group memberships are still the same; it is
658: * only the representations of the names within that are changing.
659: * @param event the incoming event
660: */
661: public void actionPerformed(WikiEvent event) {
662: if (!(event instanceof WikiSecurityEvent)) {
663: return;
664: }
665:
666: WikiSecurityEvent se = (WikiSecurityEvent) event;
667: if (se.getType() == WikiSecurityEvent.PROFILE_NAME_CHANGED) {
668: WikiSession session = (WikiSession) se.getSource();
669: UserProfile[] profiles = (UserProfile[]) se.getTarget();
670: Principal[] oldPrincipals = new Principal[] {
671: new WikiPrincipal(profiles[0].getLoginName()),
672: new WikiPrincipal(profiles[0].getFullname()),
673: new WikiPrincipal(profiles[0].getWikiName()) };
674: Principal newPrincipal = new WikiPrincipal(profiles[1]
675: .getFullname());
676:
677: // Examine each group
678: int groupsChanged = 0;
679: try {
680: Group[] groups = m_groupDatabase.groups();
681: for (int i = 0; i < groups.length; i++) {
682: boolean groupChanged = false;
683: Group group = groups[i];
684: for (int j = 0; j < oldPrincipals.length; j++) {
685: if (group.isMember(oldPrincipals[j])) {
686: group.remove(oldPrincipals[j]);
687: group.add(newPrincipal);
688: groupChanged = true;
689: }
690: }
691: if (groupChanged) {
692: setGroup(session, group);
693: groupsChanged++;
694: }
695: }
696: } catch (WikiException e) {
697: // Oooo! This is really bad...
698: log
699: .error("Could not change user name in Group lists because of GroupDatabase error:"
700: + e.getMessage());
701: }
702: log.info("Profile name change for '"
703: + newPrincipal.toString() + "' caused "
704: + groupsChanged + " groups to change also.");
705: }
706: }
707:
708: }
|