001: /*
002: * $Header: /cvsroot/mvnforum/mvnforum/src/com/mvnforum/auth/OnlineUserManager.java,v 1.77 2008/01/29 08:07:21 minhnn Exp $
003: * $Author: minhnn $
004: * $Revision: 1.77 $
005: * $Date: 2008/01/29 08:07:21 $
006: *
007: * ====================================================================
008: *
009: * Copyright (C) 2002-2007 by MyVietnam.net
010: *
011: * All copyright notices regarding mvnForum MUST remain
012: * intact in the scripts and in the outputted HTML.
013: * The "powered by" text/logo with a link back to
014: * http://www.mvnForum.com and http://www.MyVietnam.net in
015: * the footer of the pages MUST remain visible when the pages
016: * are viewed on the internet or intranet.
017: *
018: * This program is free software; you can redistribute it and/or modify
019: * it under the terms of the GNU General Public License as published by
020: * the Free Software Foundation; either version 2 of the License, or
021: * any later version.
022: *
023: * This program is distributed in the hope that it will be useful,
024: * but WITHOUT ANY WARRANTY; without even the implied warranty of
025: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
026: * GNU General Public License for more details.
027: *
028: * You should have received a copy of the GNU General Public License
029: * along with this program; if not, write to the Free Software
030: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
031: *
032: * Support can be obtained from support forums at:
033: * http://www.mvnForum.com/mvnforum/index
034: *
035: * Correspondence and Marketing Questions can be sent to:
036: * info at MyVietnam net
037: *
038: * @author: Minh Nguyen
039: * @author: Mai Nguyen
040: */
041: package com.mvnforum.auth;
042:
043: import java.sql.Timestamp;
044: import java.util.*;
045:
046: import javax.servlet.http.*;
047:
048: import org.apache.commons.logging.Log;
049: import org.apache.commons.logging.LogFactory;
050:
051: import com.mvnforum.*;
052: import com.mvnforum.db.DAOFactory;
053: import com.mvnforum.event.MvnForumEvent;
054: import com.mvnforum.event.MvnForumEventManager;
055:
056: import net.myvietnam.mvncore.exception.*;
057: import net.myvietnam.mvncore.security.Encoder;
058: import net.myvietnam.mvncore.security.FloodControl;
059: import net.myvietnam.mvncore.security.SecurityUtil;
060: import net.myvietnam.mvncore.util.*;
061: import net.myvietnam.mvncore.web.GenericRequest;
062: import net.myvietnam.mvncore.web.GenericResponse;
063: import net.myvietnam.mvncore.web.impl.GenericRequestServletImpl;
064: import net.myvietnam.mvncore.web.impl.GenericResponseServletImpl;
065:
066: public class OnlineUserManager {
067:
068: private static Log log = LogFactory.getLog(OnlineUserManager.class);
069:
070: private static final int REMOVE_INTERVAL = 2000; //update every 2 second
071:
072: private static final String MVNFORUM_SESSION_USERNAME = "mvnforum.membername";
073: private static final String MVNFORUM_SESSION_PASSWORD = "mvnforum.encodedpassword";
074:
075: private static final String MVNFORUM_COOKIE_USERNAME = "mvnforum.membername";
076: private static final String MVNFORUM_COOKIE_PASSWORD = "mvnforum.encodedpassword";
077:
078: private static final String MVNFORUM_COOKIE_PATH = "/";
079:
080: public static final String PASSWORD_OF_METHOD_REALM = "Realm"; //must not be changed in all cases
081: public static final String PASSWORD_OF_METHOD_CUSTOMIZATION = "Remote";//must not be changed in all cases
082:
083: public static final String LDAP_LOGIN_USERNAME = "com.mvnforum.ldap.UserName";
084:
085: //static variable
086: private static OnlineUserManager instance = new OnlineUserManager();
087:
088: /**
089: * Returns a collection view of the values contained in this map. The
090: * collection is backed by the map, so changes to the map are reflected in
091: * the collection, and vice-versa. If the map is modified while an
092: * iteration over the collection is in progress (except through the
093: * iterator's own <tt>remove</tt> operation), the results of the
094: * iteration are undefined.
095: */
096: //instance variable
097: private Map userMap = new TreeMap();
098: private long timeOfLastRemoveAction = 0;
099: private transient Collection onlineUserListeners;
100:
101: private Authenticator authenticator = null;
102:
103: private OnlineUserManager() {
104: onlineUserListeners = new ArrayList();
105: }
106:
107: public static OnlineUserManager getInstance() {
108: return instance;
109: }
110:
111: public Authenticator getAuthenticator() {
112: return authenticator;
113: }
114:
115: public void setAuthenticator(Authenticator authenticator) {
116: this .authenticator = authenticator;
117: }
118:
119: /**
120: * MemberUtil method to be called from Processor.
121: * It assumes that to input parameters are
122: * MemberName for username
123: * MemberMatkhau for password
124: */
125: public void processLogin(HttpServletRequest request,
126: HttpServletResponse response)
127: throws AuthenticationException, DatabaseException,
128: BadInputException, FloodException {
129:
130: SecurityUtil.checkHttpPostMethod(request);
131:
132: String memberName = ParamUtil.getParameter(request,
133: "MemberName", true);
134: StringUtil.checkGoodName(memberName);// check for better security
135: String memberPassword = "";
136: String memberPasswordMD5 = ParamUtil.getParameter(request,
137: "md5pw", false);
138: if (memberPasswordMD5.length() == 0
139: || (memberPasswordMD5.endsWith("==") == false)) {
140: // md5 is not valid, try to use unencoded password method
141: memberPassword = ParamUtil.getParameterPassword(request,
142: "MemberMatkhau", 3, 0);
143: AssertionUtil
144: .doAssert(memberPassword.length() != 0,
145: "Cannot allow memberPassword's length is 0. Serious Assertion Failed.");
146: }
147:
148: processLogin(request, response, memberName, memberPassword,
149: memberPasswordMD5);
150: }
151:
152: /**
153: * Login method, if memberPassword length == 0, then login with memberPasswordMD5
154: */
155: public void processLogin(HttpServletRequest request,
156: HttpServletResponse response, String memberName,
157: String memberPassword, String memberPasswordMD5)
158: throws AuthenticationException, DatabaseException,
159: BadInputException, FloodException {
160:
161: StringUtil.checkGoodName(memberName);// check for better security
162:
163: String currentIP = request.getRemoteAddr();
164: try {
165: // Control the login action, we dont want user to try too many login attempt
166: FloodControl.ensureNotReachMaximum(
167: MVNForumGlobal.FLOOD_ID_LOGIN_PER_IP, currentIP);
168:
169: OnlineUser user = null;
170: if (memberPassword.length() > 0) {
171: // that is we cannot find the md5 password
172: /*
173: if (MVNForumConfig.getEnableEncryptPasswordOnBrowser()) {
174: user = login(request, response, memberName, memberPassword, false);
175: } else {
176: user = login(request, response, memberName, memberPassword, true);
177: }*/
178: user = login(request, response, memberName,
179: memberPassword, false);
180: } else {
181: // have the md5, go ahead
182: user = login(request, response, memberName,
183: memberPasswordMD5, true);
184: }
185: ((OnlineUserImpl) user)
186: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_HTML_FORM);
187: } catch (AuthenticationException ex) {
188: // only increase login count if unsuccessful
189: FloodControl.increaseCount(
190: MVNForumGlobal.FLOOD_ID_LOGIN_PER_IP, currentIP);
191:
192: if (ex.getReason() == NotLoginException.WRONG_PASSWORD) {
193: request.setAttribute("MemberName", memberName);// so user dont have to retype USER NAME
194: }
195: throw ex;
196: } catch (FloodException fe) {
197: Locale locale = I18nUtil.getLocaleInRequest(request);
198: Integer maxWrongLogins = new Integer(
199: FloodControl
200: .getActionsPerHour(MVNForumGlobal.FLOOD_ID_LOGIN_PER_IP));
201: //throw new FloodException("You have reached the maximum number of wrong login actions for this page. Please try this page later. This is to prevent forum from being flooded.");
202: String localizedMessage = MVNForumResourceBundle
203: .getString(
204: locale,
205: "mvncore.exception.FloodException.login_too_many_times",
206: new Object[] { maxWrongLogins });
207: throw new FloodException(localizedMessage);
208: }
209: }
210:
211: /**
212: * NOTE: This method MUST be the only way to authenticate a user
213: * NOTE: the parameter response can be equals null
214: */
215: protected OnlineUser login(HttpServletRequest request,
216: HttpServletResponse response, String memberName,
217: String memberPassword, boolean passwordEncoded)
218: throws AuthenticationException, DatabaseException {
219:
220: try {
221: StringUtil.checkGoodName(memberName);
222: } catch (Exception ex) {
223: throw new AuthenticationException(ex.getMessage(),
224: NotLoginException.WRONG_NAME);
225: }
226:
227: GenericRequest genericRequest = new GenericRequestServletImpl(
228: request);
229: MvnForumEvent event = new MvnForumEvent(this , genericRequest);
230: MvnForumEventManager.getInstance().firePreLogin(event);
231:
232: String encodedPassword;
233: OnlineUser user;
234: if (passwordEncoded) {
235: encodedPassword = memberPassword;
236: user = ManagerFactory.getOnlineUserFactory()
237: .getAuthenticatedUser(request, response,
238: memberName, encodedPassword, true);
239: } else {
240: encodedPassword = ManagerFactory.getOnlineUserFactory()
241: .getEncodedPassword(memberName, memberPassword);
242: //user = ManagerFactory.getOnlineUserFactory().getAuthenticatedUser(request, response, memberName, memberPassword, false);
243: user = ManagerFactory.getOnlineUserFactory()
244: .getAuthenticatedUser(request, response,
245: memberName, encodedPassword, true);
246: }
247:
248: HttpSession session = request.getSession();
249: String sessionID = session.getId();
250: setOnlineUser(sessionID, user);
251:
252: // now save the login info in the session only if we support
253: // encoded passwords
254: if (encodedPassword != null) {
255: if ((user.getAuthenticationType() != OnlineUser.AUTHENTICATION_TYPE_REALM)
256: && (user.getAuthenticationType() != OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION)
257: && (encodedPassword
258: .equals(PASSWORD_OF_METHOD_REALM) == false)
259: && (encodedPassword
260: .equals(PASSWORD_OF_METHOD_CUSTOMIZATION) == false)) {
261:
262: session.setAttribute(MVNFORUM_SESSION_USERNAME,
263: memberName);
264: session.setAttribute(MVNFORUM_SESSION_PASSWORD,
265: encodedPassword);
266: }
267: }
268:
269: boolean fromLoginPage = ParamUtil.getParameterBoolean(request,
270: "FromLoginPage");
271: if (fromLoginPage && (response != null)) {
272: manageAutoLogin(memberName, encodedPassword, request,
273: response);
274: }
275:
276: // Now call the postLogin method, in the default implementation, the default folder
277: // is checked and created if not existed
278: ManagerFactory.getOnlineUserFactory().postLogin(request,
279: response, user);
280: MvnForumEventManager.getInstance().firePostLogin(event);
281:
282: return user;
283: }
284:
285: protected OnlineUser login(GenericRequest request,
286: GenericResponse response, String memberName,
287: String memberPassword, boolean passwordEncoded)
288: throws AuthenticationException, DatabaseException {
289:
290: try {
291: StringUtil.checkGoodName(memberName);
292: } catch (Exception ex) {
293: throw new AuthenticationException(ex.getMessage(),
294: NotLoginException.WRONG_NAME);
295: }
296:
297: MvnForumEvent event = new MvnForumEvent(this , request);
298: MvnForumEventManager.getInstance().firePreLogin(event);
299:
300: String encodedPassword;
301: OnlineUser user;
302: if (passwordEncoded) {
303: encodedPassword = memberPassword;
304: user = ManagerFactory.getOnlineUserFactory()
305: .getAuthenticatedUser(request, null, memberName,
306: encodedPassword, true);
307:
308: } else {
309: encodedPassword = ManagerFactory.getOnlineUserFactory()
310: .getEncodedPassword(memberName, memberPassword);
311: //user = ManagerFactory.getOnlineUserFactory().getAuthenticatedUser(request, response, memberName, memberPassword, false);
312: user = ManagerFactory.getOnlineUserFactory()
313: .getAuthenticatedUser(request, null, memberName,
314: encodedPassword, true);
315: }
316:
317: String sessionID = request.getSessionId();
318: setOnlineUser(sessionID, user);
319:
320: // now save the login info in the session only if we support
321: // encoded passwords
322: /*if (null != encodedPassword) {
323: session.setAttribute(MVNFORUM_SESSION_USERNAME, memberName);
324: session.setAttribute(MVNFORUM_SESSION_PASSWORD, encodedPassword);
325: }*/
326:
327: /*
328: boolean fromLoginPage = ParamUtil.getParameterBoolean(request, "FromLoginPage");
329: if ( fromLoginPage && (response != null) ) {
330: manageAutoLogin(memberName, encodedPassword, request, response);
331: }*/
332:
333: // Now call the postLogin method, in the default implementation, the default folder
334: // is checked and created if not existed
335: ManagerFactory.getOnlineUserFactory().postLogin(null, null,
336: user);
337: MvnForumEventManager.getInstance().firePostLogin(event);
338:
339: return user;
340: }
341:
342: protected void manageAutoLogin(String memberName,
343: String encodedPassword, HttpServletRequest request,
344: HttpServletResponse response) {
345:
346: if (MVNForumConfig.getEnableEncryptPasswordOnBrowser() == false) {
347: return;// for security, we dont remember clear password
348: }
349:
350: boolean autoLogin = ParamUtil.getParameterBoolean(request,
351: "AutoLogin");
352: if (autoLogin) {
353: int autoLoginExpire = (60 * 60 * 24) * 1; // 1 day
354: try {
355: autoLoginExpire = ParamUtil.getParameterInt(request,
356: "AutoLoginExpire");
357: } catch (Exception ex) {
358: // do nothing
359: }
360: Cookie nameCookie = new Cookie(MVNFORUM_COOKIE_USERNAME,
361: Encoder.encodeURL(memberName));
362: nameCookie.setMaxAge(autoLoginExpire);
363: nameCookie.setPath(MVNFORUM_COOKIE_PATH);
364:
365: Cookie passwordCookie = new Cookie(
366: MVNFORUM_COOKIE_PASSWORD, encodedPassword);
367: passwordCookie.setMaxAge(autoLoginExpire);
368: passwordCookie.setPath(MVNFORUM_COOKIE_PATH);
369:
370: response.addCookie(nameCookie);
371: response.addCookie(passwordCookie);
372: }
373: }
374:
375: public void logout(HttpServletRequest request,
376: HttpServletResponse response) throws DatabaseException,
377: AuthenticationException {
378:
379: GenericRequest genericRequest = new GenericRequestServletImpl(
380: request);
381: GenericResponse genericResponse = null;
382:
383: if (response != null) {
384: genericResponse = new GenericResponseServletImpl(response);
385: }
386:
387: logout(genericRequest, genericResponse);
388: }
389:
390: public void logout(GenericRequest request, GenericResponse response)
391: throws DatabaseException, AuthenticationException {
392:
393: MvnForumEvent event = new MvnForumEvent(this , request);
394: MvnForumEventManager.getInstance().firePreLogout(event);
395:
396: String sessionID = request.getSessionId();
397:
398: OnlineUser user = null;
399: if (authenticator == null) {
400: // temporary hack, if no authenticator has been set,
401: // then we use the old method
402: // @todo: more thought on this later
403: OnlineUser oldUser = getOnlineUser(request);
404: String cssPath = oldUser.getCssPath();
405: String logoPath = oldUser.getLogoPath();
406: user = ManagerFactory.getOnlineUserFactory()
407: .getAnonymousUser(request);
408: user.setCssPath(cssPath);
409: user.setLogoPath(logoPath);
410: }
411:
412: // remove current user, then set new user is a guest
413: setOnlineUser(sessionID, user);
414: ManagerFactory.getOnlineUserFactory().logout(request, response);
415:
416: // now always clear the session information
417: request.setSessionAttribute(MVNFORUM_SESSION_USERNAME, null);
418: request.setSessionAttribute(MVNFORUM_SESSION_PASSWORD, null);
419: request.setSessionAttribute(LDAP_LOGIN_USERNAME, null);
420:
421: MvnForumEventManager.getInstance().firePostLogout(event);
422: }
423:
424: public void deleteCookie(HttpServletResponse response) {
425:
426: Cookie nameCookie = new Cookie(MVNFORUM_COOKIE_USERNAME, "");
427: nameCookie.setPath(MVNFORUM_COOKIE_PATH);
428: nameCookie.setMaxAge(0);// delete this cookie
429:
430: Cookie passwordCookie = new Cookie(MVNFORUM_COOKIE_PASSWORD, "");
431: passwordCookie.setPath(MVNFORUM_COOKIE_PATH);
432: passwordCookie.setMaxAge(0);// delete this cookie
433:
434: response.addCookie(nameCookie);
435: response.addCookie(passwordCookie);
436: }
437:
438: public OnlineUser getOnlineUser(GenericRequest request)
439: throws AuthenticationException, DatabaseException {
440:
441: if (request.isServletRequest()) {
442: return getOnlineUser(request.getServletRequest());
443: }
444:
445: String sessionID = request.getSessionId();
446: OnlineUser user = getOnlineUser(sessionID);
447:
448: // When logged in as remote or customization, the remote user is logged out
449: // and mvnForum still have the old non-guest users, then we should logout this user
450: // in OnlineUser too.
451: if ((user != null) && (user.isGuest() == false)) {
452: if (user.getAuthenticationType() == OnlineUser.AUTHENTICATION_TYPE_REALM) {
453: String currentRemoteUser = request.getRemoteUser();
454: if (currentRemoteUser == null) {
455: logout(request, null /*response*/);
456: } else if (currentRemoteUser.equalsIgnoreCase(user
457: .getMemberName()) == false) {
458: logout(request, null /*response*/);
459: //throw new AssertionError("ASSERTION: Current remote user should equals the current member in OnlineUser: Remote User: " + currentRemoteUser + ". But forum user is " + user.getMemberName() +". Please report bug to mvnForum developers.");
460: }
461: } else if (user.getAuthenticationType() == OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION) {
462: String currentRemoteUser = StringUtil
463: .getEmptyStringIfNull(authenticator
464: .getRemoteUser(request));
465: if (currentRemoteUser.equals("")) {
466: logout(request, null /*response*/);
467: } else if (currentRemoteUser.equalsIgnoreCase(user
468: .getMemberName()) == false) {
469: logout(request, null /*response*/);
470: //throw new AssertionError("ASSERTION: Current remote user should equals the current member in OnlineUser: Remote User: " + currentRemoteUser + ". But forum user is " + user.getMemberName() +". Please report bug to mvnForum developers.");
471: }
472: }
473: }
474: // end of checking
475:
476: // re-get the online user to continue
477: user = getOnlineUser(sessionID);
478:
479: boolean enableLoginInfoInRealm = MVNForumConfig
480: .getEnableLoginInfoInRealm();
481: if (user == null) {
482: // when authenticator is null
483: user = ManagerFactory.getOnlineUserFactory()
484: .getAnonymousUser(request);
485: setOnlineUser(sessionID, user);
486: }
487:
488: if (user.isGuest() && enableLoginInfoInRealm
489: && (null != request.getRemoteUser())) {
490: String memberName = StringUtil.getEmptyStringIfNull(request
491: .getRemoteUser());
492: if (memberName.length() > 0) {
493: try {
494: DAOFactory.getMemberDAO()
495: .findByAlternateKey_MemberName(memberName);
496: user = login(request, null, memberName,
497: PASSWORD_OF_METHOD_REALM, true);
498: ((OnlineUserImpl) user)
499: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_REALM);
500: ((OnlineUserImpl) user).setPasswordExpired(false);//external authentication never have expired password
501: } catch (ObjectNotFoundException oe) {
502: // ignore
503: }
504: }
505: }
506:
507: // now we have the user, check if it is a Guest and we can login in CUSTOM
508: boolean enableLoginInfoInCustomization = MVNForumConfig
509: .getEnableLoginInfoInCustomization();
510: if (authenticator == null) {
511: authenticator = ManagerFactory.getAuthenticator();
512: }
513: if (authenticator != null) {
514: if (user.isGuest() && enableLoginInfoInCustomization
515: && (null != authenticator.getRemoteUser(request))) {
516: String memberName = StringUtil
517: .getEmptyStringIfNull(authenticator
518: .getRemoteUser(request));
519: if (memberName.length() > 0) {
520: try {
521: DAOFactory.getMemberDAO()
522: .findByAlternateKey_MemberName(
523: memberName);
524: user = login(request, null, memberName,
525: PASSWORD_OF_METHOD_CUSTOMIZATION, true);
526: ((OnlineUserImpl) user)
527: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION);
528: ((OnlineUserImpl) user)
529: .setPasswordExpired(false);//external authentication never have expired password
530: } catch (ObjectNotFoundException oe) {
531: // ignore, the implementation of Authenticator should create the member in database first
532: }
533: }
534: }
535: }
536:
537: user.getOnlineUserAction().updateLastRequestTime();
538: return user;
539: }
540:
541: public OnlineUser getOnlineUser(HttpServletRequest request)
542: throws AuthenticationException, DatabaseException {
543:
544: long currentTime = System.currentTimeMillis();
545: if (currentTime - timeOfLastRemoveAction > REMOVE_INTERVAL) {//update every minute
546: removeTimeoutUsers();
547: // update MostOnline here
548: int currentOnlineUserCount = userMap.size();
549: fireDataChanged(new OnlineUserEvent(this ,
550: currentOnlineUserCount));
551: }
552:
553: HttpSession session = request.getSession();
554: String sessionID = session.getId();
555: OnlineUser user = getOnlineUser(sessionID);
556:
557: // When logged in as remote or customization, the remote user is logged out
558: // and mvnForum still have the old non-guest users, then we should logout this user
559: // in OnlineUser too.
560: if ((user != null) && (user.isGuest() == false)) {
561: if (user.getAuthenticationType() == OnlineUser.AUTHENTICATION_TYPE_REALM) {
562: String currentRemoteUser = request.getRemoteUser();
563: if (currentRemoteUser == null) {
564: logout(request, null /*response*/);
565: } else if (currentRemoteUser.equalsIgnoreCase(user
566: .getMemberName()) == false) {
567: logout(request, null /*response*/);
568: //throw new AssertionError("ASSERTION: Current remote user should equals the current member in OnlineUser. Please report bug to mvnForum developers.");
569: }
570: } else if (user.getAuthenticationType() == OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION) {
571: String currentRemoteUser = StringUtil
572: .getEmptyStringIfNull(authenticator
573: .getRemoteUser(request));
574: if (currentRemoteUser.equals("")) {
575: logout(request, null /*response*/);
576: } else if (currentRemoteUser.equalsIgnoreCase(user
577: .getMemberName()) == false) {
578: logout(request, null /*response*/);
579: //throw new AssertionError("ASSERTION: Current remote user should equals the current member in OnlineUser. Please report bug to mvnForum developers.");
580: }
581: }
582: }
583: // end of checking
584:
585: // re-get the online user to continue
586: user = getOnlineUser(sessionID);
587: if (user == null) {
588:
589: boolean enableLoginInfoInCookie = MVNForumConfig
590: .getEnableLoginInfoInCookie();
591: boolean enableLoginInfoInSession = MVNForumConfig
592: .getEnableLoginInfoInSession();
593: boolean enableLoginInfoInRealm = MVNForumConfig
594: .getEnableLoginInfoInRealm();
595: boolean enableLoginInfoInCustomization = MVNForumConfig
596: .getEnableLoginInfoInCustomization();
597:
598: if ((user == null) && enableLoginInfoInSession) {
599: String memberName = ParamUtil.getAttribute(session,
600: MVNFORUM_SESSION_USERNAME);
601: String encodedPassword = ParamUtil.getAttribute(
602: session, MVNFORUM_SESSION_PASSWORD);
603: if ((memberName.length() > 0)
604: && (encodedPassword.length() > 0)) {
605: try {
606: user = login(request, null, memberName,
607: encodedPassword, true);
608: ((OnlineUserImpl) user)
609: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_SESSION);
610: } catch (AuthenticationException e) {
611: // do nothing, some time the login info in the session
612: // is not correct, we dont consider this case as error
613: }
614: }
615: }
616: if ((user == null) && enableLoginInfoInCookie) {
617: String memberName = "";
618: String encodedPassword = "";
619: Cookie[] cookies = request.getCookies();
620: if (cookies != null) {
621: for (int i = 0; i < cookies.length; i++) {
622: Cookie cookie = cookies[i];
623: String cookieName = cookie.getName();
624: if (cookieName.equals(MVNFORUM_COOKIE_USERNAME)) {
625: memberName = Encoder.decodeURL(cookie
626: .getValue());
627: } else if (cookieName
628: .equals(MVNFORUM_COOKIE_PASSWORD)) {
629: encodedPassword = cookie.getValue();
630: }
631: }
632: }
633: if ((memberName.length() > 0)
634: && (encodedPassword.length() > 0)
635: && (encodedPassword
636: .equalsIgnoreCase(PASSWORD_OF_METHOD_REALM) == false)
637: && (encodedPassword
638: .equalsIgnoreCase(PASSWORD_OF_METHOD_CUSTOMIZATION) == false)) {
639: try {
640: user = login(request, null, memberName,
641: encodedPassword, true);
642: ((OnlineUserImpl) user)
643: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_COOKIE);
644: } catch (AuthenticationException e) {
645: // do nothing, some time the login info in the cookie
646: // is not correct, we dont consider this case as error
647: }
648: }
649: }
650: if ((user == null) && enableLoginInfoInRealm
651: && (null != request.getRemoteUser())) {
652: String memberName = StringUtil
653: .getEmptyStringIfNull(request.getRemoteUser());
654: if (memberName.length() > 0) {
655: try {
656: DAOFactory.getMemberDAO()
657: .findByAlternateKey_MemberName(
658: memberName);
659: user = login(request, null, memberName,
660: PASSWORD_OF_METHOD_REALM, true);
661: ((OnlineUserImpl) user)
662: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_REALM);
663: ((OnlineUserImpl) user)
664: .setPasswordExpired(false);//external authentication never have expired password
665: } catch (ObjectNotFoundException oe) {
666: // ignore
667: }
668: }
669: }
670: if ((user == null) && enableLoginInfoInCustomization) {
671: if (authenticator == null) {
672: authenticator = ManagerFactory.getAuthenticator();
673: }
674: if (authenticator != null) {
675: String memberName = StringUtil
676: .getEmptyStringIfNull(authenticator
677: .getRemoteUser(request));
678: if (memberName.length() > 0) {
679: try {
680: DAOFactory.getMemberDAO()
681: .findByAlternateKey_MemberName(
682: memberName);
683: user = login(request, null, memberName,
684: PASSWORD_OF_METHOD_CUSTOMIZATION,
685: true);
686: ((OnlineUserImpl) user)
687: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION);
688: ((OnlineUserImpl) user)
689: .setPasswordExpired(false);//external authentication never have expired password
690: } catch (ObjectNotFoundException oe) {
691: // ignore
692: }
693: }
694: }
695: }
696: if (user == null) {
697: user = ManagerFactory.getOnlineUserFactory()
698: .getAnonymousUser(request);
699: setOnlineUser(sessionID, user);
700: }
701: } else { //user != null
702: // now we have the user, check if it is a Guest and we can login in REALM
703: boolean enableLoginInfoInRealm = MVNForumConfig
704: .getEnableLoginInfoInRealm();
705: if (user.isGuest() && enableLoginInfoInRealm
706: && (null != request.getRemoteUser())) {
707: String memberName = StringUtil
708: .getEmptyStringIfNull(request.getRemoteUser());
709: if (memberName.length() > 0) {
710: try {
711: DAOFactory.getMemberDAO()
712: .findByAlternateKey_MemberName(
713: memberName);
714: user = login(request, null, memberName,
715: PASSWORD_OF_METHOD_REALM, true);
716: ((OnlineUserImpl) user)
717: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_REALM);
718: ((OnlineUserImpl) user)
719: .setPasswordExpired(false);//external authentication never have expired password
720: } catch (ObjectNotFoundException oe) {
721: // ignore
722: }
723: }
724: }
725:
726: // now we have the user, check if it is a Guest and we can login in CUSTOM
727: boolean enableLoginInfoInCustomization = MVNForumConfig
728: .getEnableLoginInfoInCustomization();
729: if (authenticator == null) {
730: authenticator = ManagerFactory.getAuthenticator();
731: }
732: if (authenticator != null) {
733: if (user.isGuest()
734: && enableLoginInfoInCustomization
735: && (null != authenticator
736: .getRemoteUser(request))) {
737: String memberName = StringUtil
738: .getEmptyStringIfNull(authenticator
739: .getRemoteUser(request));
740: if (memberName.length() > 0) {
741: try {
742: DAOFactory.getMemberDAO()
743: .findByAlternateKey_MemberName(
744: memberName);
745: user = login(request, null, memberName,
746: PASSWORD_OF_METHOD_CUSTOMIZATION,
747: true);
748: ((OnlineUserImpl) user)
749: .setAuthenticationType(OnlineUser.AUTHENTICATION_TYPE_CUSTOMIZATION);
750: ((OnlineUserImpl) user)
751: .setPasswordExpired(false);//external authentication never have expired password
752: } catch (ObjectNotFoundException oe) {
753: // ignore, the implementation of Authenticator should create the member in database first
754: }
755: }
756: }
757: }
758: }
759: user.getOnlineUserAction().updateLastRequestTime();
760: return user;
761: }
762:
763: public synchronized Collection getOnlineUserActions(int sortOption,
764: boolean duplicateUsers) {
765:
766: Collection collection = userMap.values();
767: // @todo: find a better sollution, I dont want to copy the Collection
768: // this ArrayList is used to copy the values
769: ArrayList retValue = new ArrayList(collection.size());
770:
771: // Get members first
772: if (duplicateUsers) {
773: for (Iterator memberIterator = collection.iterator(); memberIterator
774: .hasNext();) {
775: OnlineUser onlineUser = (OnlineUser) memberIterator
776: .next();
777: if (onlineUser.isMember()) {
778: OnlineUserAction onlineUserAction = onlineUser
779: .getOnlineUserAction();
780: retValue.add(onlineUserAction);
781: }
782: }
783: } else {
784: // now we combine the duplicated users
785: Hashtable distinctUserActions = new Hashtable();
786: OnlineUserAction lastUserAction = null;
787: for (Iterator memberIterator = collection.iterator(); memberIterator
788: .hasNext();) {
789: OnlineUser onlineUser = (OnlineUser) memberIterator
790: .next();
791: if (onlineUser.isMember()) {
792: OnlineUserAction onlineUserAction = onlineUser
793: .getOnlineUserAction();
794: String memberName = onlineUserAction
795: .getMemberName();
796: onlineUserAction.resetSessionCount();
797: lastUserAction = (OnlineUserAction) distinctUserActions
798: .get(memberName);
799: if (lastUserAction == null) {
800: distinctUserActions.put(memberName,
801: onlineUserAction);
802: } else if (onlineUserAction.getLastRequestTime()
803: .after(lastUserAction.getLastRequestTime())) {
804: distinctUserActions.put(memberName,
805: onlineUserAction);
806: onlineUserAction
807: .increaseSessionCount(lastUserAction
808: .getSessionCount());
809: } else {
810: lastUserAction.increaseSessionCount(1);
811: }
812: }
813: }
814: // now add the distinct member to the returned value
815: Collection distinctCollection = distinctUserActions
816: .values();
817: for (Iterator iterator = distinctCollection.iterator(); iterator
818: .hasNext();) {
819: OnlineUserAction onlineUserAction = (OnlineUserAction) iterator
820: .next();
821: retValue.add(onlineUserAction);
822: }
823: }
824:
825: // then get guest last
826: for (Iterator guestIterator = collection.iterator(); guestIterator
827: .hasNext();) {
828: OnlineUser onlineUser = (OnlineUser) guestIterator.next();
829: if (onlineUser.isGuest()) {
830: OnlineUserAction onlineUserAction = onlineUser
831: .getOnlineUserAction();
832: retValue.add(onlineUserAction);
833: }
834: }
835: return retValue;
836: }
837:
838: public void updateOnlineUserAction(HttpServletRequest request,
839: Action action) throws DatabaseException,
840: AuthenticationException {
841:
842: GenericRequest genericRequest = new GenericRequestServletImpl(
843: request, null);
844: updateOnlineUserAction(genericRequest, action);
845: }
846:
847: public void updateOnlineUserAction(GenericRequest request,
848: Action action) throws DatabaseException,
849: AuthenticationException {
850:
851: if (action != null) {
852: OnlineUser onlineUser = getOnlineUser(request);
853: OnlineUserAction onlineUserAction = onlineUser
854: .getOnlineUserAction();
855: // the setAction has package-default access
856: // so this is the only way to set action to a user
857: onlineUserAction.setAction(action);
858: }
859: }
860:
861: public synchronized boolean isUserOnline(String username) {
862:
863: Collection collection = userMap.values();
864: Iterator iterator = collection.iterator();
865: while (iterator.hasNext()) {
866: OnlineUser onlineUser = (OnlineUser) iterator.next();
867: String currentUser = onlineUser.getMemberName();
868: if (username.equalsIgnoreCase(currentUser)) {
869: return true;
870: }
871: }
872: return false;
873: }
874:
875: /************************************************************************
876: * private methods
877: ************************************************************************/
878: private synchronized OnlineUser getOnlineUser(String sessionID) {
879:
880: return (OnlineUser) userMap.get(sessionID);
881: }
882:
883: private synchronized void setOnlineUser(String sessionID,
884: OnlineUser user) {
885:
886: OnlineUser onlineUser = getOnlineUser(sessionID);
887: if (null == user) {
888: userMap.remove(sessionID);
889: } else {
890: userMap.put(sessionID, user);
891: }
892:
893: if (onlineUser != null) {
894: final int DONT_CARE = -1;
895: fireUserLogout(new OnlineUserEvent(onlineUser, DONT_CARE));
896: }
897: }
898:
899: private synchronized void removeTimeoutUsers() {
900:
901: long currentTimeMillis = System.currentTimeMillis();
902: // try to resolve problem with synchronization on the class-variable : timeOfLastRemoveAction
903: if (currentTimeMillis - timeOfLastRemoveAction < REMOVE_INTERVAL) {
904: return;
905: }
906: // okie now, go ahead
907: timeOfLastRemoveAction = currentTimeMillis;
908:
909: Timestamp currentTime = DateUtil.getCurrentGMTTimestamp();
910:
911: Collection collection = userMap.values();
912: Iterator iterator = collection.iterator();
913: while (iterator.hasNext()) {
914: OnlineUser onlineUser = (OnlineUser) iterator.next();
915: OnlineUserAction onlineUserAction = onlineUser
916: .getOnlineUserAction();
917: long duration = currentTime.getTime()
918: - onlineUserAction.getLastRequestTime().getTime();
919: if (duration > MVNForumConfig.SESSION_DURATION) {
920: iterator.remove();
921: final int DONT_CARE = -1;
922: fireUserLogout(new OnlineUserEvent(onlineUser,
923: DONT_CARE));
924: }
925: }
926: }
927:
928: public Map getUserMap() {
929: return this .userMap;
930: }
931:
932: /************************************************************************
933: * Event method
934: ************************************************************************/
935: public synchronized void removeOnlineUserListener(
936: OnlineUserListener listener) {
937: onlineUserListeners.remove(listener);
938: }
939:
940: public synchronized void addOnlineUserListener(
941: OnlineUserListener listener) {
942: onlineUserListeners.add(listener);
943: }
944:
945: protected void fireDataChanged(OnlineUserEvent e) {
946: for (Iterator iterator = onlineUserListeners.iterator(); iterator
947: .hasNext();) {
948: ((OnlineUserListener) iterator.next()).onChange(e);
949: }
950: }
951:
952: protected void fireUserLogout(OnlineUserEvent e) {
953: for (Iterator iterator = onlineUserListeners.iterator(); iterator
954: .hasNext();) {
955: ((OnlineUserListener) iterator.next()).onLogout(e);
956: }
957: }
958:
959: }
|