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