001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005: package com.sun.portal.desktop.context;
006:
007: import com.iplanet.sso.SSOException;
008: import com.iplanet.sso.SSOToken;
009: import com.iplanet.sso.SSOTokenEvent;
010: import com.iplanet.sso.SSOTokenListener;
011: import com.sun.identity.session.util.SessionUtils;
012:
013: import javax.servlet.http.Cookie;
014: import javax.servlet.http.HttpServletRequest;
015: import java.security.Principal;
016: import java.util.HashMap;
017: import java.util.HashSet;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Set;
021:
022: class DSAMESessionContext implements SessionContext, SSOTokenListener {
023: static int counter = 0;
024: static Set sids = new HashSet();
025:
026: // Use getSSOToken() method to access this
027: private SSOToken _token = null;
028:
029: //
030: // this maps sid's to a set of objects that implement SessionListener
031: //
032: static protected Map sessionListeners = new HashMap();
033:
034: //
035: // this maps uid's to an object that encapsulates a reference count
036: // and a set of objects that implement UserListener
037: //
038: static protected Map userListeners = new HashMap();
039:
040: //
041: // this map is used because we are unable to determine the uid of
042: // a destroyed session. we keep our own internal map of sid to
043: // uid.
044: //
045: static protected Map sessionIDs = new HashMap();
046:
047: //
048: // this keeps track of whether we've added an sso token listener
049: // for this object
050: //
051: protected boolean ssoTokenListenerAdded = false;
052:
053: //
054: // uid, sid never changes for the life
055: // of this object, so get once and then return
056: // reference
057: //
058: String sid = null;
059: String uid = null;
060:
061: DesktopAppContext desktopAppContext = null;
062:
063: private String portalId = null;
064:
065: public DSAMESessionContext() {
066: }
067:
068: private static synchronized void incCounter() {
069: counter++;
070: }
071:
072: private static synchronized void addSID(String sid) {
073: sids.add(sid);
074: }
075:
076: private static synchronized void decCounter() {
077: counter--;
078: }
079:
080: private static synchronized void removeSID(String sid) {
081: sids.remove(sid);
082: }
083:
084: public void init(HttpServletRequest req, String portalId) {
085: if (portalId != null && portalId.length() != 0) {
086: this .portalId = portalId;
087: }
088: _token = getSSOToken(req);
089: desktopAppContext = DesktopAppContextThreadLocalizer.get();
090:
091: initSessionID();
092: initUserID();
093: }
094:
095: protected DesktopAppContext getDesktopAppContext() {
096: return desktopAppContext;
097: }
098:
099: public String getStringProperty(String name) {
100: try {
101: name = portalId == null ? name : (portalId + "." + name);
102: return getSSOToken().getProperty(name);
103: } catch (SSOException ssoe) {
104: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
105: }
106:
107: }
108:
109: public void setStringProperty(String name, String val) {
110: try {
111: name = portalId == null ? name : (portalId + "." + name);
112: getSSOToken().setProperty(name, val);
113: } catch (SSOException ssoe) {
114: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
115: }
116: }
117:
118: private synchronized SSOToken getSSOToken() {
119: if (_token == null) {
120: throw new ContextError(
121: "DSAMESessionContext.getSSOToken(): not initialized");
122: }
123:
124: return _token;
125: }
126:
127: private synchronized SSOToken getSSOToken(HttpServletRequest req) {
128: SSOToken token;
129:
130: try {
131: token = DSAMEConnection.getSSOTokenManager()
132: .createSSOToken(req);
133: } catch (SSOException se) {
134: // This means that SSOToken is invalid
135: throw new ContextError(se, ContextError.SESSION_TYPE);
136: }
137:
138: return token;
139: }
140:
141: public String getSessionID() {
142: if (sid == null) {
143: throw new ContextError("not initialized");
144: }
145:
146: return sid;
147: }
148:
149: protected void initSessionID() {
150: this .sid = getSSOToken().getTokenID().toString();
151: }
152:
153: public String getUserID() {
154: if (uid == null) {
155: throw new ContextError("not initialized");
156: }
157:
158: return uid;
159: }
160:
161: protected void initUserID() {
162: Principal p;
163:
164: try {
165: p = getSSOToken().getPrincipal();
166: } catch (SSOException ssoe) {
167: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
168: }
169:
170: this .uid = p.toString();
171: }
172:
173: /*
174: * Add an SSO token listener.
175: *
176: * It is assumed that this method is called from a synchronized block.
177: */
178: protected void addSSOTokenListener() {
179: //
180: // only register as an SSO token listener
181: // once per session
182: //
183: try {
184: if (!ssoTokenListenerAdded) {
185: synchronized (this ) {
186: if (!ssoTokenListenerAdded) {
187: getSSOToken().addSSOTokenListener(this );
188: incCounter();
189: addSID(getSessionID());
190: ssoTokenListenerAdded = true;
191: }
192: }
193: }
194: } catch (SSOException ssoe) {
195: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
196: }
197: }
198:
199: public void addSessionListener(SessionListener sl) {
200: String sid = getSessionID();
201: //
202: // see if there is already a set of listeners registered for this
203: // sid
204: //
205:
206: synchronized (sessionListeners) {
207: Set listeners = (Set) sessionListeners.get(sid);
208: if (listeners == null) {
209: //
210: // no listener registered under this sid, create a set and add this
211: // listener to the set
212: //
213:
214: listeners = new HashSet();
215: sessionListeners.put(sid, listeners);
216: }
217: listeners.add(sl);
218: }
219: addSSOTokenListener();
220:
221: }
222:
223: /*
224: public void addUserReference() {
225: String uid = getUserID();
226: String sid = getSessionID();
227:
228: synchronized (userListeners) {
229: UserListenersReference ref = (UserListenersReference)userListeners.get(uid);
230: if (ref == null) {
231: //
232: // this means that someone tried to add a reference to a user
233: // when they were not listening for notifications on that user
234: //
235: throw new ContextError("DSAMESessionContext.addUserReference(): no listener for uid=" + uid);
236: }
237:
238: if (!ref.containsSID(sid)) {
239: ref.references++;
240: sessionIDs.put(sid, uid);
241: }
242: }
243: }
244: */
245:
246: public void addUserListener(UserListener ul) {
247: String uid = getUserID();
248: String sid = getSessionID();
249:
250: synchronized (userListeners) {
251: UserListenersReference ref = (UserListenersReference) userListeners
252: .get(uid);
253:
254: if (ref == null) {
255: //getDesktopAppContext().debugError("DSAMESessionContext.addUserListener(): creating new user listener reference");
256: ref = new UserListenersReference();
257: userListeners.put(uid, ref);
258: }
259:
260: //getDesktopAppContext().debugError("DSAMESessionContext.addUserListener(): ref=" + ref);
261:
262: //
263: // only increment the reference count if we have not
264: // processed this session id already. reference counts
265: // count the number of unique session ids that have
266: // registered with this method.
267: //
268:
269: if (ref.getListeners(sid) == null) {
270: sessionIDs.put(sid, uid);
271: //getDesktopAppContext().debugError("DSAMESessionContext.addUserListener(): no reference for sid");
272: } else {
273: //getDesktopAppContext().debugError("DSAMESessionContext.addUserListener(): reference already exists for sid");
274: }
275:
276: //
277: // do not let any object reference as a user
278: // listener twice. this is really protecting
279: // clients of this class from doing something
280: // that they don't want to do.
281: //
282: // this is handled by the reference impl, where the
283: // listeners per sid is a set.
284: //
285: ref.addListener(sid, ul);
286: }
287: addSSOTokenListener();
288: }
289:
290: public void ssoTokenChanged(SSOTokenEvent evt) {
291: decCounter();
292:
293: SSOToken token = evt.getToken();
294: String sid = token.getTokenID().toString();
295:
296: removeSID(sid);
297:
298: int type = -1;
299: try {
300: type = evt.getType();
301: } catch (SSOException ssoe) {
302: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
303: }
304:
305: ssoTokenChangedUsers(sid, type);
306: ssoTokenChangedSessions(sid, type);
307: }
308:
309: public String encodeURL(String url) {
310: String val;
311:
312: try {
313: SSOToken t = getSSOToken();
314: val = SessionUtils.encodeURL(t, url, SessionUtils.QUERY,
315: false);
316: } catch (SSOException se) {
317: throw new ContextError("failed to encode URL: " + url, se,
318: ContextError.SESSION_TYPE);
319: }
320:
321: //getDesktopAppContext().debugError("DSAMESessionContext.encodeURL(): val=" + val);
322: return val;
323:
324: }
325:
326: protected void ssoTokenChangedSessions(String sid, int type) {
327: Set listeners;
328: boolean destroySession;
329: DSAMESessionEvent se;
330:
331: synchronized (sessionListeners) {
332: listeners = (Set) sessionListeners.get(sid);
333:
334: if (listeners == null) {
335: return;
336: }
337:
338: switch (type) {
339: case SSOTokenEvent.SSO_TOKEN_DESTROY:
340: case SSOTokenEvent.SSO_TOKEN_IDLE_TIMEOUT:
341: case SSOTokenEvent.SSO_TOKEN_MAX_TIMEOUT:
342: se = new DSAMESessionEvent();
343: se.setSessionID(sid);
344: sessionListeners.remove(sid);
345: destroySession = true;
346: break;
347:
348: default:
349: throw new ContextError(
350: "DSAMESessionContext.ssoTokenChangedSessions(): unknown event type="
351: + type);
352: }
353: }
354:
355: // notify session listener of the event
356: if (destroySession) {
357: destroySessions(listeners, se);
358: }
359: }
360:
361: protected void ssoTokenChangedUsers(String sid, int type) {
362: Set listeners;
363: boolean logoutUser = false;
364:
365: DSAMEUserEvent ue = null;
366:
367: synchronized (userListeners) {
368: String uid = (String) sessionIDs.get(sid);
369: //getDesktopAppContext().debugError("DSAMESessionContext.ssoTokenChangedUsers(): uid=" + uid);
370: if (uid == null) {
371: throw new ContextError(
372: "DSAMESessionContext.ssoTokenChangedUsers(): could not lookup uid for sid="
373: + sid);
374: }
375:
376: UserListenersReference ref = (UserListenersReference) userListeners
377: .get(uid);
378: //getDesktopAppContext().debugError("DSAMESessionContext.ssoTokenChangedUsers(): ref=" + ref);
379:
380: if (ref == null) {
381: return;
382: }
383:
384: switch (type) {
385: case SSOTokenEvent.SSO_TOKEN_DESTROY:
386: case SSOTokenEvent.SSO_TOKEN_IDLE_TIMEOUT:
387: case SSOTokenEvent.SSO_TOKEN_MAX_TIMEOUT:
388: //
389: // session is gone ... even if the user is still around, this
390: // session for them is gone, so remove it for the mapping table
391: //
392: sessionIDs.remove(sid);
393: listeners = ref.removeSID(sid);
394: if (ref.size() > 0) {
395: //getDesktopAppContext().debugError("DSAMESessionContext.ssoTokenChangedUsers(): ref was >0 for uid=" + uid + ", userListeners=" + userListeners);
396: //
397: // there is still a user with this name logged in someone under
398: // a different session ...
399: //
400: break;
401: }
402:
403: //getDesktopAppContext().debugError("DSAMESessionContext.ssoTokenChangedUsers(): ref was 0 for uid=" + uid + ", userListeners=" + userListeners);
404:
405: ue = new DSAMEUserEvent();
406: ue.setUserID(uid);
407: userListeners.remove(uid);
408: logoutUser = true;
409: break;
410:
411: default:
412: throw new ContextError(
413: "DSAMESessionContext.ssoTokenChangedUsers(): unknown event type="
414: + type);
415: }
416: }
417:
418: // notify each user listener of the event
419: if (logoutUser) {
420: logoutUsers(listeners, ue);
421: }
422: }
423:
424: protected void destroySessions(Set listeners, SessionEvent se) {
425: //getDesktopAppContext().debugError("DSAMESessionContext.destroySessions(): listeners=" + listeners);
426: for (Iterator i = listeners.iterator(); i.hasNext();) {
427: SessionListener sl = (SessionListener) i.next();
428: //getDesktopAppContext().debugError("DSAMESessionContext.destroySessions(): calling for sl=" + sl);
429: sl.sessionDestroyed(se);
430: }
431: }
432:
433: protected void logoutUsers(Set listenersForSID, UserEvent ue) {
434: //getDesktopAppContext().debugError("DSAMESessionContext.userLogut(): listenersForSID=" + listenersForSID);
435: for (Iterator j = listenersForSID.iterator(); j.hasNext();) {
436: UserListener ul = (UserListener) j.next();
437: //getDesktopAppContext().debugError("DSAMESessionContext.userLogut(): calling for ul=" + ul);
438: ul.userLogout(ue);
439: }
440: }
441:
442: static private class UserListenersReference {
443: //
444: // maps session IDs to a list of user listeners for that Id
445: //
446: private Map listeners = new HashMap();
447:
448: public UserListenersReference() {
449: }
450:
451: public int getReferences() {
452: return listeners.size();
453: }
454:
455: public Set removeSID(String sid) {
456: return (Set) listeners.remove(sid);
457: }
458:
459: public int size() {
460: return listeners.size();
461: }
462:
463: public Iterator getSIDs() {
464: return listeners.keySet().iterator();
465: }
466:
467: public Set getListeners(String sid) {
468: return (Set) listeners.get(sid);
469: }
470:
471: public void addListener(String sid, UserListener ul) {
472: Set listenersForSID = (Set) listeners.get(sid);
473: if (listenersForSID == null) {
474: listenersForSID = new HashSet();
475: listeners.put(sid, listenersForSID);
476: }
477:
478: listenersForSID.add(ul);
479: }
480:
481: public String toString() {
482: return listeners.toString();
483: }
484: }
485:
486: public String getAuthenticationType() {
487: SSOToken token = getSSOToken();
488:
489: try {
490: return token.getAuthType();
491: } catch (SSOException ssoe) {
492: throw new ContextError(ssoe, ContextError.SESSION_TYPE);
493: }
494: }
495:
496: /* Properties that are stored as Cookie on client browser.
497: * AuthlessAnonymous user state is managed via such cookie.
498: * Authenticated users use AM/DSAME session to manage user state, returns null in such case.
499: */
500: public Cookie getClientProperties() {
501: return null;
502: }
503: }
|