SessionHolder.java
package sk.iway.iwcm.stat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import sk.iway.iwcm.Adminlog;
import sk.iway.iwcm.Cache;
import sk.iway.iwcm.Constants;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.InitServlet;
import sk.iway.iwcm.Logger;
import sk.iway.iwcm.RequestBean;
import sk.iway.iwcm.SetCharacterEncodingFilter;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.common.CloudToolsForCore;
import sk.iway.iwcm.system.cluster.ClusterDB;
import sk.iway.iwcm.users.UsersDB;
/**
* Toto drzi globalne info o session pouzivatelov, pretoze SessionListener pri
* ukonceni session nema pristup k datam v session a teda nie je mozne zistit
* aky bol posledny docId a aky to bol server
*
*@Title magma-web
*@Company Interway s.r.o. (www.interway.sk)
*@Copyright Interway s.r.o. (c) 2001-2002
*@author $Author: jeeff $
*@version $Revision: 1.2 $
*@created Piatok, 2002, máj 31
*@modified $Date: 2003/02/23 16:56:22 $
*/
public class SessionHolder
{
/**
* Description of the Field
*/
public static final String SESSION_HOLDER = "iwcm_session_holder";
private Map<String, SessionDetails> data = Collections.synchronizedMap(new Hashtable<String, SessionDetails>());
private static final String INVALIDATE_SESSION_ADDR = "INVALIDATE";
/**
* Takyto konstruktor sa normalne nesmie pouzivat!
*
*/
public SessionHolder()
{
}
public static SessionHolder getInstance()
{
return(getInstance(Constants.getServletContext()));
}
/**
* Gets the instance attribute of the SessionHolder object
*
*@param servletContext Description of the Parameter
*@return The instance value
*/
public static SessionHolder getInstance(javax.servlet.ServletContext servletContext)
{
if (servletContext!=null && servletContext.getAttribute(SESSION_HOLDER) != null)
{
return ((SessionHolder) servletContext.getAttribute(SESSION_HOLDER));
}
return (new SessionHolder(servletContext));
}
/**
* Constructor for the SessionHolder object
*
*@param servletContext Description of the Parameter
*/
private SessionHolder(javax.servlet.ServletContext servletContext)
{
//Logger.println(this,"SessionHolder: constructor");
data = Collections.synchronizedMap(new Hashtable<String, SessionDetails>());
servletContext.setAttribute(SESSION_HOLDER, this);
}
/**
* Vrati aktualny zoznam ludi v session
* @return
*/
public List<SessionDetails> getList()
{
cleanup();
List<SessionDetails> list = new ArrayList<>();
Collection<Entry<String, SessionDetails>> entries = null;
synchronized (data)
{
entries = new Vector<>(data.entrySet());
}
for (Entry<String, SessionDetails> me : entries)
{
if (InitServlet.isTypeCloud() || Constants.getBoolean("enableStaticFilesExternalDir")==true)
{
if (me.getValue().getDomainId() != CloudToolsForCore.getDomainId())
{
continue;
}
}
list.add(me.getValue());
}
return list;
}
/**
* Nastavi hodnoty pre session holder a skontroluje session stealing, ked nastane session stealing vrati false
* @param sessionId
* @param lastURL
* @param request
* @return
*/
public boolean set(String sessionId, String lastURL, HttpServletRequest request) {
// lebo iframe a cookie toho potom vygeneruje kopec
if (lastURL != null && (lastURL.indexOf("/admin/mem.jsp") != -1 || lastURL.indexOf("/admin/refresher.jsp") != -1
|| lastURL.indexOf("/admin/divpopup-blank.jsp") != -1 || lastURL.indexOf("/admin/FCKeditor") != -1
|| lastURL.indexOf("/admin/rest/refresher") != -1))
return true;
// aby bolo mozne grafy tlacit do PDF, normalne by nam nastal session stealing
// check
if (lastURL != null
&& (lastURL.startsWith("/admin/statchartnew.do") || lastURL.startsWith("/admin/statchart.do")))
return true;
// multiupload robi cachre machre so session, radsej vynechavam
if (lastURL != null && lastURL.startsWith("/admin/multiplefileupload.do"))
return true;
SessionDetails det = get(sessionId);
if (det == null) {
cleanup();
det = new SessionDetails();
det.setLogonTime(Tools.getNow());
det.setRemoteAddr(Tools.getRemoteIP(request));
} else {
Identity sessionUser = UsersDB.getCurrentUser(request);
if (Constants.getBoolean("sessionStealingCheck") == true
&& det.getRemoteAddr().equals(Tools.getRemoteIP(request)) == false) {
// session stealing vyvolame len ak je niekto prihlaseny
if (sessionUser != null || det.getLoggedUserId() > 0) {
String sessionUserData = "";
if (sessionUser != null)
sessionUserData = " suid=" + sessionUser.getUserId() + " " + sessionUser.getFullName();
String description = "SESSION STEALING, sessionId=" + sessionId + " userId=" + det.getLoggedUserId()
+ " " + det.getLoggedUserName() + " logonDate=" + Tools.formatDateTime(det.getLogonTime())
+ " session IP=" + det.getRemoteAddr() + " req IP=" + Tools.getRemoteIP(request) + " "
+ sessionUserData;
Logger.error(SessionHolder.class, description);
Adminlog.add(Adminlog.TYPE_XSS, description, -1, -1);
request.getSession().invalidate();
return false;
}
}
if (INVALIDATE_SESSION_ADDR.equals(det.getRemoteAddr())) {
request.getSession().invalidate();
return false;
}
}
det.setLastURL(lastURL);
det.setDomainId(CloudToolsForCore.getDomainId());
det.setDomainName(CloudToolsForCore.getDomainName());
Identity user = (Identity) request.getSession().getAttribute(Constants.USER_KEY);
if (user != null) {
if (det.getLoggedUserId() < 1 || det.getLoggedUserId() != user.getUserId()) {
det.setLoggedUserId(user.getUserId());
det.setAdmin(user.isAdmin());
det.setLoggedUserName(user.getFullName());
}
} else {
if (det.getLoggedUserId() > 0) {
det.setLoggedUserId(-1);
det.setAdmin(false);
det.setLoggedUserName(null);
}
}
// ziskaj IP a remoteHost
det.setLastActivity(Tools.getNow());
data.put(sessionId, det);
return true;
}
/**
* Nastavi atribut lastDocId na sessionDetails, vola sa zo StatDB statistiky stranok
* @param sessionId
* @param lastDocId
*/
public void setLastDocId(String sessionId, int lastDocId)
{
SessionDetails det = get(sessionId);
if (det != null)
{
det.setLastDocId(lastDocId);
data.put(sessionId, det);
}
}
/**
* Description of the Method
*
*@param sessionId Description of the Parameter
*@return Description of the Return Value
*/
public SessionDetails get(String sessionId)
{
return data.get(sessionId);
}
/**
* Description of the Method
*
*@param sessionId Description of the Parameter
*/
public void remove(String sessionId)
{
SessionDetails ses = get(sessionId);
if (ses != null)
{
ses = null;
}
data.remove(sessionId);
cleanup();
}
/**
* Vrati aktualny pocet sessions aktualneho clustru (kolko ludi si cita stranku)
* @return
*/
public static int getTotalSessionsPerNode()
{
SessionHolder sh = SessionHolder.getInstance();
return(sh.getList().size());
}
/**
* Vrati aktualny pocet sessions (kolko ludi si cita stranku)
*
* Ak system bezi v cluster mode vrati sucet poctu sessions jednotlivych clustrov, ktore sa ukladaju do _conf_ cez MonitoringManager (cron)
* Ak system nebezi v cluster mode, vratena hodnota je identicka s hodnotou ktoru vrati <code>getTotalSessionsPerNode()</code>
*
* @return
*/
public static int getTotalSessions()
{
if(ClusterDB.isServerRunningInClusterMode())
{
int totalSessions=Constants.getInt("statSessionsAllNodes");
if(totalSessions<=0)
totalSessions = getTotalSessionsPerNode();
return totalSessions;
}
else
return getTotalSessionsPerNode();
}
/**
* Vrati pocet prihlasenych pouzivatelov aktualneho clustru. Pod prihlasenym pouzivatelom sa rozumie
* pouzivatel s ID vacsim ako 0, pricom vsetky otvorene session sa pri pocitani
* agreguju ako jeden pouzivatel.
*
* @return {@link Integer}
*/
public static int getDistinctUsersCountPerNode()
{
//pouziva Cache - iteruje nad vsetkymi pouzivatelmi a uzamkyna pritom
//zamok (ak by nezamkynal - mozny ConcurrentModificationException) => mozny bottleNeck
//notNull && isInteger
if (Cache.getInstance().getObject("distinctUserCount") instanceof Integer)
return (Integer)Cache.getInstance().getObject("distinctUserCount");
SessionHolder sh = SessionHolder.getInstance();
Set<Integer> userIds = new HashSet<>();
//vyrobime si kopiu
List<SessionDetails> sessionList = null;
synchronized(getInstance().data)
{
sessionList = new ArrayList<>(sh.getList());
}
for (SessionDetails session : sessionList)
{
if (session.getLoggedUserId() > 0)
userIds.add( session.getLoggedUserId() );
}
final int SECONDS_TO_LAST_IN_CACHE = 10;
Cache.getInstance().setObjectSeconds("distinctUserCount",userIds.size(),SECONDS_TO_LAST_IN_CACHE);
return userIds.size();
}
/**
* Vrati pocet prihlasenych pouzivatelov. Pod prihlasenym pouzivatelom sa rozumie
* pouzivatel s ID vacsim ako 0, pricom vsetky otvorene session sa pri pocitani
* agreguju ako jeden pouzivatel.
*
* Ak system bezi v cluster mode vrati sucet pouzivatelov jednotlivych clustrov, ktore sa ukladaju do _conf_ cez MonitoringManager (cron)
* Ak system nebezi v cluster mode, vratena hodnota je identicka s hodnotou ktoru vrati <code>getDistrinctUsersCountPerNode()</code>
*
* @return {@link Integer}
*/
public static int getDistinctUsersCount()
{
if(ClusterDB.isServerRunningInClusterMode())
{
int totalUsers=Constants.getInt("statDistinctUsersAllNodes");
if(totalUsers<=0)
totalUsers = getDistinctUsersCountPerNode();
return totalUsers;
}
else
return getDistinctUsersCountPerNode();
}
/**
* Zrusi stare neaktivne sessions
*
*/
private void cleanup() {
try {
SessionDetails sd;
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -Constants.getInt("sessionRemoveTimeout"));
long removeTime = cal.getTimeInMillis();
synchronized (data) {
Set<String> keys = data.keySet();
List<String> myKeysList = new ArrayList<>();
for (String key : keys) {
myKeysList.add(key);
}
for (String key : myKeysList) {
sd = data.get(key);
if (sd == null || sd.getLastActivity() < removeTime) {
if (sd == null) {
Logger.debug(SessionHolder.class, "Removing session: " + key + " sd=null");
} else {
Logger.debug(SessionHolder.class,
"Removing session: " + key + " la=" + Tools.formatDateTime(sd.getLastActivity()));
}
data.remove(key);
}
}
}
} catch (Exception e) {
// sk.iway.iwcm.Logger.error(e);
}
}
/**
* Nastavi vsetkym ostatnym session atribut pre ich invalidovanie (napr. po zmene hesla)
*/
public void invalidateOtherUserSessions()
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
if (rb == null || rb.getUserId()<1) return;
invalidateOtherUserSessions(rb.getUserId());
}
/**
* Invalidate other sessions for user with userId, call this after password change
* @param userId - ID of user changed password
*/
public void invalidateOtherUserSessions(int userId)
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
if (rb == null || rb.getUserId()<1) return;
for (Map.Entry<String, SessionDetails> entry : data.entrySet())
{
String sessionId = entry.getKey();
if (Tools.isEmpty(sessionId)) continue;
SessionDetails sd = entry.getValue();
if (sd == null) continue;
if (sd.getLoggedUserId() == userId && sessionId.equals(rb.getSessionId())==false)
{
//destroy session
sd.setRemoteAddr(INVALIDATE_SESSION_ADDR);
Logger.debug(SessionHolder.class, "Invalidating session: " + sessionId +" uid="+sd.getLoggedUserId());
}
}
}
}