Support lookup of session by principal name or session ID
[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     /** Partition 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, sessionID, sessionEntry);
102         sessionStore.put(partition, principal, sessionEntry);
103         appCtx.publishEvent(new LoginEvent(session));
104         return session;
105     }
106
107     /** {@inheritDoc} */
108     public void destroySession(String sessionID) {
109         if (sessionID == null) {
110             return;
111         }
112
113         SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
114         if (sessionEntry != null) {
115             appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
116         }
117     }
118
119     /** {@inheritDoc} */
120     public Session getSession(String sessionID) {
121         if (sessionID == null) {
122             return null;
123         }
124
125         SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
126         if (sessionEntry == null) {
127             return null;
128         }
129
130         if (sessionEntry.isExpired()) {
131             destroySession(sessionEntry.getSessionId());
132             return null;
133         } else {
134             return sessionEntry.getSession();
135         }
136     }
137     
138     /** {@inheritDoc} */
139     public Session getSessionByPrincipalName(String name) {
140         
141         //TODO
142         return null;
143     }
144
145     /**
146      * Session store entry.
147      */
148     public class SessionManagerEntry implements ExpiringObject {
149
150         /** User's session. */
151         private Session userSession;
152
153         /** Manager that owns the session. */
154         private SessionManager<Session> sessionManager;
155
156         /** Time this entry expires. */
157         private DateTime expirationTime;
158
159         /**
160          * Constructor.
161          * 
162          * @param manager manager that owns the session
163          * @param session user session
164          * @param lifetime lifetime of session
165          */
166         public SessionManagerEntry(SessionManager<Session> manager, Session session, long lifetime) {
167             sessionManager = manager;
168             userSession = session;
169             expirationTime = new DateTime().plus(lifetime);
170         }
171
172         /**
173          * Gets the user session.
174          * 
175          * @return user session
176          */
177         public Session getSession() {
178             return userSession;
179         }
180
181         /**
182          * Gets the ID of the user session.
183          * 
184          * @return ID of the user session
185          */
186         public String getSessionId() {
187             return userSession.getSessionID();
188         }
189
190         /** {@inheritDoc} */
191         public DateTime getExpirationTime() {
192             return expirationTime;
193         }
194
195         /** {@inheritDoc} */
196         public boolean isExpired() {
197             return expirationTime.isBeforeNow();
198         }
199
200         /** {@inheritDoc} */
201         public void onExpire() {
202             sessionManager.destroySession(userSession.getSessionID());
203         }
204     }
205 }