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