a5117043cba2ea7ee8f811df3cb9ddb192610c02
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / session / impl / SessionManagerImpl.java
1 /*
2  * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package edu.internet2.middleware.shibboleth.idp.session.impl;
18
19 import java.security.SecureRandom;
20
21 import org.joda.time.DateTime;
22 import org.opensaml.util.storage.ExpiringObject;
23 import org.opensaml.util.storage.StorageService;
24 import org.opensaml.xml.util.Base64;
25 import org.opensaml.xml.util.DatatypeHelper;
26 import org.springframework.context.ApplicationContext;
27 import org.springframework.context.ApplicationContextAware;
28
29 import edu.internet2.middleware.shibboleth.common.session.LoginEvent;
30 import edu.internet2.middleware.shibboleth.common.session.LogoutEvent;
31 import edu.internet2.middleware.shibboleth.common.session.SessionManager;
32 import edu.internet2.middleware.shibboleth.idp.session.Session;
33
34 /**
35  * Manager of IdP sessions.
36  */
37 public class SessionManagerImpl implements SessionManager<Session>, ApplicationContextAware {
38
39     /** Spring context used to publish login and logout events. */
40     private ApplicationContext appCtx;
41     
42     /** Number of random bits within a session ID. */
43     private final int sessionIDSize = 32;
44     
45     /** A {@link SecureRandom} PRNG to generate session IDs. */
46     private final SecureRandom prng = new SecureRandom();
47
48     /** Backing service used to store sessions. */
49     private StorageService<String, SessionManagerEntry> sessionStore;
50
51     /** Parition in which entries are stored. */
52     private String partition;
53
54     /** Lifetime, in milliseconds, of session. */
55     private long sessionLifetime;
56
57     /**
58      * Constructor.
59      * 
60      * @param storageService service used to store sessions
61      * @param lifetime lifetime, in milliseconds, of sessions
62      */
63     public SessionManagerImpl(StorageService<String, SessionManagerEntry> storageService, long lifetime) {
64         sessionStore = storageService;
65         partition = "session";
66         sessionLifetime = lifetime;
67     }
68
69     /**
70      * Constructor.
71      * 
72      * @param storageService service used to store session
73      * @param storageParition partition in which sessions are stored
74      * @param lifetime lifetime, in milliseconds, of sessions
75      */
76     public SessionManagerImpl(StorageService<String, SessionManagerEntry> storageService, String storageParition,
77             long lifetime) {
78         sessionStore = storageService;
79         if (!DatatypeHelper.isEmpty(storageParition)) {
80             partition = DatatypeHelper.safeTrim(storageParition);
81         } else {
82             partition = "session";
83         }
84         sessionLifetime = lifetime;
85     }
86
87     /** {@inheritDoc} */
88     public void setApplicationContext(ApplicationContext applicationContext) {
89         appCtx = applicationContext;
90     }
91
92     /** {@inheritDoc} */
93     public Session createSession(String principal) {
94         // generate a random session ID
95         byte[] sid = new byte[sessionIDSize];
96         prng.nextBytes(sid);
97         String sessionID = Base64.encodeBytes(sid);
98         
99         Session session = new SessionImpl(sessionID, principal, sessionLifetime);
100         SessionManagerEntry sessionEntry = new SessionManagerEntry(this, session, sessionLifetime);
101         sessionStore.put(partition, session.getSessionID(), sessionEntry);
102         appCtx.publishEvent(new LoginEvent(session));
103         return session;
104     }
105
106     /** {@inheritDoc} */
107     public void destroySession(String sessionID) {
108         if (sessionID == null) {
109             return;
110         }
111
112         SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
113         if (sessionEntry != null) {
114             appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
115         }
116     }
117
118     /** {@inheritDoc} */
119     public Session getSession(String sessionID) {
120         if (sessionID == null) {
121             return null;
122         }
123
124         SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
125         if (sessionEntry == null) {
126             return null;
127         }
128
129         if (sessionEntry.isExpired()) {
130             destroySession(sessionEntry.getSessionId());
131             return null;
132         } else {
133             return sessionEntry.getSession();
134         }
135     }
136
137     /**
138      * Session store entry.
139      */
140     public class SessionManagerEntry implements ExpiringObject {
141
142         /** User's session. */
143         private Session userSession;
144
145         /** Manager that owns the session. */
146         private SessionManager<Session> sessionManager;
147
148         /** Time this entry expires. */
149         private DateTime expirationTime;
150
151         /**
152          * Constructor.
153          * 
154          * @param manager manager that owns the session
155          * @param session user session
156          * @param lifetime lifetime of session
157          */
158         public SessionManagerEntry(SessionManager<Session> manager, Session session, long lifetime) {
159             sessionManager = manager;
160             userSession = session;
161             expirationTime = new DateTime().plus(lifetime);
162         }
163
164         /**
165          * Gets the user session.
166          * 
167          * @return user session
168          */
169         public Session getSession() {
170             return userSession;
171         }
172
173         /**
174          * Gets the ID of the user session.
175          * 
176          * @return ID of the user session
177          */
178         public String getSessionId() {
179             return userSession.getSessionID();
180         }
181
182         /** {@inheritDoc} */
183         public DateTime getExpirationTime() {
184             return expirationTime;
185         }
186
187         /** {@inheritDoc} */
188         public boolean isExpired() {
189             return expirationTime.isBeforeNow();
190         }
191
192         /** {@inheritDoc} */
193         public void onExpire() {
194             sessionManager.destroySession(userSession.getSessionID());
195         }
196     }
197 }