1 /**
2 * Copyright 2005-2012 The Kuali Foundation
3 *
4 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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 package org.kuali.rice.krad;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.config.property.ConfigContext;
20 import org.kuali.rice.core.api.exception.RiceRuntimeException;
21 import org.kuali.rice.kim.api.identity.Person;
22 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
23 import org.kuali.rice.krad.util.SessionTicket;
24
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.atomic.AtomicInteger;
32
33 /**
34 * Holds info about the User Session
35 *
36 * @author Kuali Rice Team (rice.collab@kuali.org)
37 */
38 public class UserSession implements Serializable {
39 private static final long serialVersionUID = 4532616762540067557L;
40
41 private Person person;
42 private Person backdoorUser;
43 private AtomicInteger nextObjectKey;
44 private Map<String, Object> objectMap;
45 private String kualiSessionId;
46
47 /**
48 * Returns the session id. The session id is a unique identifier for the session.
49 * @return the kualiSessionId
50 */
51 public String getKualiSessionId() {
52 return this.kualiSessionId;
53 }
54
55 /**
56 * Sets the session id.
57 * @param kualiSessionId the kualiSessionId to set
58 */
59 public void setKualiSessionId(String kualiSessionId) {
60 this.kualiSessionId = kualiSessionId;
61 }
62
63 /**
64 * Creates a user session for the principal specified in the parameter.
65 * Take in a netid, and construct the user from that.
66 *
67 * @param principalName
68 */
69 public UserSession(String principalName) {
70 initPerson(principalName);
71 this.nextObjectKey = new AtomicInteger(0);
72 this.objectMap = Collections.synchronizedMap(new HashMap<String,Object>());
73 }
74
75 /**
76 * Loads the Person object from KIM. Factored out for testability.
77 * @param principalName the principalName
78 */
79 protected void initPerson(String principalName) {
80 this.person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName);
81 if (this.person == null) {
82 throw new IllegalArgumentException(
83 "Failed to locate a principal with principal name '" + principalName + "'");
84 }
85 }
86
87 /**
88 * Returns the id of the current user.
89 * @return the principalId of the current user in the system, backdoor principalId if backdoor is set
90 */
91 public String getPrincipalId() {
92 if (backdoorUser != null) {
93 return backdoorUser.getPrincipalId();
94 }
95 return person.getPrincipalId();
96 }
97
98 /**
99 * Returns the name of the current user.
100 * @return the principalName of the current user in the system, backdoor principalName if backdoor is set
101 */
102 public String getPrincipalName() {
103 if (backdoorUser != null) {
104 return backdoorUser.getPrincipalName();
105 }
106 return person.getPrincipalName();
107 }
108
109 /**
110 * Returns who is logged in. If the backdoor is in use, this will return the network id of the person that is
111 * standing in as the backdoor user.
112 *
113 * @return String
114 */
115 public String getLoggedInUserPrincipalName() {
116 if (person != null) {
117 return person.getPrincipalName();
118 }
119 return "";
120 }
121
122 /**
123 * Returns a Person object for the current user.
124 * @return the KualiUser which is the current user in the system, backdoor if backdoor is set
125 */
126 public Person getPerson() {
127 if (backdoorUser != null) {
128 return backdoorUser;
129 }
130 return person;
131 }
132
133 /**
134 * Returns the actual current user even if the backdoor is in use.
135 * @return the KualiUser which is the current user in the system
136 */
137 public Person getActualPerson() {
138 return person;
139 }
140
141 /**
142 * override the current user in the system by setting the backdoor networkId, which is useful when dealing with
143 * routing or other reasons why you would need to assume an identity in the system
144 *
145 * @param principalName
146 */
147 public void setBackdoorUser(String principalName) {
148 // only allow backdoor in non-production environments
149 if (!isProductionEnvironment()) {
150 this.backdoorUser = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName);
151 }
152 }
153
154 private boolean isProductionEnvironment() {
155 return ConfigContext.getCurrentContextConfig().isProductionEnvironment();
156 }
157
158 /**
159 * clear the backdoor user
160 */
161 public void clearBackdoorUser() {
162 this.backdoorUser = null;
163 }
164
165 /**
166 * allows adding an arbitrary object to the session and returns a string key that can be used to later access this
167 * object from
168 * the session using the retrieveObject method in this class. This allows for a prefix to be placed in front of the
169 * incremented key. So if the prefix is "searchResults" and the nextObjectKey (local int that holds the key value)
170 * is 2 then
171 * the new key will be "searchResults3". "searchResults3" will be returned from the method.
172 *
173 * @param object
174 */
175 public String addObjectWithGeneratedKey(Serializable object, String keyPrefix) {
176 String objectKey = keyPrefix + nextObjectKey.incrementAndGet();
177 objectMap.put(objectKey, object);
178 return objectKey;
179 }
180
181 /**
182 * allows adding an arbitrary object to the session and returns a string key that can be used to later access this
183 * object from
184 * the session using the retrieveObject method in this class. The key is generated from an integer and incremented
185 * for every
186 * object added. So the first object added with have a key of "1". This key will be returned from the method.
187 *
188 * @param object
189 */
190 public String addObjectWithGeneratedKey(Object object) {
191 String objectKey = nextObjectKey.incrementAndGet() + "";
192 objectMap.put(objectKey, object);
193 return objectKey;
194 }
195
196 /**
197 * allows adding an arbitrary object to the session with static a string key that can be used to later access this
198 * object from
199 * the session using the retrieveObject method in this class
200 *
201 * @param object
202 */
203 public void addObject(String key, Object object) {
204 objectMap.put(key, object);
205 }
206
207 /**
208 * allows for fetching an object that has been put into the userSession based on the key that would have been
209 * returned when
210 * adding the object
211 *
212 * @param objectKey
213 */
214 public Object retrieveObject(String objectKey) {
215 return this.objectMap.get(objectKey);
216 }
217
218 /**
219 * allows for removal of an object from session that has been put into the userSession based on the key that would
220 * have been
221 * assigned
222 *
223 * @param objectKey
224 */
225 public void removeObject(String objectKey) {
226 this.objectMap.remove(objectKey);
227 }
228
229 /**
230 * allows for removal of an object from session that has been put into the userSession based on a key that starts
231 * with the given
232 * prefix
233 */
234 public void removeObjectsByPrefix(String objectKeyPrefix) {
235 synchronized (objectMap) {
236 List<String> removeKeys = new ArrayList<String>();
237 for (String key : objectMap.keySet()) {
238 if (key.startsWith(objectKeyPrefix)) {
239 removeKeys.add(key);
240 }
241 }
242
243 for (String key : removeKeys) {
244 this.objectMap.remove(key);
245 }
246 }
247 }
248
249 /**
250 * @return boolean indicating if the backdoor is in use
251 */
252 public boolean isBackdoorInUse() {
253 return backdoorUser != null;
254 }
255
256 /**
257 * Adds the given SessionTicket to the objectMap and returns the associated key
258 *
259 * @param ticket - SessionTicket to add
260 * @return the objectMap key for the ticket as a String
261 */
262 public String putSessionTicket(SessionTicket ticket) {
263 return addObjectWithGeneratedKey(ticket);
264 }
265
266 /**
267 * Retrieves all SessionTicket instances currently in the UserSession#objectMap
268 *
269 * @return List<SessionTicket> contained in user session
270 */
271 public List<SessionTicket> getAllSessionTickets() {
272 List<SessionTicket> sessionTickets = new ArrayList<SessionTicket>();
273
274 synchronized (objectMap) {
275 for (Object object : objectMap.values()) {
276 if (object instanceof SessionTicket) {
277 sessionTickets.add((SessionTicket) object);
278 }
279 }
280 }
281
282 return sessionTickets;
283 }
284
285 /**
286 * Retrieves all SessionTicket instances currently in the UserSession#objectMap that are of a given ticket type
287 *
288 * @return List<SessionTicket> contained in user session
289 */
290 public List<SessionTicket> getAllSessionTicketsByType(String ticketTypeName) {
291 List<SessionTicket> sessionTickets = new ArrayList<SessionTicket>();
292
293 for (SessionTicket ticket : getAllSessionTickets()) {
294 if (StringUtils.equalsIgnoreCase(ticket.getTicketTypeName(), ticketTypeName)) {
295 sessionTickets.add(ticket);
296 }
297 }
298
299 return sessionTickets;
300 }
301
302 /**
303 * Determines if the UserSession contains a ticket of the given type that matches the given context. To match context
304 * the ticket must
305 * contain all the same keys at the given context and the values must be equal with the exception of case
306 *
307 * @param ticketTypeName - Name of the ticket type to match
308 * @param matchContext - Map on context parameters to match on
309 * @return true if a ticket was found in the UserSession that matches the request, false if one was not found
310 */
311 public boolean hasMatchingSessionTicket(String ticketTypeName, Map<String, String> matchContext) {
312 boolean hasTicket = false;
313
314 for (SessionTicket ticket : getAllSessionTicketsByType(ticketTypeName)) {
315 Map<String, String> ticketContext = ticket.getTicketContext();
316
317 boolean keySetMatch = ticketContext.keySet().equals(matchContext.keySet());
318 if (keySetMatch) {
319 boolean valuesMatch = true;
320 for (String contextKey : ticketContext.keySet()) {
321 String ticketValue = ticketContext.get(contextKey);
322 String matchValue = matchContext.get(contextKey);
323 if (!StringUtils.equalsIgnoreCase(ticketValue, matchValue)) {
324 valuesMatch = false;
325 }
326 }
327
328 if (valuesMatch) {
329 hasTicket = true;
330 break;
331 }
332 }
333 }
334
335 return hasTicket;
336 }
337
338 /**
339 * retrieves an unmodifiable view of the objectMap.
340 */
341 public Map<String, Object> getObjectMap() {
342 return Collections.unmodifiableMap(this.objectMap);
343 }
344
345 /**
346 * clear the objectMap
347 */
348 public void clearObjectMap() {
349 this.objectMap = Collections.synchronizedMap(new HashMap<String,Object>());
350 }
351 }