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