1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.session.mgt;
20
21 import org.apache.shiro.authz.AuthorizationException;
22 import org.apache.shiro.session.ExpiredSessionException;
23 import org.apache.shiro.session.InvalidSessionException;
24 import org.apache.shiro.session.Session;
25 import org.apache.shiro.session.UnknownSessionException;
26 import org.apache.shiro.util.Destroyable;
27 import org.apache.shiro.util.LifecycleUtils;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import java.util.Collection;
32
33
34
35
36
37
38
39 public abstract class AbstractValidatingSessionManager extends AbstractNativeSessionManager
40 implements ValidatingSessionManager, Destroyable {
41
42
43
44 private static final Logger log = LoggerFactory.getLogger(AbstractValidatingSessionManager.class);
45
46
47
48
49
50 public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = MILLIS_PER_HOUR;
51
52 protected boolean sessionValidationSchedulerEnabled;
53
54
55
56
57 protected SessionValidationScheduler sessionValidationScheduler;
58
59 protected long sessionValidationInterval;
60
61 public AbstractValidatingSessionManager() {
62 this.sessionValidationSchedulerEnabled = true;
63 this.sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;
64 }
65
66 public boolean isSessionValidationSchedulerEnabled() {
67 return sessionValidationSchedulerEnabled;
68 }
69
70 @SuppressWarnings({"UnusedDeclaration"})
71 public void setSessionValidationSchedulerEnabled(boolean sessionValidationSchedulerEnabled) {
72 this.sessionValidationSchedulerEnabled = sessionValidationSchedulerEnabled;
73 }
74
75 public void setSessionValidationScheduler(SessionValidationScheduler sessionValidationScheduler) {
76 this.sessionValidationScheduler = sessionValidationScheduler;
77 }
78
79 public SessionValidationScheduler getSessionValidationScheduler() {
80 return sessionValidationScheduler;
81 }
82
83 private void enableSessionValidationIfNecessary() {
84 SessionValidationScheduler scheduler = getSessionValidationScheduler();
85 if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {
86 enableSessionValidation();
87 }
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 public void setSessionValidationInterval(long sessionValidationInterval) {
105 this.sessionValidationInterval = sessionValidationInterval;
106 }
107
108 public long getSessionValidationInterval() {
109 return sessionValidationInterval;
110 }
111
112 @Override
113 protected final Session doGetSession(final SessionKey key) throws InvalidSessionException {
114 enableSessionValidationIfNecessary();
115
116 log.trace("Attempting to retrieve session with key {}", key);
117
118 Session s = retrieveSession(key);
119 if (s != null) {
120 validate(s, key);
121 }
122 return s;
123 }
124
125
126
127
128
129
130
131
132 protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException;
133
134 protected Session createSession(SessionContext context) throws AuthorizationException {
135 enableSessionValidationIfNecessary();
136 return doCreateSession(context);
137 }
138
139 protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException;
140
141 protected void validate(Session session, SessionKey key) throws InvalidSessionException {
142 try {
143 doValidate(session);
144 } catch (ExpiredSessionException ese) {
145 onExpiration(session, ese, key);
146 throw ese;
147 } catch (InvalidSessionException ise) {
148 onInvalidation(session, ise, key);
149 throw ise;
150 }
151 }
152
153 protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) {
154 log.trace("Session with id [{}] has expired.", s.getId());
155 try {
156 onExpiration(s);
157 notifyExpiration(s);
158 } finally {
159 afterExpired(s);
160 }
161 }
162
163 protected void onExpiration(Session session) {
164 onChange(session);
165 }
166
167 protected void afterExpired(Session session) {
168 }
169
170 protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey key) {
171 if (ise instanceof ExpiredSessionException) {
172 onExpiration(s, (ExpiredSessionException) ise, key);
173 return;
174 }
175 log.trace("Session with id [{}] is invalid.", s.getId());
176 try {
177 onStop(s);
178 notifyStop(s);
179 } finally {
180 afterStopped(s);
181 }
182 }
183
184 protected void doValidate(Session session) throws InvalidSessionException {
185 if (session instanceof ValidatingSession) {
186 ((ValidatingSession) session).validate();
187 } else {
188 String msg = "The " + getClass().getName() + " implementation only supports validating " +
189 "Session implementations of the " + ValidatingSession.class.getName() + " interface. " +
190 "Please either implement this interface in your session implementation or override the " +
191 AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
192 throw new IllegalStateException(msg);
193 }
194 }
195
196
197
198
199
200
201
202
203
204
205 protected long getTimeout(Session session) {
206 return session.getTimeout();
207 }
208
209 protected SessionValidationScheduler createSessionValidationScheduler() {
210 ExecutorServiceSessionValidationScheduler scheduler;
211
212 if (log.isDebugEnabled()) {
213 log.debug("No sessionValidationScheduler set. Attempting to create default instance.");
214 }
215 scheduler = new ExecutorServiceSessionValidationScheduler(this);
216 scheduler.setInterval(getSessionValidationInterval());
217 if (log.isTraceEnabled()) {
218 log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "].");
219 }
220 return scheduler;
221 }
222
223 protected synchronized void enableSessionValidation() {
224 SessionValidationScheduler scheduler = getSessionValidationScheduler();
225 if (scheduler == null) {
226 scheduler = createSessionValidationScheduler();
227 setSessionValidationScheduler(scheduler);
228 }
229
230
231 if (!scheduler.isEnabled()) {
232 if (log.isInfoEnabled()) {
233 log.info("Enabling session validation scheduler...");
234 }
235 scheduler.enableSessionValidation();
236 afterSessionValidationEnabled();
237 }
238 }
239
240 protected void afterSessionValidationEnabled() {
241 }
242
243 protected synchronized void disableSessionValidation() {
244 beforeSessionValidationDisabled();
245 SessionValidationScheduler scheduler = getSessionValidationScheduler();
246 if (scheduler != null) {
247 try {
248 scheduler.disableSessionValidation();
249 if (log.isInfoEnabled()) {
250 log.info("Disabled session validation scheduler.");
251 }
252 } catch (Exception e) {
253 if (log.isDebugEnabled()) {
254 String msg = "Unable to disable SessionValidationScheduler. Ignoring (shutting down)...";
255 log.debug(msg, e);
256 }
257 }
258 LifecycleUtils.destroy(scheduler);
259 setSessionValidationScheduler(null);
260 }
261 }
262
263 protected void beforeSessionValidationDisabled() {
264 }
265
266 public void destroy() {
267 disableSessionValidation();
268 }
269
270
271
272
273 public void validateSessions() {
274 if (log.isInfoEnabled()) {
275 log.info("Validating all active sessions...");
276 }
277
278 int invalidCount = 0;
279
280 Collection<Session> activeSessions = getActiveSessions();
281
282 if (activeSessions != null && !activeSessions.isEmpty()) {
283 for (Session s : activeSessions) {
284 try {
285
286
287 SessionKey key = new DefaultSessionKey(s.getId());
288 validate(s, key);
289 } catch (InvalidSessionException e) {
290 if (log.isDebugEnabled()) {
291 boolean expired = (e instanceof ExpiredSessionException);
292 String msg = "Invalidated session with id [" + s.getId() + "]" +
293 (expired ? " (expired)" : " (stopped)");
294 log.debug(msg);
295 }
296 invalidCount++;
297 }
298 }
299 }
300
301 if (log.isInfoEnabled()) {
302 String msg = "Finished session validation.";
303 if (invalidCount > 0) {
304 msg += " [" + invalidCount + "] sessions were stopped.";
305 } else {
306 msg += " No sessions were stopped.";
307 }
308 log.info(msg);
309 }
310 }
311
312 protected abstract Collection<Session> getActiveSessions();
313 }