1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server.session;
20
21 import static java.lang.Math.round;
22
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.EventListener;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.CopyOnWriteArrayList;
33
34 import javax.servlet.SessionCookieConfig;
35 import javax.servlet.SessionTrackingMode;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpSession;
38 import javax.servlet.http.HttpSessionAttributeListener;
39 import javax.servlet.http.HttpSessionBindingEvent;
40 import javax.servlet.http.HttpSessionContext;
41 import javax.servlet.http.HttpSessionEvent;
42 import javax.servlet.http.HttpSessionListener;
43
44 import org.eclipse.jetty.http.HttpCookie;
45 import org.eclipse.jetty.server.Server;
46 import org.eclipse.jetty.server.SessionIdManager;
47 import org.eclipse.jetty.server.SessionManager;
48 import org.eclipse.jetty.server.handler.ContextHandler;
49 import org.eclipse.jetty.util.annotation.ManagedAttribute;
50 import org.eclipse.jetty.util.annotation.ManagedObject;
51 import org.eclipse.jetty.util.annotation.ManagedOperation;
52 import org.eclipse.jetty.util.component.AbstractLifeCycle;
53 import org.eclipse.jetty.util.log.Logger;
54 import org.eclipse.jetty.util.statistic.CounterStatistic;
55 import org.eclipse.jetty.util.statistic.SampleStatistic;
56
57
58
59
60
61
62
63
64
65
66
67 @SuppressWarnings("deprecation")
68 @ManagedObject("Abstract Session Manager")
69 public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
70 {
71 final static Logger __log = SessionHandler.LOG;
72
73 public Set<SessionTrackingMode> __defaultSessionTrackingModes =
74 Collections.unmodifiableSet(
75 new HashSet<SessionTrackingMode>(
76 Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL})));
77
78 public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
79
80
81 public final static int __distantFuture=60*60*24*7*52*20;
82
83 static final HttpSessionContext __nullSessionContext=new HttpSessionContext()
84 {
85 public HttpSession getSession(String sessionId)
86 {
87 return null;
88 }
89
90 @SuppressWarnings({ "rawtypes", "unchecked" })
91 public Enumeration getIds()
92 {
93 return Collections.enumeration(Collections.EMPTY_LIST);
94 }
95 };
96
97 private boolean _usingCookies=true;
98
99
100
101
102 protected int _dftMaxIdleSecs=-1;
103 protected SessionHandler _sessionHandler;
104 protected boolean _httpOnly=false;
105 protected SessionIdManager _sessionIdManager;
106 protected boolean _secureCookies=false;
107 protected boolean _secureRequestOnly=true;
108
109 protected final List<HttpSessionAttributeListener> _sessionAttributeListeners = new CopyOnWriteArrayList<HttpSessionAttributeListener>();
110 protected final List<HttpSessionListener> _sessionListeners= new CopyOnWriteArrayList<HttpSessionListener>();
111
112 protected ClassLoader _loader;
113 protected ContextHandler.Context _context;
114 protected String _sessionCookie=__DefaultSessionCookie;
115 protected String _sessionIdPathParameterName = __DefaultSessionIdPathParameterName;
116 protected String _sessionIdPathParameterNamePrefix =";"+ _sessionIdPathParameterName +"=";
117 protected String _sessionDomain;
118 protected String _sessionPath;
119 protected int _maxCookieAge=-1;
120 protected int _refreshCookieAge;
121 protected boolean _nodeIdInSessionId;
122 protected boolean _checkingRemoteSessionIdEncoding;
123 protected String _sessionComment;
124
125 public Set<SessionTrackingMode> _sessionTrackingModes;
126
127 private boolean _usingURLs;
128
129 protected final CounterStatistic _sessionsStats = new CounterStatistic();
130 protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
131
132
133
134 public static HttpSession renewSession (HttpServletRequest request, HttpSession httpSession, boolean authenticated)
135 {
136 Map<String,Object> attributes = new HashMap<String, Object>();
137
138 for (Enumeration<String> e=httpSession.getAttributeNames();e.hasMoreElements();)
139 {
140 String name=e.nextElement();
141 attributes.put(name,httpSession.getAttribute(name));
142 httpSession.removeAttribute(name);
143 }
144
145 httpSession.invalidate();
146 httpSession = request.getSession(true);
147 if (authenticated)
148 httpSession.setAttribute(SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
149 for (Map.Entry<String, Object> entry: attributes.entrySet())
150 httpSession.setAttribute(entry.getKey(),entry.getValue());
151 return httpSession;
152 }
153
154
155 public AbstractSessionManager()
156 {
157 setSessionTrackingModes(__defaultSessionTrackingModes);
158 }
159
160
161 public ContextHandler.Context getContext()
162 {
163 return _context;
164 }
165
166
167 public ContextHandler getContextHandler()
168 {
169 return _context.getContextHandler();
170 }
171
172 @ManagedAttribute("path of the session cookie, or null for default")
173 public String getSessionPath()
174 {
175 return _sessionPath;
176 }
177
178 @ManagedAttribute("if greater the zero, the time in seconds a session cookie will last for")
179 public int getMaxCookieAge()
180 {
181 return _maxCookieAge;
182 }
183
184
185 public HttpCookie access(HttpSession session,boolean secure)
186 {
187 long now=System.currentTimeMillis();
188
189 AbstractSession s = ((SessionIf)session).getSession();
190
191 if (s.access(now))
192 {
193
194 if (isUsingCookies() &&
195 (s.isIdChanged() ||
196 (getSessionCookieConfig().getMaxAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
197 )
198 )
199 {
200 HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure);
201 s.cookieSet();
202 s.setIdChanged(false);
203 return cookie;
204 }
205 }
206 return null;
207 }
208
209
210 public void addEventListener(EventListener listener)
211 {
212 if (listener instanceof HttpSessionAttributeListener)
213 _sessionAttributeListeners.add((HttpSessionAttributeListener)listener);
214 if (listener instanceof HttpSessionListener)
215 _sessionListeners.add((HttpSessionListener)listener);
216 }
217
218
219 public void clearEventListeners()
220 {
221 _sessionAttributeListeners.clear();
222 _sessionListeners.clear();
223 }
224
225
226 public void complete(HttpSession session)
227 {
228 AbstractSession s = ((SessionIf)session).getSession();
229 s.complete();
230 }
231
232
233 @Override
234 public void doStart() throws Exception
235 {
236 _context=ContextHandler.getCurrentContext();
237 _loader=Thread.currentThread().getContextClassLoader();
238
239 if (_sessionIdManager==null)
240 {
241 final Server server=getSessionHandler().getServer();
242 synchronized (server)
243 {
244 _sessionIdManager=server.getSessionIdManager();
245 if (_sessionIdManager==null)
246 {
247 _sessionIdManager=new HashSessionIdManager();
248 server.setSessionIdManager(_sessionIdManager);
249 }
250 }
251 }
252 if (!_sessionIdManager.isStarted())
253 _sessionIdManager.start();
254
255
256 if (_context!=null)
257 {
258 String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
259 if (tmp!=null)
260 _sessionCookie=tmp;
261
262 tmp=_context.getInitParameter(SessionManager.__SessionIdPathParameterNameProperty);
263 if (tmp!=null)
264 setSessionIdPathParameterName(tmp);
265
266
267 if (_maxCookieAge==-1)
268 {
269 tmp=_context.getInitParameter(SessionManager.__MaxAgeProperty);
270 if (tmp!=null)
271 _maxCookieAge=Integer.parseInt(tmp.trim());
272 }
273
274
275 if (_sessionDomain==null)
276 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
277
278
279 if (_sessionPath==null)
280 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
281
282 tmp=_context.getInitParameter(SessionManager.__CheckRemoteSessionEncoding);
283 if (tmp!=null)
284 _checkingRemoteSessionIdEncoding=Boolean.parseBoolean(tmp);
285 }
286
287 super.doStart();
288 }
289
290
291 @Override
292 public void doStop() throws Exception
293 {
294 super.doStop();
295
296 invalidateSessions();
297
298 _loader=null;
299 }
300
301
302
303
304
305 @ManagedAttribute("true if cookies use the http only flag")
306 public boolean getHttpOnly()
307 {
308 return _httpOnly;
309 }
310
311
312 public HttpSession getHttpSession(String nodeId)
313 {
314 String cluster_id = getSessionIdManager().getClusterId(nodeId);
315
316 AbstractSession session = getSession(cluster_id);
317 if (session!=null && !session.getNodeId().equals(nodeId))
318 session.setIdChanged(true);
319 return session;
320 }
321
322
323
324
325
326
327 public SessionIdManager getIdManager()
328 {
329 return getSessionIdManager();
330 }
331
332
333
334
335
336 @ManagedAttribute("Session ID Manager")
337 public SessionIdManager getSessionIdManager()
338 {
339 return _sessionIdManager;
340 }
341
342
343
344
345
346
347 @Override
348 @ManagedAttribute("defailt maximum time a session may be idle for (in s)")
349 public int getMaxInactiveInterval()
350 {
351 return _dftMaxIdleSecs;
352 }
353
354
355
356
357
358 @Deprecated
359 public int getMaxSessions()
360 {
361 return getSessionsMax();
362 }
363
364
365
366
367
368 @ManagedAttribute("maximum number of simultaneous sessions")
369 public int getSessionsMax()
370 {
371 return (int)_sessionsStats.getMax();
372 }
373
374
375
376
377
378 @ManagedAttribute("total number of sessions")
379 public int getSessionsTotal()
380 {
381 return (int)_sessionsStats.getTotal();
382 }
383
384
385
386
387
388 @Deprecated
389 public SessionIdManager getMetaManager()
390 {
391 return getSessionIdManager();
392 }
393
394
395
396
397
398 @Deprecated
399 public int getMinSessions()
400 {
401 return 0;
402 }
403
404
405 @ManagedAttribute("time before a session cookie is re-set (in s)")
406 public int getRefreshCookieAge()
407 {
408 return _refreshCookieAge;
409 }
410
411
412
413
414
415
416
417
418 @ManagedAttribute("if true, secure cookie flag is set on session cookies")
419 public boolean getSecureCookies()
420 {
421 return _secureCookies;
422 }
423
424
425
426
427
428 public boolean isSecureRequestOnly()
429 {
430 return _secureRequestOnly;
431 }
432
433
434
435
436
437
438
439
440 public void setSecureRequestOnly(boolean secureRequestOnly)
441 {
442 _secureRequestOnly = secureRequestOnly;
443 }
444
445
446
447
448 @ManagedAttribute("the set session cookie")
449 public String getSessionCookie()
450 {
451 return _sessionCookie;
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
481 {
482 if (isUsingCookies())
483 {
484 String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath;
485 sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath;
486 String id = getNodeId(session);
487 HttpCookie cookie = null;
488 if (_sessionComment == null)
489 {
490 cookie = new HttpCookie(
491 _sessionCookie,
492 id,
493 _sessionDomain,
494 sessionPath,
495 _cookieConfig.getMaxAge(),
496 _cookieConfig.isHttpOnly(),
497 _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure));
498 }
499 else
500 {
501 cookie = new HttpCookie(
502 _sessionCookie,
503 id,
504 _sessionDomain,
505 sessionPath,
506 _cookieConfig.getMaxAge(),
507 _cookieConfig.isHttpOnly(),
508 _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure),
509 _sessionComment,
510 1);
511 }
512
513 return cookie;
514 }
515 return null;
516 }
517
518 @ManagedAttribute("domain of the session cookie, or null for the default")
519 public String getSessionDomain()
520 {
521 return _sessionDomain;
522 }
523
524
525
526
527
528 public SessionHandler getSessionHandler()
529 {
530 return _sessionHandler;
531 }
532
533
534
535
536
537 @SuppressWarnings("rawtypes")
538 public Map getSessionMap()
539 {
540 throw new UnsupportedOperationException();
541 }
542
543
544
545
546 @ManagedAttribute("number of currently active sessions")
547 public int getSessions()
548 {
549 return (int)_sessionsStats.getCurrent();
550 }
551
552
553 @ManagedAttribute("name of use for URL session tracking")
554 public String getSessionIdPathParameterName()
555 {
556 return _sessionIdPathParameterName;
557 }
558
559
560 public String getSessionIdPathParameterNamePrefix()
561 {
562 return _sessionIdPathParameterNamePrefix;
563 }
564
565
566
567
568
569 public boolean isUsingCookies()
570 {
571 return _usingCookies;
572 }
573
574
575 public boolean isValid(HttpSession session)
576 {
577 AbstractSession s = ((SessionIf)session).getSession();
578 return s.isValid();
579 }
580
581
582 public String getClusterId(HttpSession session)
583 {
584 AbstractSession s = ((SessionIf)session).getSession();
585 return s.getClusterId();
586 }
587
588
589 public String getNodeId(HttpSession session)
590 {
591 AbstractSession s = ((SessionIf)session).getSession();
592 return s.getNodeId();
593 }
594
595
596
597
598
599 public HttpSession newHttpSession(HttpServletRequest request)
600 {
601 AbstractSession session=newSession(request);
602 session.setMaxInactiveInterval(_dftMaxIdleSecs);
603 addSession(session,true);
604 return session;
605 }
606
607
608 public void removeEventListener(EventListener listener)
609 {
610 if (listener instanceof HttpSessionAttributeListener)
611 _sessionAttributeListeners.remove(listener);
612 if (listener instanceof HttpSessionListener)
613 _sessionListeners.remove(listener);
614 }
615
616
617
618
619
620 @Deprecated
621 public void resetStats()
622 {
623 statsReset();
624 }
625
626
627
628
629
630 @ManagedOperation(value="reset statistics", impact="ACTION")
631 public void statsReset()
632 {
633 _sessionsStats.reset(getSessions());
634 _sessionTimeStats.reset();
635 }
636
637
638
639
640
641
642 public void setHttpOnly(boolean httpOnly)
643 {
644 _httpOnly=httpOnly;
645 }
646
647
648
649
650
651
652 public void setIdManager(SessionIdManager metaManager)
653 {
654 setSessionIdManager(metaManager);
655 }
656
657
658
659
660
661 public void setSessionIdManager(SessionIdManager metaManager)
662 {
663 _sessionIdManager=metaManager;
664 }
665
666
667
668
669
670
671
672 public void setMaxInactiveInterval(int seconds)
673 {
674 _dftMaxIdleSecs=seconds;
675 }
676
677
678
679 public void setRefreshCookieAge(int ageInSeconds)
680 {
681 _refreshCookieAge=ageInSeconds;
682 }
683
684
685
686 public void setSessionCookie(String cookieName)
687 {
688 _sessionCookie=cookieName;
689 }
690
691
692
693
694
695
696
697
698 public void setSessionHandler(SessionHandler sessionHandler)
699 {
700 _sessionHandler=sessionHandler;
701 }
702
703
704
705 public void setSessionIdPathParameterName(String param)
706 {
707 _sessionIdPathParameterName =(param==null||"none".equals(param))?null:param;
708 _sessionIdPathParameterNamePrefix =(param==null||"none".equals(param))?null:(";"+ _sessionIdPathParameterName +"=");
709 }
710
711
712
713
714
715 public void setUsingCookies(boolean usingCookies)
716 {
717 _usingCookies=usingCookies;
718 }
719
720
721 protected abstract void addSession(AbstractSession session);
722
723
724
725
726
727
728 protected void addSession(AbstractSession session, boolean created)
729 {
730 synchronized (_sessionIdManager)
731 {
732 _sessionIdManager.addSession(session);
733 addSession(session);
734 }
735
736 if (created)
737 {
738 _sessionsStats.increment();
739 if (_sessionListeners!=null)
740 {
741 HttpSessionEvent event=new HttpSessionEvent(session);
742 for (HttpSessionListener listener : _sessionListeners)
743 listener.sessionCreated(event);
744 }
745 }
746 }
747
748
749
750
751
752
753
754 public abstract AbstractSession getSession(String idInCluster);
755
756 protected abstract void invalidateSessions() throws Exception;
757
758
759
760
761
762
763
764
765 protected abstract AbstractSession newSession(HttpServletRequest request);
766
767
768
769
770
771
772 public boolean isNodeIdInSessionId()
773 {
774 return _nodeIdInSessionId;
775 }
776
777
778
779
780
781 public void setNodeIdInSessionId(boolean nodeIdInSessionId)
782 {
783 _nodeIdInSessionId=nodeIdInSessionId;
784 }
785
786
787
788
789
790
791
792 public void removeSession(HttpSession session, boolean invalidate)
793 {
794 AbstractSession s = ((SessionIf)session).getSession();
795 removeSession(s,invalidate);
796 }
797
798
799
800
801
802
803
804 public void removeSession(AbstractSession session, boolean invalidate)
805 {
806
807 boolean removed = removeSession(session.getClusterId());
808
809 if (removed)
810 {
811 _sessionsStats.decrement();
812 _sessionTimeStats.set(round((System.currentTimeMillis() - session.getCreationTime())/1000.0));
813
814
815 _sessionIdManager.removeSession(session);
816 if (invalidate)
817 _sessionIdManager.invalidateAll(session.getClusterId());
818
819 if (invalidate && _sessionListeners!=null)
820 {
821 HttpSessionEvent event=new HttpSessionEvent(session);
822 for (HttpSessionListener listener : _sessionListeners)
823 listener.sessionDestroyed(event);
824 }
825 }
826 }
827
828
829 protected abstract boolean removeSession(String idInCluster);
830
831
832
833
834
835 @ManagedAttribute("maximum amount of time sessions have remained active (in s)")
836 public long getSessionTimeMax()
837 {
838 return _sessionTimeStats.getMax();
839 }
840
841
842 public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
843 {
844 return __defaultSessionTrackingModes;
845 }
846
847
848 public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
849 {
850 return Collections.unmodifiableSet(_sessionTrackingModes);
851 }
852
853
854 @Override
855 public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
856 {
857 _sessionTrackingModes=new HashSet<SessionTrackingMode>(sessionTrackingModes);
858 _usingCookies=_sessionTrackingModes.contains(SessionTrackingMode.COOKIE);
859 _usingURLs=_sessionTrackingModes.contains(SessionTrackingMode.URL);
860 }
861
862
863 @Override
864 public boolean isUsingURLs()
865 {
866 return _usingURLs;
867 }
868
869
870
871 public SessionCookieConfig getSessionCookieConfig()
872 {
873 return _cookieConfig;
874 }
875
876
877 private SessionCookieConfig _cookieConfig =
878 new SessionCookieConfig()
879 {
880 @Override
881 public String getComment()
882 {
883 return _sessionComment;
884 }
885
886 @Override
887 public String getDomain()
888 {
889 return _sessionDomain;
890 }
891
892 @Override
893 public int getMaxAge()
894 {
895 return _maxCookieAge;
896 }
897
898 @Override
899 public String getName()
900 {
901 return _sessionCookie;
902 }
903
904 @Override
905 public String getPath()
906 {
907 return _sessionPath;
908 }
909
910 @Override
911 public boolean isHttpOnly()
912 {
913 return _httpOnly;
914 }
915
916 @Override
917 public boolean isSecure()
918 {
919 return _secureCookies;
920 }
921
922 @Override
923 public void setComment(String comment)
924 {
925 _sessionComment = comment;
926 }
927
928 @Override
929 public void setDomain(String domain)
930 {
931 _sessionDomain=domain;
932 }
933
934 @Override
935 public void setHttpOnly(boolean httpOnly)
936 {
937 _httpOnly=httpOnly;
938 }
939
940 @Override
941 public void setMaxAge(int maxAge)
942 {
943 _maxCookieAge=maxAge;
944 }
945
946 @Override
947 public void setName(String name)
948 {
949 _sessionCookie=name;
950 }
951
952 @Override
953 public void setPath(String path)
954 {
955 _sessionPath=path;
956 }
957
958 @Override
959 public void setSecure(boolean secure)
960 {
961 _secureCookies=secure;
962 }
963
964 };
965
966
967
968
969
970
971 @ManagedAttribute("total time sessions have remained valid")
972 public long getSessionTimeTotal()
973 {
974 return _sessionTimeStats.getTotal();
975 }
976
977
978
979
980
981 @ManagedAttribute("mean time sessions remain valid (in s)")
982 public double getSessionTimeMean()
983 {
984 return _sessionTimeStats.getMean();
985 }
986
987
988
989
990
991 @ManagedAttribute("standard deviation a session remained valid (in s)")
992 public double getSessionTimeStdDev()
993 {
994 return _sessionTimeStats.getStdDev();
995 }
996
997
998
999
1000
1001 @ManagedAttribute("check remote session id encoding")
1002 public boolean isCheckingRemoteSessionIdEncoding()
1003 {
1004 return _checkingRemoteSessionIdEncoding;
1005 }
1006
1007
1008
1009
1010
1011 public void setCheckingRemoteSessionIdEncoding(boolean remote)
1012 {
1013 _checkingRemoteSessionIdEncoding=remote;
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 public interface SessionIf extends HttpSession
1025 {
1026 public AbstractSession getSession();
1027 }
1028
1029 public void doSessionAttributeListeners(AbstractSession session, String name, Object old, Object value)
1030 {
1031 if (!_sessionAttributeListeners.isEmpty())
1032 {
1033 HttpSessionBindingEvent event=new HttpSessionBindingEvent(session,name,old==null?value:old);
1034
1035 for (HttpSessionAttributeListener l : _sessionAttributeListeners)
1036 {
1037 if (old==null)
1038 l.attributeAdded(event);
1039 else if (value==null)
1040 l.attributeRemoved(event);
1041 else
1042 l.attributeReplaced(event);
1043 }
1044 }
1045 }
1046 }