1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.idp.session.impl;
18
19 import java.security.SecureRandom;
20
21 import org.apache.commons.ssl.util.Hex;
22 import org.opensaml.util.storage.StorageService;
23 import org.opensaml.xml.util.DatatypeHelper;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.slf4j.MDC;
27 import org.springframework.context.ApplicationContext;
28 import org.springframework.context.ApplicationContextAware;
29 import org.springframework.context.ApplicationEvent;
30 import org.springframework.context.ApplicationListener;
31
32 import edu.internet2.middleware.shibboleth.common.session.LoginEvent;
33 import edu.internet2.middleware.shibboleth.common.session.LogoutEvent;
34 import edu.internet2.middleware.shibboleth.common.session.SessionManager;
35 import edu.internet2.middleware.shibboleth.common.util.EventingMapBasedStorageService.AddEntryEvent;
36 import edu.internet2.middleware.shibboleth.common.util.EventingMapBasedStorageService.RemoveEntryEvent;
37 import edu.internet2.middleware.shibboleth.idp.session.Session;
38
39
40 public class SessionManagerImpl implements SessionManager<Session>, ApplicationContextAware, ApplicationListener {
41
42
43 private final Logger log = LoggerFactory.getLogger(SessionManagerImpl.class);
44
45
46 private ApplicationContext appCtx;
47
48
49 private final int sessionIDSize = 32;
50
51
52 private final SecureRandom prng = new SecureRandom();
53
54
55 private StorageService<String, SessionManagerEntry> sessionStore;
56
57
58 private String partition;
59
60
61 private long sessionLifetime;
62
63
64
65
66
67
68
69 public SessionManagerImpl(StorageService<String, SessionManagerEntry> storageService, long lifetime) {
70 sessionStore = storageService;
71 partition = "session";
72 sessionLifetime = lifetime;
73 }
74
75
76
77
78
79
80
81
82 public SessionManagerImpl(StorageService<String, SessionManagerEntry> storageService, String storageParition,
83 long lifetime) {
84 sessionStore = storageService;
85 if (!DatatypeHelper.isEmpty(storageParition)) {
86 partition = DatatypeHelper.safeTrim(storageParition);
87 } else {
88 partition = "session";
89 }
90 sessionLifetime = lifetime;
91 }
92
93
94 public Session createSession() {
95
96 byte[] sid = new byte[sessionIDSize];
97 prng.nextBytes(sid);
98 String sessionID = Hex.encode(sid);
99
100 byte[] sessionSecret = new byte[16];
101 prng.nextBytes(sessionSecret);
102
103 Session session = new SessionImpl(sessionID, sessionSecret, sessionLifetime);
104 SessionManagerEntry sessionEntry = new SessionManagerEntry(session, sessionLifetime);
105 sessionStore.put(partition, sessionID, sessionEntry);
106
107 MDC.put("idpSessionId", sessionID);
108 log.trace("Created session {}", sessionID);
109 appCtx.publishEvent(new LoginEvent(session));
110 return session;
111 }
112
113
114 public Session createSession(String principal) {
115
116 byte[] sid = new byte[sessionIDSize];
117 prng.nextBytes(sid);
118 String sessionID = Hex.encode(sid);
119
120 byte[] sessionSecret = new byte[16];
121 prng.nextBytes(sessionSecret);
122
123 Session session = new SessionImpl(sessionID, sessionSecret, sessionLifetime);
124 SessionManagerEntry sessionEntry = new SessionManagerEntry(session, sessionLifetime);
125 sessionStore.put(partition, sessionID, sessionEntry);
126
127 MDC.put("idpSessionId", sessionID);
128 log.trace("Created session {}", sessionID);
129 return session;
130 }
131
132
133 public void destroySession(String sessionID) {
134 if (sessionID == null) {
135 return;
136 }
137
138 sessionStore.remove(partition, sessionID);
139 }
140
141
142 public Session getSession(String sessionID) {
143 if (sessionID == null) {
144 return null;
145 }
146
147 SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
148 if (sessionEntry == null) {
149 return null;
150 }
151
152 if (sessionEntry.isExpired()) {
153 destroySession(sessionEntry.getSessionId());
154 return null;
155 } else {
156 return sessionEntry.getSession();
157 }
158 }
159
160
161 public boolean indexSession(Session session, String index) {
162 if (sessionStore.contains(partition, index)) {
163 return false;
164 }
165
166 SessionManagerEntry sessionEntry = sessionStore.get(partition, session.getSessionID());
167 if (sessionEntry == null) {
168 return false;
169 }
170
171 if (sessionEntry.getSessionIndexes().contains(index)) {
172 return true;
173 }
174
175 sessionEntry.getSessionIndexes().add(index);
176 sessionStore.put(partition, index, sessionEntry);
177 log.trace("Added index {} to session {}", index, session.getSessionID());
178 return true;
179 }
180
181
182 public void onApplicationEvent(ApplicationEvent event) {
183 if (event instanceof AddEntryEvent) {
184 AddEntryEvent addEvent = (AddEntryEvent) event;
185 if (addEvent.getValue() instanceof SessionManagerEntry) {
186 SessionManagerEntry sessionEntry = (SessionManagerEntry) addEvent.getValue();
187 appCtx.publishEvent(new LoginEvent(sessionEntry.getSession()));
188 }
189 }
190
191 if (event instanceof RemoveEntryEvent) {
192 RemoveEntryEvent removeEvent = (RemoveEntryEvent) event;
193 if (removeEvent.getValue() instanceof SessionManagerEntry) {
194 SessionManagerEntry sessionEntry = (SessionManagerEntry) removeEvent.getValue();
195 appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
196 }
197 }
198 }
199
200
201 public void removeSessionIndex(String index) {
202 SessionManagerEntry sessionEntry = sessionStore.remove(partition, index);
203 if (sessionEntry != null) {
204 log.trace("Removing index {} for session {}", index, sessionEntry.getSessionId());
205 sessionEntry.getSessionIndexes().remove(index);
206 }
207 }
208
209
210 public void setApplicationContext(ApplicationContext applicationContext) {
211 ApplicationContext rootContext = applicationContext;
212 while (rootContext.getParent() != null) {
213 rootContext = rootContext.getParent();
214 }
215 appCtx = rootContext;
216 }
217 }