001 /**
002 * Copyright 2005-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.krad;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.rice.core.api.config.property.ConfigContext;
020 import org.kuali.rice.core.api.exception.RiceRuntimeException;
021 import org.kuali.rice.kim.api.identity.Person;
022 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
023 import org.kuali.rice.krad.util.SessionTicket;
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027 import java.util.Collections;
028 import java.util.HashMap;
029 import java.util.List;
030 import java.util.Map;
031 import java.util.concurrent.atomic.AtomicInteger;
032
033 /**
034 * Holds info about the User Session
035 *
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038 public class UserSession implements Serializable {
039 private static final long serialVersionUID = 4532616762540067557L;
040
041 private Person person;
042 private Person backdoorUser;
043 private AtomicInteger nextObjectKey;
044 private Map<String, Object> objectMap;
045 private String kualiSessionId;
046
047 /**
048 * Returns the session id. The session id is a unique identifier for the session.
049 * @return the kualiSessionId
050 */
051 public String getKualiSessionId() {
052 return this.kualiSessionId;
053 }
054
055 /**
056 * Sets the session id.
057 * @param kualiSessionId the kualiSessionId to set
058 */
059 public void setKualiSessionId(String kualiSessionId) {
060 this.kualiSessionId = kualiSessionId;
061 }
062
063 /**
064 * Creates a user session for the principal specified in the parameter.
065 * Take in a netid, and construct the user from that.
066 *
067 * @param principalName
068 */
069 public UserSession(String principalName) {
070 initPerson(principalName);
071 this.nextObjectKey = new AtomicInteger(0);
072 this.objectMap = Collections.synchronizedMap(new HashMap<String,Object>());
073 }
074
075 /**
076 * Loads the Person object from KIM. Factored out for testability.
077 * @param principalName the principalName
078 */
079 protected void initPerson(String principalName) {
080 this.person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName);
081 if (this.person == null) {
082 throw new IllegalArgumentException(
083 "Failed to locate a principal with principal name '" + principalName + "'");
084 }
085 }
086
087 /**
088 * Returns the id of the current user.
089 * @return the principalId of the current user in the system, backdoor principalId if backdoor is set
090 */
091 public String getPrincipalId() {
092 if (backdoorUser != null) {
093 return backdoorUser.getPrincipalId();
094 }
095 return person.getPrincipalId();
096 }
097
098 /**
099 * 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 }