Source Code Cross Referenced for WikiSession.java in  » Wiki-Engine » JSPWiki » com » ecyrd » jspwiki » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Wiki Engine » JSPWiki » com.ecyrd.jspwiki 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:            JSPWiki - a JSP-based WikiWiki clone.
003:
004:            Copyright (C) 2001-2005 The JSPWiki Development Group
005:
006:            This program is free software; you can redistribute it and/or modify
007:            it under the terms of the GNU Lesser General Public License as published by
008:            the Free Software Foundation; either version 2.1 of the License, or
009:            (at your option) any later version.
010:
011:            This program is distributed in the hope that it will be useful,
012:            but WITHOUT ANY WARRANTY; without even the implied warranty of
013:            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014:            GNU Lesser General Public License for more details.
015:
016:            You should have received a copy of the GNU Lesser General Public License
017:            along with this program; if not, write to the Free Software
018:            Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019:         */
020:        package com.ecyrd.jspwiki;
021:
022:        import java.security.AccessControlException;
023:        import java.security.Principal;
024:        import java.security.PrivilegedAction;
025:        import java.util.*;
026:
027:        import javax.security.auth.Subject;
028:        import javax.security.auth.callback.CallbackHandler;
029:        import javax.security.auth.login.LoginContext;
030:        import javax.security.auth.login.LoginException;
031:        import javax.servlet.http.HttpServletRequest;
032:        import javax.servlet.http.HttpSession;
033:
034:        import org.apache.log4j.Logger;
035:
036:        import com.ecyrd.jspwiki.auth.*;
037:        import com.ecyrd.jspwiki.auth.authorize.Group;
038:        import com.ecyrd.jspwiki.auth.authorize.GroupManager;
039:        import com.ecyrd.jspwiki.auth.authorize.Role;
040:        import com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule;
041:        import com.ecyrd.jspwiki.auth.login.PrincipalWrapper;
042:        import com.ecyrd.jspwiki.auth.user.UserDatabase;
043:        import com.ecyrd.jspwiki.auth.user.UserProfile;
044:        import com.ecyrd.jspwiki.event.WikiEvent;
045:        import com.ecyrd.jspwiki.event.WikiEventListener;
046:        import com.ecyrd.jspwiki.event.WikiSecurityEvent;
047:
048:        /**
049:         * <p>Represents a long-running wiki session, with an associated user Principal,
050:         * user Subject, and authentication status. This class is initialized with
051:         * minimal, default-deny values: authentication is set to <code>false</code>,
052:         * and the user principal is set to <code>null</code>.</p>
053:         * <p>The WikiSession class allows callers to:</p>
054:         * <ul>
055:         *   <li>Obtain the authentication status of the user via
056:         *     {@link #isAnonymous()} and {@link #isAuthenticated()}</li>
057:         *   <li>Query the session for Principals representing the
058:         *     user's identity via {@link #getLoginPrincipal()},
059:         *     {@link #getUserPrincipal()} and {@link #getPrincipals()}</li>
060:         *   <li>Store, retrieve and clear UI messages via
061:         *     {@link #addMessage(String)}, {@link #getMessages(String)}
062:         *     and {@link #clearMessages(String)}</li>
063:         * </ul>
064:         * <p>To keep track of the Principals each user posseses, each WikiSession
065:         * stores a JAAS Subject. Various login processes add or remove Principals
066:         * when users authenticate or log out.</p>
067:         * <p>WikiSession implements the {@link com.ecyrd.jspwiki.event.WikiEventListener}
068:         * interface and listens for group add/change/delete events fired by
069:         * event sources the WikiSession is registered with. Normally,
070:         * {@link com.ecyrd.jspwiki.auth.AuthenticationManager} registers each WikiSession
071:         * with the {@link com.ecyrd.jspwiki.auth.authorize.GroupManager}
072:         * so it can catch group events. Thus, when a user is added to a
073:         * {@link com.ecyrd.jspwiki.auth.authorize.Group}, a corresponding
074:         * {@link com.ecyrd.jspwiki.auth.GroupPrincipal} is injected into
075:         * the Subject's Principal set. Likewise, when the user is removed from
076:         * the Group or the Group is deleted, the GroupPrincipal is removed
077:         * from the Subject. The effect that this strategy produces is extremely
078:         * beneficial: when someone adds a user to a wiki group, that user
079:         * <em>immediately</em> gains the privileges associated with that
080:         * group; he or she does not need to re-authenticate.
081:         * </p>
082:         * <p>In addition to methods for examining individual <code>WikiSession</code>
083:         * objects, this class also contains a number of static methods for
084:         * managing WikiSessions for an entire wiki. These methods allow callers
085:         * to find, query and remove WikiSession objects, and
086:         * to obtain a list of the current wiki session users.</p>
087:         * <p>WikiSession encloses a protected static class, {@link SessionMonitor},
088:         * to keep track of WikiSessions registered with each wiki.</p>
089:         * @author Andrew R. Jaquith
090:         */
091:        public final class WikiSession implements  WikiEventListener {
092:
093:            /** An anonymous user's session status. */
094:            public static final String ANONYMOUS = "anonymous";
095:
096:            /** An asserted user's session status. */
097:            public static final String ASSERTED = "asserted";
098:
099:            /** An authenticated user's session status. */
100:            public static final String AUTHENTICATED = "authenticated";
101:
102:            private static final int ONE = 48;
103:
104:            private static final int NINE = 57;
105:
106:            private static final int DOT = 46;
107:
108:            private static final Logger log = Logger
109:                    .getLogger(WikiSession.class);
110:
111:            private static final String ALL = "*";
112:
113:            private static ThreadLocal c_guestSession = new ThreadLocal();
114:
115:            private final Subject m_subject = new Subject();
116:
117:            private final Map m_messages = new HashMap();
118:
119:            private String m_cachedCookieIdentity = null;
120:
121:            private String m_cachedRemoteUser = null;
122:
123:            private Principal m_cachedUserPrincipal = null;
124:
125:            /** The WikiEngine that created this session. */
126:            private WikiEngine m_engine = null;
127:
128:            private boolean m_isNew = true;
129:
130:            private String m_status = ANONYMOUS;
131:
132:            private Principal m_userPrincipal = WikiPrincipal.GUEST;
133:
134:            private Principal m_loginPrincipal = WikiPrincipal.GUEST;
135:
136:            private Locale m_cachedLocale = Locale.getDefault();
137:
138:            /**
139:             * Returns <code>true</code> if one of this WikiSession's user Principals
140:             * can be shown to belong to a particular wiki group. If the user is
141:             * not authenticated, this method will always return <code>false</code>.
142:             * @param group the group to test
143:             * @return the result
144:             */
145:            protected final boolean isInGroup(Group group) {
146:                Principal[] principals = getPrincipals();
147:                for (int i = 0; i < principals.length; i++) {
148:                    if (isAuthenticated() && group.isMember(principals[i])) {
149:                        return true;
150:                    }
151:                }
152:                return false;
153:            }
154:
155:            /**
156:             * Returns <code>true</code> if the wiki session is newly initialized.
157:             *
158:             * @return True, if this is a new session.
159:             */
160:            protected final boolean isNew() {
161:                return m_isNew;
162:            }
163:
164:            /**
165:             * Sets the status of this wiki session.
166:             * @param isNew whether this session should be considered "new".
167:             */
168:            protected final void setNew(boolean isNew) {
169:                m_isNew = isNew;
170:            }
171:
172:            /**
173:             * Private constructor to prevent WikiSession from being instantiated
174:             * directly.
175:             */
176:            private WikiSession() {
177:            }
178:
179:            /**
180:             * Returns <code>true</code> if the user is considered asserted via
181:             * a session cookie; that is, the Subject contains the Principal
182:             * Role.ASSERTED.
183:             * @return Returns <code>true</code> if the user is asserted
184:             */
185:            public final boolean isAsserted() {
186:                return m_subject.getPrincipals().contains(Role.ASSERTED);
187:            }
188:
189:            /**
190:             * Returns the authentication status of the user's session. The user is
191:             * considered authenticated if the Subject contains the Principal
192:             * Role.AUTHENTICATED. If this method determines that an earlier
193:             * LoginModule did not inject Role.AUTHENTICATED, it will inject one
194:             * if the user is not anonymous <em>and</em> not asserted.
195:             * @return Returns <code>true</code> if the user is authenticated
196:             */
197:            public final boolean isAuthenticated() {
198:                // If Role.AUTHENTICATED is in principals set, always return true.
199:                if (m_subject.getPrincipals().contains(Role.AUTHENTICATED)) {
200:                    return true;
201:                }
202:
203:                // With non-JSPWiki LoginModules, the role may not be there, so
204:                // we need to add it if the user really is authenticated.
205:                if (!isAnonymous() && !isAsserted()) {
206:                    // Inject AUTHENTICATED role
207:                    m_subject.getPrincipals().add(Role.AUTHENTICATED);
208:                    return true;
209:                }
210:
211:                return false;
212:            }
213:
214:            /**
215:             * <p>Determines whether the current session is anonymous. This will be
216:             * true if any of these conditions are true:</p>
217:             * <ul>
218:             *   <li>The session's Principal set contains
219:             *       {@link com.ecyrd.jspwiki.auth.authorize.Role#ANONYMOUS}</li>
220:             *   <li>The session's Principal set contains
221:             *       {@link com.ecyrd.jspwiki.auth.WikiPrincipal#GUEST}</li>
222:             *   <li>The Principal returned by {@link #getUserPrincipal()} evaluates
223:             *       to an IP address.</li>
224:             * </ul>
225:             * <p>The criteria above are listed in the order in which they are
226:             * evaluated.</p>
227:             * @return whether the current user's identity is equivalent to an IP
228:             * address
229:             */
230:            public final boolean isAnonymous() {
231:                Set principals = m_subject.getPrincipals();
232:                return principals.contains(Role.ANONYMOUS)
233:                        || principals.contains(WikiPrincipal.GUEST)
234:                        || isIPV4Address(getUserPrincipal().getName());
235:            }
236:
237:            /**
238:             * Creates and returns a new login context for this wiki session.
239:             * This method is called by
240:             * {@link com.ecyrd.jspwiki.auth.AuthenticationManager}.
241:             * @param application the name of the application
242:             * @param handler the callback handler
243:             * @return A new login context
244:             * @throws LoginException If the login context cannot be created
245:             */
246:            public final LoginContext getLoginContext(String application,
247:                    CallbackHandler handler) throws LoginException {
248:                return new LoginContext(application, m_subject, handler);
249:            }
250:
251:            /**
252:             * <p> Returns the Principal used to log in to an authenticated session. The
253:             * login principal is determined by examining the Subject's Principal set
254:             * for PrincipalWrappers or WikiPrincipals with type designator
255:             * <code>LOGIN_NAME</code>; the first one found is the login principal.
256:             * If one is not found, this method returns the first principal that isn't
257:             * of type Role or GroupPrincipal. If neither of these conditions hold, this method returns
258:             * {@link com.ecyrd.jspwiki.auth.WikiPrincipal#GUEST}.
259:             * @return the login Principal. If it is a PrincipalWrapper containing an
260:             * externally-provided Principal, the object returned is the Principal, not
261:             * the wrapper around it.
262:             */
263:            public final Principal getLoginPrincipal() {
264:                if (m_loginPrincipal instanceof  PrincipalWrapper) {
265:                    return ((PrincipalWrapper) m_loginPrincipal).getPrincipal();
266:                }
267:                return m_loginPrincipal;
268:            }
269:
270:            /**
271:             * <p>Returns the primary user Principal associated with this session. The
272:             * primary user principal is determined as follows:</p> <ol> <li>If the
273:             * Subject's Principal set contains WikiPrincipals, the first WikiPrincipal
274:             * with type designator <code>WIKI_NAME</code> or (alternatively)
275:             * <code>FULL_NAME</code> is the primary Principal.</li>
276:             *   <li>For all other cases, the first Principal in the Subject's principal
277:             *       collection that that isn't of type Role or GroupPrincipal is the primary.</li>
278:             * </ol>
279:             * If no primary user Principal is found, this method returns
280:             * {@link com.ecyrd.jspwiki.auth.WikiPrincipal#GUEST}.
281:             * @return the primary user Principal
282:             */
283:            public final Principal getUserPrincipal() {
284:                if (m_loginPrincipal instanceof  PrincipalWrapper) {
285:                    return ((PrincipalWrapper) m_userPrincipal).getPrincipal();
286:                }
287:                return m_userPrincipal;
288:            }
289:
290:            /**
291:             *  Returns a cached Locale object for this user.  It's better to use
292:             *  WikiContext's corresponding getBundle() method, since that will actually
293:             *  react if the user changes the locale in the middle, but if that's not
294:             *  available (or, for some reason, you need the speed), this method can
295:             *  also be used.  The Locale expires when the WikiSession expires, and
296:             *  currently there is no way to reset the Locale.
297:             *
298:             *  @return A cached Locale object
299:             *  @since 2.5.96
300:             */
301:            public final Locale getLocale() {
302:                return m_cachedLocale;
303:            }
304:
305:            /**
306:             * Adds a message to the generic list of messages associated with the
307:             * session. These messages retain their order of insertion and remain until
308:             * the {@link #clearMessages()} method is called.
309:             * @param message the message to add; if <code>null</code> it is ignored.
310:             */
311:            public final void addMessage(String message) {
312:                addMessage(ALL, message);
313:            }
314:
315:            /**
316:             * Adds a message to the specific set of messages associated with the
317:             * session. These messages retain their order of insertion and remain until
318:             * the {@link #clearMessages()} method is called.
319:             * @param topic the topic to associate the message to;
320:             * @param message the message to add
321:             */
322:            public final void addMessage(String topic, String message) {
323:                if (topic == null) {
324:                    throw new IllegalArgumentException(
325:                            "addMessage: topic cannot be null.");
326:                }
327:                if (message == null) {
328:                    message = "";
329:                }
330:                Set messages = (Set) m_messages.get(topic);
331:                if (messages == null) {
332:                    messages = new LinkedHashSet();
333:                    m_messages.put(topic, messages);
334:                }
335:                messages.add(message);
336:            }
337:
338:            /**
339:             * Clears all messages associated with this session.
340:             */
341:            public final void clearMessages() {
342:                m_messages.clear();
343:            }
344:
345:            /**
346:             * Clears all messages associated with a session topic.
347:             * @param topic the topic whose messages should be cleared.
348:             */
349:            public final void clearMessages(String topic) {
350:                Set messages = (Set) m_messages.get(topic);
351:                if (messages != null) {
352:                    m_messages.clear();
353:                }
354:            }
355:
356:            /**
357:             * Returns all generic messages associated with this session.
358:             * The messages stored with the session persist throughout the
359:             * session unless they have been reset with {@link #clearMessages()}.
360:             * @return the current messsages.
361:             */
362:            public final String[] getMessages() {
363:                return getMessages(ALL);
364:            }
365:
366:            /**
367:             * Returns all messages associated with a session topic.
368:             * The messages stored with the session persist throughout the
369:             * session unless they have been reset with {@link #clearMessages(String)}.
370:             * @return the current messsages.
371:             * @param topic The topic
372:             */
373:            public final String[] getMessages(String topic) {
374:                Set messages = (Set) m_messages.get(topic);
375:                if (messages == null || messages.size() == 0) {
376:                    return new String[0];
377:                }
378:                return (String[]) messages.toArray(new String[messages.size()]);
379:            }
380:
381:            /**
382:             * Returns all user Principals associated with this session. User principals
383:             * are those in the Subject's principal collection that aren't of type Role or
384:             * of type GroupPrincipal. This is a defensive copy.
385:             * @return Returns the user principal
386:             * @see com.ecyrd.jspwiki.auth.AuthenticationManager#isUserPrincipal(Principal)
387:             */
388:            public final Principal[] getPrincipals() {
389:                ArrayList principals = new ArrayList();
390:
391:                // Take the first non Role as the main Principal
392:                for (Iterator it = m_subject.getPrincipals().iterator(); it
393:                        .hasNext();) {
394:                    Principal principal = (Principal) it.next();
395:                    if (AuthenticationManager.isUserPrincipal(principal)) {
396:                        principals.add(principal);
397:                    }
398:                }
399:
400:                return (Principal[]) principals
401:                        .toArray(new Principal[principals.size()]);
402:            }
403:
404:            /**
405:             * Returns an array of Principal objects that represents the groups and
406:             * roles that the user associated with a WikiSession possesses. The array is
407:             * built by iterating through the Subject's Principal set and extracting all
408:             * Role and GroupPrincipal objects into a list. The list is returned as an
409:             * array sorted in the natural order implied by each Principal's
410:             * <code>getName</code> method. Note that this method does <em>not</em>
411:             * consult the external Authorizer or GroupManager; it relies on the
412:             * Principals that have been injected into the user's Subject at login time,
413:             * or after group creation/modification/deletion.
414:             * @return an array of Principal objects corresponding to the roles the
415:             *         Subject possesses
416:             */
417:            public final Principal[] getRoles() {
418:                Set roles = new HashSet();
419:
420:                // Add all of the Roles possessed by the Subject directly
421:                roles.addAll(m_subject.getPrincipals(Role.class));
422:
423:                // Add all of the GroupPrincipals possessed by the Subject directly
424:                roles.addAll(m_subject.getPrincipals(GroupPrincipal.class));
425:
426:                // Return a defensive copy
427:                Principal[] roleArray = (Principal[]) roles
428:                        .toArray(new Principal[roles.size()]);
429:                Arrays.sort(roleArray, WikiPrincipal.COMPARATOR);
430:                return roleArray;
431:            }
432:
433:            /**
434:             * Removes the wiki session associated with the user's HTTP request
435:             * from the cache of wiki sessions, typically as part of a logout
436:             * process.
437:             * @param engine the wiki engine
438:             * @param request the users's HTTP request
439:             */
440:            public static final void removeWikiSession(WikiEngine engine,
441:                    HttpServletRequest request) {
442:                if (engine == null || request == null) {
443:                    throw new IllegalArgumentException(
444:                            "Request or engine cannot be null.");
445:                }
446:                SessionMonitor monitor = SessionMonitor.getInstance(engine);
447:                monitor.remove(request.getSession());
448:            }
449:
450:            /**
451:             * Returns <code>true</code> if the WikiSession's Subject
452:             * possess a supplied Principal. This method eliminates the need
453:             * to externally request and inspect the JAAS subject.
454:             * @param principal the Principal to test
455:             * @return the result
456:             */
457:            public final boolean hasPrincipal(Principal principal) {
458:                return m_subject.getPrincipals().contains(principal);
459:
460:            }
461:
462:            /**
463:             * Listens for WikiEvents generated by source objects such as the
464:             * GroupManager. This method adds Principals to the private Subject managed
465:             * by the WikiSession.
466:             * @see com.ecyrd.jspwiki.event.WikiEventListener#actionPerformed(com.ecyrd.jspwiki.event.WikiEvent)
467:             * {@inheritDoc}
468:             */
469:            public final void actionPerformed(WikiEvent event) {
470:                if (event instanceof  WikiSecurityEvent) {
471:                    WikiSecurityEvent e = (WikiSecurityEvent) event;
472:                    if (e.getTarget() != null) {
473:                        switch (e.getType()) {
474:                        case WikiSecurityEvent.GROUP_ADD: {
475:                            Group group = (Group) e.getTarget();
476:                            if (isInGroup(group)) {
477:                                m_subject.getPrincipals().add(
478:                                        group.getPrincipal());
479:                            }
480:                            break;
481:                        }
482:                        case WikiSecurityEvent.GROUP_REMOVE: {
483:                            Group group = (Group) e.getTarget();
484:                            if (m_subject.getPrincipals().contains(
485:                                    group.getPrincipal())) {
486:                                m_subject.getPrincipals().remove(
487:                                        group.getPrincipal());
488:                            }
489:                            break;
490:                        }
491:                        case WikiSecurityEvent.GROUP_CLEAR_GROUPS: {
492:                            m_subject
493:                                    .getPrincipals()
494:                                    .removeAll(
495:                                            m_subject
496:                                                    .getPrincipals(GroupPrincipal.class));
497:                            break;
498:                        }
499:                        case WikiSecurityEvent.LOGIN_INITIATED: {
500:                            WikiSession target = (WikiSession) e.getTarget();
501:                            if (this .equals(target)) {
502:                                updatePrincipals();
503:                            }
504:                            break;
505:                        }
506:                        case WikiSecurityEvent.LOGIN_ASSERTED: {
507:                            WikiSession target = (WikiSession) e.getTarget();
508:                            if (this .equals(target)) {
509:                                m_status = ASSERTED;
510:                            }
511:                            break;
512:                        }
513:                        case WikiSecurityEvent.LOGIN_AUTHENTICATED: {
514:                            WikiSession target = (WikiSession) e.getTarget();
515:                            if (this .equals(target)) {
516:                                m_status = AUTHENTICATED;
517:                                injectUserProfilePrincipals(); // Add principals for the user profile
518:                                injectRolePrincipals(); // Inject role and group principals
519:                                updatePrincipals();
520:                            }
521:                            break;
522:                        }
523:                        case WikiSecurityEvent.PROFILE_SAVE: {
524:                            WikiSession source = (WikiSession) e.getSource();
525:                            if (this .equals(source)) {
526:                                injectUserProfilePrincipals(); // Add principals for the user profile
527:                                updatePrincipals();
528:                            }
529:                            break;
530:                        }
531:                        case WikiSecurityEvent.PROFILE_NAME_CHANGED: {
532:                            // Refresh user principals based on new user profile
533:                            WikiSession source = (WikiSession) e.getSource();
534:                            if (this .equals(source)) {
535:                                // To prepare for refresh, set the new full name as the primary principal
536:                                UserProfile[] profiles = (UserProfile[]) e
537:                                        .getTarget();
538:                                UserProfile newProfile = profiles[1];
539:                                if (newProfile.getFullname() == null) {
540:                                    throw new IllegalStateException(
541:                                            "User profile FullName cannot be null.");
542:                                }
543:                                m_userPrincipal = new WikiPrincipal(newProfile
544:                                        .getFullname());
545:
546:                                // Refresh principals for the user profile
547:                                injectUserProfilePrincipals();
548:                                updatePrincipals();
549:                            }
550:                            break;
551:                        }
552:
553:                            //
554:                            //  No action, if the event is not recognized.
555:                            //
556:                        default:
557:                            break;
558:                        }
559:                    }
560:                }
561:            }
562:
563:            /**
564:             * Invalidates the WikiSession and resets its Subject's
565:             * Principals to the equivalent of a "guest session".
566:             */
567:            public final void invalidate() {
568:                m_subject.getPrincipals().clear();
569:                m_subject.getPrincipals().add(WikiPrincipal.GUEST);
570:                m_subject.getPrincipals().add(Role.ANONYMOUS);
571:                m_subject.getPrincipals().add(Role.ALL);
572:                m_cachedCookieIdentity = null;
573:                m_cachedRemoteUser = null;
574:                m_cachedUserPrincipal = null;
575:            }
576:
577:            /**
578:             * Returns whether the HTTP servlet container's authentication status has
579:             * changed. Used to detect whether the container has logged in a user since
580:             * the last call to this function. This method is stateful. After calling
581:             * this function, the cached values are set to those in the current request.
582:             * If the servlet request is <code>null</code>, this method always returns
583:             * <code>false</code>. Note that once a user authenticates, the container
584:             * status for the session will <em>never</em> change again, unless the
585:             * session is invalidated by timeout or logout.
586:             * @param request the servlet request
587:             * @return <code>true</code> if the status has changed, <code>false</code>
588:             * otherwise
589:             */
590:            protected final boolean isContainerStatusChanged(
591:                    HttpServletRequest request) {
592:                if (request == null || m_status.equals(AUTHENTICATED)) {
593:                    return false;
594:                }
595:
596:                String remoteUser = request.getRemoteUser();
597:                Principal userPrincipal = request.getUserPrincipal();
598:                String cookieIdentity = CookieAssertionLoginModule
599:                        .getUserCookie(request);
600:                boolean changed = false;
601:
602:                // If request contains non-null remote user, update cached value if changed
603:                if (remoteUser != null
604:                        && !remoteUser.equals(m_cachedRemoteUser)) {
605:                    m_cachedRemoteUser = remoteUser;
606:                    log.info("Remote user changed to " + remoteUser);
607:                    changed = true;
608:                }
609:
610:                // If request contains non-null user principal, updated cached value if changed
611:                if (userPrincipal != null
612:                        && !userPrincipal.equals(m_cachedUserPrincipal)) {
613:                    m_cachedUserPrincipal = userPrincipal;
614:                    log.info("User principal changed to "
615:                            + userPrincipal.getName());
616:                    changed = true;
617:                }
618:
619:                // If cookie identity changed (to a different value or back to null), update cache
620:                if ((cookieIdentity != null && !cookieIdentity
621:                        .equals(m_cachedCookieIdentity))
622:                        || (cookieIdentity == null && m_cachedCookieIdentity != null)) {
623:                    m_cachedCookieIdentity = cookieIdentity;
624:                    log.info("Cookie changed to " + cookieIdentity);
625:                    changed = true;
626:                }
627:                return changed;
628:            }
629:
630:            /**
631:             * Injects GroupPrincipal and Role objects into the user's Principal set
632:             * based on the groups and roles the user belongs to.
633:             * For Roles, the algorithm first calls the
634:             * {@link Authorizer#getRoles()} to obtain the array of
635:             * Principals the authorizer knows about. Then, the method
636:             * {@link Authorizer#isUserInRole(WikiSession, Principal)} is
637:             * called for each Principal. If the user possesses the role,
638:             * an equivalent role Principal is injected into the user's
639:             * principal set.
640:             * Reloads user Principals into the suppplied WikiSession's Subject.
641:             * Existing Role principals are preserved; all other Principal
642:             * types are flushed and replaced by those returned by
643:             * {@link com.ecyrd.jspwiki.auth.user.UserDatabase#getPrincipals(String)}.
644:             * This method should generally be called after a user's {@link com.ecyrd.jspwiki.auth.user.UserProfile}
645:             * is saved. If the wiki session is null, or there is no matching user profile, the
646:             * method returns silently.
647:             */
648:            protected final void injectRolePrincipals() {
649:                // Get the GroupManager and test for each Group
650:                GroupManager manager = m_engine.getGroupManager();
651:                Principal[] groups = manager.getRoles();
652:                for (int i = 0; i < groups.length; i++) {
653:                    if (manager.isUserInRole(this , groups[i])) {
654:                        m_subject.getPrincipals().add(groups[i]);
655:                    }
656:                }
657:
658:                // Get the authorizer's known roles, then test for each
659:                try {
660:                    Authorizer authorizer = m_engine.getAuthorizationManager()
661:                            .getAuthorizer();
662:                    Principal[] roles = authorizer.getRoles();
663:                    for (int i = 0; i < roles.length; i++) {
664:                        Principal role = roles[i];
665:                        if (authorizer.isUserInRole(this , role)) {
666:                            String roleName = role.getName();
667:                            if (!Role.isReservedName(roleName)) {
668:                                m_subject.getPrincipals().add(
669:                                        new Role(roleName));
670:                            }
671:                        }
672:                    }
673:                } catch (WikiException e) {
674:                    log.error("Could not refresh role principals: "
675:                            + e.getMessage());
676:                }
677:            }
678:
679:            /**
680:             * Adds Principal objects to the Subject that correspond to the
681:             * logged-in user's profile attributes for the wiki name, full name
682:             * and login name. These Principals will be WikiPrincipals, and they
683:             * will replace all other WikiPrincipals in the Subject. <em>Note:
684:             * this method is never called during anonymous or asserted sessions.</em>
685:             */
686:            protected final void injectUserProfilePrincipals() {
687:                // Copy all Role and GroupPrincipal principals into a temporary cache
688:                Set oldPrincipals = m_subject.getPrincipals();
689:                Set newPrincipals = new HashSet();
690:                for (Iterator it = oldPrincipals.iterator(); it.hasNext();) {
691:                    Principal principal = (Principal) it.next();
692:                    if (AuthenticationManager.isRolePrincipal(principal)) {
693:                        newPrincipals.add(principal);
694:                    }
695:                }
696:                String searchId = getUserPrincipal().getName();
697:                if (searchId == null) {
698:                    // Oh dear, this wasn't an authenticated user after all
699:                    log
700:                            .info("Refresh principals failed because WikiSession had no user Principal; maybe not logged in?");
701:                    return;
702:                }
703:
704:                // Look up the user and go get the new Principals
705:                UserDatabase database = m_engine.getUserManager()
706:                        .getUserDatabase();
707:                if (database == null) {
708:                    throw new IllegalStateException(
709:                            "User database cannot be null.");
710:                }
711:                try {
712:                    UserProfile profile = database.find(searchId);
713:                    Principal[] principals = database.getPrincipals(profile
714:                            .getLoginName());
715:                    for (int i = 0; i < principals.length; i++) {
716:                        Principal principal = principals[i];
717:                        newPrincipals.add(principal);
718:                    }
719:
720:                    // Replace the Subject's old Principals with the new ones
721:                    oldPrincipals.clear();
722:                    oldPrincipals.addAll(newPrincipals);
723:                } catch (NoSuchPrincipalException e) {
724:                    // We will get here if the user has a principal but not a profile
725:                    // For example, it's a container-managed user who hasn't set up a profile yet
726:                    log
727:                            .warn("User profile '"
728:                                    + searchId
729:                                    + "' not found. This is normal for container-auth users who haven't set up a profile yet.");
730:                }
731:            }
732:
733:            /**
734:             * Updates the internally cached principals returned by {@link #getUserPrincipal()} and
735:             * {@link #getLoginPrincipal()}. This method is called when the WikiSession receives
736:             * the {@link com.ecyrd.jspwiki.event.WikiSecurityEvent#LOGIN_INITIATED} message.
737:             */
738:            protected final void updatePrincipals() {
739:                Set principals = m_subject.getPrincipals();
740:                m_loginPrincipal = null;
741:                m_userPrincipal = null;
742:                Principal wikinamePrincipal = null;
743:                Principal fullnamePrincipal = null;
744:                Principal otherPrincipal = null;
745:
746:                for (Iterator it = principals.iterator(); it.hasNext();) {
747:                    Principal currentPrincipal = (Principal) it.next();
748:                    if (!(currentPrincipal instanceof  Role || currentPrincipal instanceof  GroupPrincipal)) {
749:                        // For login principal, take the first PrincipalWrapper or WikiPrincipal of type LOGIN_NAME
750:                        // For user principal take the  first WikiPrincipal of type WIKI_NAME
751:                        if (currentPrincipal instanceof  PrincipalWrapper) {
752:                            m_loginPrincipal = currentPrincipal;
753:                        } else if (currentPrincipal instanceof  WikiPrincipal) {
754:                            WikiPrincipal wp = (WikiPrincipal) currentPrincipal;
755:                            if (wp.getType().equals(WikiPrincipal.LOGIN_NAME)) {
756:                                m_loginPrincipal = wp;
757:                            } else if (wp.getType().equals(
758:                                    WikiPrincipal.WIKI_NAME)) {
759:                                wikinamePrincipal = currentPrincipal;
760:                                m_userPrincipal = wp;
761:                            } else if (wp.getType().equals(
762:                                    WikiPrincipal.FULL_NAME)) {
763:                                fullnamePrincipal = currentPrincipal;
764:                            } else {
765:                                otherPrincipal = currentPrincipal;
766:                            }
767:                        } else if (otherPrincipal == null) {
768:                            otherPrincipal = currentPrincipal;
769:                        }
770:                    }
771:                }
772:                if (otherPrincipal == null) {
773:                    otherPrincipal = WikiPrincipal.GUEST;
774:                }
775:
776:                // If no login principal, use wiki name, full name or other principal (in that order)
777:                if (m_loginPrincipal == null) {
778:                    m_loginPrincipal = wikinamePrincipal;
779:                    if (m_loginPrincipal == null) {
780:                        m_loginPrincipal = fullnamePrincipal;
781:                        if (m_loginPrincipal == null) {
782:                            m_loginPrincipal = otherPrincipal;
783:                        }
784:                    }
785:                }
786:
787:                // If no user principal, use wiki name, full name or login principal (in that order)
788:                if (m_userPrincipal == null) {
789:                    m_userPrincipal = wikinamePrincipal;
790:                    if (m_userPrincipal == null) {
791:                        m_userPrincipal = fullnamePrincipal;
792:                        if (m_userPrincipal == null) {
793:                            m_userPrincipal = m_loginPrincipal;
794:                        }
795:                    }
796:                }
797:            }
798:
799:            /**
800:             * <p>Returns the status of the wiki session as a text string. Valid values are:</p>
801:             * <ul>
802:             *   <li>{@link #AUTHENTICATED}</li>
803:             *   <li>{@link #ASSERTED}</li>
804:             *   <li>{@link #ANONYMOUS}</li>
805:             * </ul>
806:             * @return the user's session status
807:             */
808:            public final String getStatus() {
809:                return m_status;
810:            }
811:
812:            /**
813:             * <p>Static factory method that returns the WikiSession object associated with
814:             * the current HTTP request. This method looks up the associated HttpSession
815:             * in an internal WeakHashMap and attempts to retrieve the WikiSession. If
816:             * not found, one is created. This method is guaranteed to always return a
817:             * WikiSession, although the authentication status is unpredictable until
818:             * the user attempts to log in. If the servlet request parameter is
819:             * <code>null</code>, a synthetic {@link #guestSession(WikiEngine)}is returned.</p>
820:             * <p>When a session is created, this method attaches a WikiEventListener
821:             * to the GroupManager so that changes to groups are detected automatically.</p>
822:             * @param engine the wiki engine
823:             * @param request the servlet request object
824:             * @return the existing (or newly created) wiki session
825:             */
826:            public static final WikiSession getWikiSession(WikiEngine engine,
827:                    HttpServletRequest request) {
828:                // If request is null, return guest session
829:                if (request == null) {
830:                    if (log.isDebugEnabled()) {
831:                        log
832:                                .debug("Looking up WikiSession for NULL HttpRequest: returning guestSession()");
833:                    }
834:                    return staticGuestSession(engine);
835:                }
836:
837:                // Look for a WikiSession associated with the user's Http Session
838:                // and create one if it isn't there yet.
839:                HttpSession session = request.getSession();
840:                SessionMonitor monitor = SessionMonitor.getInstance(engine);
841:                WikiSession wikiSession = monitor.find(session);
842:
843:                // Attach reference to wiki engine
844:                wikiSession.m_engine = engine;
845:
846:                wikiSession.m_cachedLocale = request.getLocale();
847:
848:                return wikiSession;
849:            }
850:
851:            /**
852:             * Static factory method that creates a new "guest" session containing a single
853:             * user Principal {@link com.ecyrd.jspwiki.auth.WikiPrincipal#GUEST},
854:             * plus the role principals {@link Role#ALL} and
855:             * {@link Role#ANONYMOUS}. This method also adds the session as a listener
856:             * for GroupManager, AuthenticationManager and UserManager events.
857:             * @param engine the wiki engine
858:             * @return the guest wiki session
859:             */
860:            public static final WikiSession guestSession(WikiEngine engine) {
861:                WikiSession session = new WikiSession();
862:                session.m_engine = engine;
863:                session.invalidate();
864:
865:                // Add the session as listener for GroupManager, AuthManager, UserManager events
866:                GroupManager groupMgr = engine.getGroupManager();
867:                AuthenticationManager authMgr = engine
868:                        .getAuthenticationManager();
869:                UserManager userMgr = engine.getUserManager();
870:                groupMgr.addWikiEventListener(session);
871:                authMgr.addWikiEventListener(session);
872:                userMgr.addWikiEventListener(session);
873:
874:                return session;
875:            }
876:
877:            /**
878:             *  Returns a static guest session, which is available for this
879:             *  thread only.  This guest session is used internally whenever
880:             *  there is no HttpServletRequest involved, but the request is
881:             *  done e.g. when embedding JSPWiki code.
882:             *
883:             *  @param engine WikiEngine for this session
884:             *  @return A static WikiSession which is shared by all in this
885:             *          same Thread.
886:             */
887:            // FIXME: Should really use WeakReferences to clean away unused sessions.
888:            private static WikiSession staticGuestSession(WikiEngine engine) {
889:                WikiSession session = (WikiSession) c_guestSession.get();
890:
891:                if (session == null) {
892:                    session = guestSession(engine);
893:
894:                    c_guestSession.set(session);
895:                }
896:
897:                return session;
898:            }
899:
900:            /**
901:             * Returns the total number of active wiki sessions for a
902:             * particular wiki. This method delegates to the wiki's
903:             * {@link SessionMonitor#sessions()} method.
904:             * @param engine the wiki session
905:             * @return the number of sessions
906:             */
907:            public static final int sessions(WikiEngine engine) {
908:                SessionMonitor monitor = SessionMonitor.getInstance(engine);
909:                return monitor.sessions();
910:            }
911:
912:            /**
913:             * Returns Principals representing the current users known
914:             * to a particular wiki. Each Principal will correspond to the
915:             * value returned by each WikiSession's {@link #getUserPrincipal()}
916:             * method. This method delegates to {@link SessionMonitor#userPrincipals()}.
917:             * @param engine the wiki engine
918:             * @return an array of Principal objects, sorted by name
919:             */
920:            public static final Principal[] userPrincipals(WikiEngine engine) {
921:                SessionMonitor monitor = SessionMonitor.getInstance(engine);
922:                return monitor.userPrincipals();
923:            }
924:
925:            /**
926:             * Wrapper for
927:             * {@link javax.security.auth.Subject#doAsPrivileged(Subject, java.security.PrivilegedExceptionAction, java.security.AccessControlContext)}
928:             * that executes an action with the privileges posssessed by a
929:             * WikiSession's Subject. The action executes with a <code>null</code>
930:             * AccessControlContext, which has the effect of running it "cleanly"
931:             * without the AccessControlContexts of the caller.
932:             * @param session the wiki session
933:             * @param action the privileged action
934:             * @return the result of the privileged action; may be <code>null</code>
935:             * @throws java.security.AccessControlException if the action is not permitted
936:             * by the security policy
937:             */
938:            public static final Object doPrivileged(WikiSession session,
939:                    PrivilegedAction action) throws AccessControlException {
940:                return Subject.doAsPrivileged(session.m_subject, action, null);
941:            }
942:
943:            /**
944:             * Verifies whether a String represents an IPv4 address. The algorithm is
945:             * extremely efficient and does not allocate any objects.
946:             * @param name the address to test
947:             * @return the result
948:             */
949:            protected static final boolean isIPV4Address(String name) {
950:                if (name.charAt(0) == DOT
951:                        || name.charAt(name.length() - 1) == DOT) {
952:                    return false;
953:                }
954:
955:                int[] addr = new int[] { 0, 0, 0, 0 };
956:                int currentOctet = 0;
957:                for (int i = 0; i < name.length(); i++) {
958:                    int ch = name.charAt(i);
959:                    boolean isDigit = ch >= ONE && ch <= NINE;
960:                    boolean isDot = ch == DOT;
961:                    if (!isDigit && !isDot) {
962:                        return false;
963:                    }
964:                    if (isDigit) {
965:                        addr[currentOctet] = 10 * addr[currentOctet]
966:                                + (ch - ONE);
967:                        if (addr[currentOctet] > 255) {
968:                            return false;
969:                        }
970:                    } else if (name.charAt(i - 1) == DOT) {
971:                        return false;
972:                    } else {
973:                        currentOctet++;
974:                    }
975:                }
976:                return currentOctet == 3;
977:            }
978:
979:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.