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