1 package com.randomnoun.common.security;
2
3 /* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
4 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
5 */
6
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13
14 import com.randomnoun.common.MRUCache;
15
16 /**
17 * This class manages users, roles, resources and permissions for an application.
18 *
19 * <p>Most of the code that adds/deletes/maintains these objects has been removed, that is
20 * now the responsibility of the security implementation code.
21 *
22 * <p>Methods to read user and permission data are delegated to the SecurityLoader, and
23 * methods that authenticate users are delegated to the SecurityAuthenticator.
24 *
25 * <p>This class now mostly acts as a cache for user and role data, and can perform
26 * simple and complex permission checks for users against resources.
27 *
28 * <p>The following properties can be passed to the SecurityContext during construction;
29 * property keys are defined as static public final Strings in this class.
30 *
31 * <ul>
32 * <li>INIT_CASE_INSENSITIVE - make the security cache case-insensitive, typically when interfacing with
33 * Active Directory. Defaults to false.
34 * <li>INIT_USER_CACHE_SIZE - maximum size of user cache
35 * <li>INIT_USER_CACHE_EXPIRY - expiry time of users from the user cache (in milliseconds). If this
36 * property is not set, user caching is disabled.
37 * </ul>
38 *
39 * <p>Additional properties may also be required based on the SecurityLoader implementation used.
40 *
41 * @author knoxg
42 *
43 * @see com.randomnoun.common.security.SecurityLoader
44 */
45 public class SecurityContext {
46
47 // /** The logger for this class */
48 // private static Logger logger = Logger.getLogger(SecurityContext.class.getName());
49
50 /** SecurityContext properties */
51 private Map<String, Object> properties = null;
52
53 /** An initialisation property key. See the class documentation for details. */
54 public static final String INIT_USER_CACHE_SIZE = "securityContext.userCacheSize";
55
56 /** An initialisation property key. See the class documentation for details. */
57 public static final String INIT_USER_CACHE_EXPIRY = "securityContext.userCacheExpiry";
58
59 /** An initialisation property key. See the class documentation for details. */
60 public static final String INIT_USERNAME_MASK = "securityContext.usernameMask";
61
62 /** An initialisation property key. See the class documentation for details. */
63 public static final String INIT_CASE_INSENSITIVE = "securityContext.caseInsensitive";
64
65 /** Maps rolenames to maps of permission names (in the form 'activity.resource')
66 * to Permission objects (possibly containing ResourceCriteria objects).
67 *
68 * If the security context is case-insensitive, then role names are lower-cased.
69 */
70 private Map<String, Map<String, Permission>> rolePermissionCache = null;
71
72 /** Maps usernames to maps of permission names (in the form 'activity.resource')
73 * to Permission objects (possibly containing ResourceCriteria objects).
74 *
75 * If the security context is case-insensitive, then usernames are lower-cased. */
76 private Map<User, Map<String, Permission>> userPermissionCache = null;
77
78 /** Maps user objects to list of roles.
79 *
80 * @TODO convert to HashSet ?
81 */
82 private Map<User, List<String>> userRoleCache = null;
83
84 /** Maps userIds to Users.
85 */
86 private Map<Long, User> userCache = null;
87
88 /** This security loader is used to retrieve information from a persistant data
89 * store for this context */
90 private SecurityLoader securityLoader = null;
91
92
93 /** The authenticator, if you want to actually check passwords */
94 private SecurityAuthenticator securityAuthenticator = null;
95
96 // should probably use guava caches for all of this now
97
98 /** This class is invoked by the MRUCache to recalculate values in the
99 * user permission cache that have expired, or where not in the cache to begin with.
100 */
101 private static class UserPermissionCallback
102 implements MRUCache.RetrievalCallback {
103
104 SecurityLoader loader;
105
106 /** Creates a new callback used to populate the
107 * user cache
108 */
109 public UserPermissionCallback(SecurityLoader loader) {
110 this.loader = loader;
111 }
112
113 /** this method is only called if the required value is not in the cache,
114 * or the value in the cache has expired.
115 *
116 * @param key The username of the User to return
117 */
118 public Object get(Object key) {
119 if (key==null) { throw new NullPointerException("null key"); }
120 if (!(key instanceof User)) {
121 throw new IllegalArgumentException("Expected user as User, found " + key.getClass().getName());
122 }
123
124 User user = (User) key;
125
126 Map<String, Permission> result = new HashMap<String, Permission>();
127 try {
128 List<Permission> permissions = loader.loadUserPermissions(user);
129 for (Iterator<Permission> i = permissions.iterator(); i.hasNext(); ) {
130 Permission perm = (Permission) i.next();
131 if (result.containsKey(perm.getActivity() + "." + perm.getResource())) {
132 throw new IllegalStateException("User '" + key + "' contains two versions of permission '" +
133 perm.getActivity() + "." + perm.getResource() + "'; please check the database");
134 }
135 result.put(perm.getActivity() + "." + perm.getResource(), perm);
136 }
137 } catch (IOException ioe) {
138 throw new RuntimeException("IOException reading user permissions", ioe);
139 }
140 return result;
141 }
142 }
143
144 /** This class is invoked by the MRUCache to recalculate values in the
145 * user permission cache that have expired, or where not in the cache to begin with.
146 */
147 private static class RolePermissionCallback
148 implements MRUCache.RetrievalCallback {
149
150 SecurityLoader loader;
151
152 /** Creates a new rowcount callback used to populate the
153 * user cache
154 */
155 public RolePermissionCallback(SecurityLoader loader) {
156 this.loader = loader;
157 }
158
159 /** this method is only called if the required value is not in the cache,
160 * or the value in the cache has expired.
161 *
162 * @param key The username of the User to return
163 */
164 public Object get(Object key) {
165 if (key==null) { throw new NullPointerException("null key"); }
166 if (!(key instanceof String)) {
167 throw new IllegalArgumentException("Expected roleName as string, found " + key.getClass().getName());
168 }
169 String rolename = (String) key;
170 Map<String, Permission> result = new HashMap<String, Permission>();
171 try {
172 List<Permission> permissions = loader.loadRolePermissions(rolename);
173 for (Iterator<Permission> i = permissions.iterator(); i.hasNext(); ) {
174 Permission perm = (Permission) i.next();
175 if (result.containsKey(perm.getActivity() + "." + perm.getResource())) {
176 throw new IllegalStateException("Role '" + key + "' contains two versions of permission '" +
177 perm.getActivity() + "." + perm.getResource() + "'; please check the database");
178 }
179 result.put(perm.getActivity() + "." + perm.getResource(), perm);
180 }
181 } catch (IOException ioe) {
182 throw new RuntimeException("IOException reading role permissions", ioe);
183 }
184 return result;
185 }
186 }
187
188
189 /** This class is invoked by the MRUCache to recalculate values in the
190 * user role cache that have expired, or where not in the cache to begin with.
191 */
192 private static class UserRoleCallback
193 implements MRUCache.RetrievalCallback {
194
195 SecurityLoader loader;
196
197 /** Creates a new rowcount callback used to populate the
198 * user cache
199 */
200 public UserRoleCallback(SecurityLoader loader) {
201 this.loader = loader;
202 }
203
204 /** this method is only called if the required value is not in the cache,
205 * or the value in the cache has expired.
206 *
207 * @param key The username of the User to return
208 */
209 public Object get(Object key) {
210 if (key==null) { throw new NullPointerException("null key"); }
211 if (!(key instanceof User)) {
212 throw new IllegalArgumentException("Expected user as User, found " + key.getClass().getName());
213 }
214
215 try {
216 // @TODO convert to HashSet ?
217 return loader.loadUserRoles((User) key);
218 } catch (IOException ioe) {
219 throw new RuntimeException("IOException reading user permissions", ioe);
220 }
221 }
222 }
223
224
225 /** This class is invoked by the MRUCache to load Users. It delegates to the Loader.
226 */
227 private static class UserCallback
228 implements MRUCache.RetrievalCallback {
229
230 SecurityLoader loader;
231
232 /** Creates a new rowcount callback used to populate the
233 * user cache
234 */
235 public UserCallback(SecurityLoader loader) {
236 this.loader = loader;
237 }
238
239 /** this method is only called if the required value is not in the cache,
240 * or the value in the cache has expired.
241 *
242 * @param key The username of the User to return
243 */
244 public Object get(Object key) {
245 if (key==null) { throw new NullPointerException("null key"); }
246 if (!(key instanceof Number)) {
247 throw new IllegalArgumentException("Expected numeric userId, found " + key.getClass().getName());
248 }
249
250 try {
251 // @TODO convert to HashSet ?
252 return loader.loadUser(((Number) key).longValue());
253 } catch (IOException ioe) {
254 throw new RuntimeException("IOException reading user", ioe);
255 }
256 }
257 }
258
259
260 /**
261 * Creates a new SecurityContext object.
262 *
263 * @param properties Initialisation properties for this SecurityContext, its
264 * SecurityLoader, and SecurityAuthenticator
265 *
266 * @throws IllegalStateException if the context is configured to preload,
267 * and it fails to do so.
268 */
269 public SecurityContext(Map<String, Object> properties, SecurityLoader securityLoader,
270 SecurityAuthenticator securityAuthenticator) {
271 this.properties = properties;
272 this.securityLoader = securityLoader;
273 this.securityLoader.initialise(properties);
274 this.securityAuthenticator = securityAuthenticator;
275 this.securityAuthenticator.initialise(properties);
276 resetSecurityContext();
277 }
278
279
280 /** Retrieve a list of permissions for this user, as Permission objects.
281 *
282 * @param user
283 * @return
284 * @throws IOException
285 */
286 public List<Permission> getUserPermissions(User user) throws IOException {
287 // @TODO should get this User out of our userCache, keyed by id
288
289 List<Permission> permissions = new ArrayList<Permission>();
290 Map<String, Permission> cachedPermissions = userPermissionCache.get(user);
291 for (Iterator<Permission> i = cachedPermissions.values().iterator(); i.hasNext(); ) {
292 permissions.add(i.next());
293 }
294 return permissions;
295 }
296
297
298 /** Returns a list of Permission objects that apply to the specified rolename.
299 *
300 * @param roleName the role name
301 * @return A List of Permission objects that apply to that role
302 */
303 public List<Permission> getRolePermissions(String roleName) {
304 // retrieve from cache
305 List<Permission> result = new ArrayList<Permission>();
306 if (roleName==null) {
307 throw new NullPointerException("null roleName");
308 } else {
309 Map<String, Permission> rolePermissions = rolePermissionCache.get(roleName);
310 if (rolePermissions == null) {
311 throw new IllegalArgumentException("Unknown role '" + roleName + "'");
312 }
313 for (Iterator<Permission> i = rolePermissions.values().iterator(); i.hasNext(); ) {
314 result.add(i.next());
315 }
316 }
317 return result;
318 }
319
320 /**
321 * Return a list of User objects representing all users contained in this
322 * security context. Permission information relating to that user is not
323 * populated unless the 'populatePermission' parameter is set to true.
324 *
325 * <p>The information returned by this function may be cached, depending
326 * on the initialisation properties of the security context.
327 *
328 * @return A List of Users.
329 */
330 public List<User> getAllUsers() throws IOException {
331 return securityLoader.loadAllUsers();
332 }
333
334 /**
335 * Return a List of all resources in this security context, identified
336 * by String.
337 *
338 * <p>The information returned by this function may be cached, depending
339 * on the initialisation properties of the security context.
340 *
341 * @return A List of resources
342 */
343 public List<String> getAllResources() throws IOException {
344 return securityLoader.loadAllResources();
345 }
346
347 /**
348 * Return a List of all Permissions in this security context.
349 *
350 * <p>The information returned by this function may be cached, depending
351 * on the initialisation properties of the security context.
352 *
353 * @return A List of resources
354 */
355 public List<Permission> getAllPermissions() throws IOException {
356 return securityLoader.loadAllPermissions();
357 }
358
359
360 /**
361 * Return a List of all activities in this security context for a given
362 * resource, identified by String.
363 *
364 * <p>The information returned by this function may be cached, depending
365 * on the initialisation properties of the security context.
366 *
367 * @param resourceName The resource we wish to retrieve activities for
368 *
369 * @return A List of activities.
370 *
371 * @throws SecurityException
372 */
373 public List<String> getAllActivities(String resourceName) throws IOException {
374 return securityLoader.loadAllActivities(resourceName);
375 }
376
377 /**
378 * Return a List of roles in this security context for the User, identified
379 * by String.
380 *
381 * <p>The information returned by this function may be cached, depending
382 * on the initialisation properties of the security context.
383 *
384 * @return A List of roles.
385 */
386 public List<String> getAllRoles()
387 throws IOException {
388 return securityLoader.loadAllRoles();
389 }
390
391 /**
392 * Return a List of all roles in this security context, identified
393 * by String.
394 *
395 * <p>The information returned by this function may be cached, depending
396 * on the initialisation properties of the security context.
397 *
398 * @return A List of roles.
399 */
400 public List<String> getUserRoles(User user)
401 throws IOException
402 {
403 List<String> cachedRoles = userRoleCache.get(user);
404 if (cachedRoles==null) {
405 throw new IllegalStateException("Unknown user '" + user + "'");
406 }
407 return cachedRoles;
408 }
409
410 /**
411 * Returns a detailed list of roles from the security context. Each role
412 * is defined as a Map with the following keys:
413 *
414 * <attributes>
415 * roleId - the numeric id for the role
416 * roleName - the name of the role for
417 * system - (Number) set to 1 if this role is read-only, 0 otherwise
418 * description - a description for the role
419 * </attributes>
420 *
421 * @return a list of roles, as described above
422 *
423 * @throws IOException
424 */
425 public List<Map<String, Object>> getAllRoleDetails()
426 throws IOException {
427 return securityLoader.loadAllRoleDetails();
428 }
429
430 /**
431 * Returns a detailed list of users from the security context. Each user
432 * is defined as a Map with the following keys:
433 *
434 * <attributes>
435 * userId - the login name for the user
436 * name - the full name of the user
437 * system - (Number) set to 1 if this role is read-only, 0 otherwise
438 * </attributes>
439 *
440 * @return a list of users, as described above
441 *
442 * @throws IOException
443 */
444 public List<Map<String, Object>> getAllUserDetails()
445 throws IOException {
446 return securityLoader.loadAllUserDetails();
447 }
448
449
450
451
452 /** Returns true if a user is allowed to perform the permission supplied. The permission
453 * is expressed in 'activity.resourceType' format, e.g. 'update.message'. No expression
454 * context is supplied; this method will not evaluate any conditional resource
455 * restrictions. This is useful in cases where the full resource context is not known,
456 * for example when a message is first created by a user.
457 *
458 * <p>In this case, the 'create.message' permission can be checked using this method
459 * before the user starts entering information, and 'create.message' can be
460 * checked with an expression context after the header fields have been populated.
461 *
462 * <p>If a permission is supplied that is not known by the application, this
463 * method will return false.
464 *
465 * @param user The user we are determining
466 * @param permission The permission we are testing for. Permissions are expressed in
467 * 'activity.resourceType' format.
468 * @return true if the permission is allowed, false is the permission is denied.
469 *
470 * @throws NullPointerException if either parameter to this method is null
471 * @throws IllegalArgumentException if the permission supplied is formatted incorrectly.
472 */
473 public boolean hasPermission(User user, String permission) {
474 return hasPermission(user, permission, null);
475 }
476
477 /**
478 * Returns true if a user is allowed to perform the permission supplied, with
479 * given resource context. If a permission is assigned to both the user
480 * and the role, then the user permission is evaluated first.
481 *
482 * @param user The user we are determining
483 * @param permission The permission we are testing for. Permissions are expressed in
484 * 'activity.resourceType' format.
485 * @param context The resource context used to evaluate against the resource expression
486 *
487 * @return true if the permission is allowed, false is the permission is denied.
488 *
489 * @throws NullPointerException if either parameter to this method is null
490 * @throws IllegalArgumentException if the permission supplied is formatted incorrectly.
491 */
492 public boolean hasPermission(User user, String permission, Map<String, Object> context) {
493 // @TODO should get this User out of our userCache, keyed by id
494 if (permission == null) { throw new NullPointerException("Null permission"); }
495 if (user == null) { throw new NullPointerException("Null user"); }
496
497 int pos = permission.indexOf('.');
498 if (pos == -1) {
499 throw new IllegalArgumentException("Illegal permission value '" + permission + "'");
500 }
501
502 // try per-user permissions...
503 Map<String, Permission> userPermissions = userPermissionCache.get(user);
504 if (userPermissions == null) {
505 // @TODO - load from DB ? should be handled by MRUCache
506 throw new IllegalStateException("Unknown user '" + user.getUsername() + "'");
507 } else {
508 Permission userPermission = (Permission) userPermissions.get(permission);
509 if (userPermission!=null) {
510 if (context == null) {
511 return true;
512 } else {
513 ResourceCriteria criteria = userPermission.getResourceCriteria();
514 if (criteria == null || criteria.evaluate(context)) {
515 return true;
516 }
517 }
518 }
519 }
520
521 // then try per-role permissions ...
522 List<String> roles = userRoleCache.get(user);
523 if (roles == null) {
524 // @TODO - load from DB ? should be handled by MRUCache
525 throw new IllegalStateException("Unknown user '" + user.getUsername() + "'");
526 } else {
527 for (Iterator<String> i = roles.iterator(); i.hasNext(); ) {
528 String rolename = (String) i.next();
529 Map<String, Permission> rolePermissions = rolePermissionCache.get(rolename);
530 if (rolePermissions == null) {
531 // @TODO - load from DB ? should be handled by MRUCache
532 throw new IllegalStateException("Unknown role '" + rolename + "'");
533 } else {
534 // this is a strange data structure
535 Permission rolePermission = (Permission) rolePermissions.get(permission);
536 if (rolePermission!=null) {
537 if (context == null) {
538 return true;
539 } else {
540 ResourceCriteria criteria = rolePermission.getResourceCriteria();
541 if (criteria == null || criteria.evaluate(context)) {
542 return true;
543 }
544 }
545 }
546 }
547 }
548 }
549
550 return false;
551 }
552
553 /**
554 * Returns the Permission object for a specific user/permission combination, or null
555 * if this permission is not granted. This method will not search the user's
556 * role-based permissions.
557 *
558 * @param user The user we are determining
559 * @param permission The permission we are testing for. Permissions are expressed in
560 * 'activity.resourceType' format.
561 *
562 * @return a permission object.
563 *
564 * @throws NullPointerException if either parameter to this method is null
565 * @throws IllegalArgumentException if the permission supplied is formatted incorrectly.
566 */
567 public Permission getPermission(User user, String permission) {
568 // @TODO should get this User out of our userCache, keyed by id
569 if (permission == null) { throw new NullPointerException("Null permission"); }
570 if (user == null) { throw new NullPointerException("Null user"); }
571
572 int pos = permission.indexOf('.');
573 if (pos == -1) {
574 throw new IllegalArgumentException("Illegal permission value '" + permission + "'");
575 }
576
577 // try per-user permissions...
578 Map<String, Permission> userPermissions = userPermissionCache.get(user);
579 if (userPermissions == null) {
580 // @TODO - load from DB ? should be handled by MRUCache
581 throw new IllegalStateException("Unknown user '" + user.getUsername() + "'");
582 } else {
583 Permission userPermission = (Permission) userPermissions.get(permission);
584 if (userPermission != null) {
585 return userPermission;
586 }
587 }
588
589 return null;
590 }
591
592
593 /**
594 * Returns a list of all Permission objects assigned to a user and all the
595 * roles that the user is a member of. This allows multiple permission conditions
596 * to be applied to a user, one for each role.
597 *
598 * @param user The user we are determining
599 * @param permission The permission we are testing for. Permissions are expressed in
600 * 'activity.resourceType' format.
601 *
602 * @return a List of Permission objects, or an empty list if the user
603 * (and none of their roles) contains this permission
604 *
605 * @throws NullPointerException if either parameter to this method is null
606 * @throws IllegalArgumentException if the permission supplied is formatted incorrectly.
607 */
608 public List<Permission> getPermissions(User user, String permission) {
609 // @TODO should get this User out of our userCache, keyed by id
610 if (permission == null) { throw new NullPointerException("Null permission"); }
611 if (user == null) { throw new NullPointerException("Null user"); }
612 List<Permission> result = new ArrayList<Permission>();
613
614 int pos = permission.indexOf('.');
615 if (pos == -1) {
616 throw new IllegalArgumentException("Illegal permission value '" + permission + "'");
617 }
618
619 // try per-user permissions...
620 Map<String, Permission> userPermissions = userPermissionCache.get(user);
621 if (userPermissions == null) {
622 // @TODO - load from DB ? should be handled by MRUCache
623 throw new IllegalStateException("Unknown user '" + user.getUsername() + "'");
624 } else {
625 Permission userPermission = (Permission) userPermissions.get(permission);
626 if (userPermission != null) {
627 result.add(userPermission);
628 }
629 }
630
631 // then try per-role permissions ...
632 List<String> roles = userRoleCache.get(user);
633 if (roles == null) {
634 throw new IllegalStateException("Unknown user '" + user.getUsername() + "'");
635 } else {
636 for (Iterator<String> i = roles.iterator(); i.hasNext(); ) {
637 String rolename = (String) i.next();
638 Map<String, Permission> rolePermissions = rolePermissionCache.get(rolename);
639 if (rolePermissions == null) {
640 throw new IllegalStateException("Unknown role '" + rolename + "'");
641 } else {
642 Permission rolePermission = (Permission) rolePermissions.get(permission);
643 if (rolePermission!=null) {
644 result.add(rolePermission);
645 }
646 }
647 }
648 }
649 return result;
650 }
651
652
653
654 /** Returns a string representation of this security context.
655 *
656 * @return a string representation of this security context.
657 */
658 public String toString() {
659 return super.toString() + (rolePermissionCache == null ? " - uninitialised" : ": " + rolePermissionCache.toString());
660 }
661
662 /** Clear all caches and re-initialises this security context (as defined
663 * in this instance's initial initialisation properties).
664 * This method also resets this security context's loader.
665 */
666 @SuppressWarnings("unchecked")
667 public void resetSecurityContext() {
668 // logger.debug("Security context properties: " + properties.toString());
669
670 int cacheSize = Integer.MAX_VALUE;
671 int cacheExpiry = Integer.MAX_VALUE;
672 if (properties.get(INIT_USER_CACHE_SIZE) != null && properties.get(INIT_USER_CACHE_EXPIRY) != null) {
673 cacheSize = Integer.parseInt((String) properties.get(INIT_USER_CACHE_SIZE));
674 cacheExpiry = Integer.parseInt((String) properties.get(INIT_USER_CACHE_EXPIRY));
675 }
676
677 UserPermissionCallback userPermissionCallback = new UserPermissionCallback(this.securityLoader);
678 userPermissionCache = new MRUCache(cacheSize, cacheExpiry, userPermissionCallback );
679
680 UserRoleCallback userRoleCallback = new UserRoleCallback (this.securityLoader);
681 userRoleCache = new MRUCache(cacheSize, cacheExpiry, userRoleCallback );
682
683 RolePermissionCallback rolePermissionCallback = new RolePermissionCallback (this.securityLoader);
684 rolePermissionCache = new MRUCache(cacheSize, cacheExpiry, rolePermissionCallback );
685
686 UserCallback userCallback = new UserCallback (this.securityLoader);
687 userCache = new MRUCache(cacheSize, cacheExpiry, userCallback );
688
689 try {
690 securityLoader.resetSecurityContext();
691 } catch (IOException ioe) {
692 throw (IllegalArgumentException) new IllegalArgumentException(
693 "Cannot initialise security Context").initCause(ioe);
694 }
695 }
696
697 /**
698 * Authenticate the supplied username and password with the authentication provider.
699 * Returns true if the username/password combination is valid, false otherwise
700 *
701 * <p>Some authentication providers may require more complex handshakes (e.g. TFA authentication)
702 * which are currently suported by setting flags in a subclassed User object.
703 * Possible mangling the password parameter as well. See the securityAuthenticator
704 * documentation for details.
705 *
706 * <p>The User object passed to this method may not have a valid userId assigned to it (this
707 * may be set by the authentication provider).
708 *
709 * @param user user
710 * @param password password
711 *
712 * @return true if the username/password combination is valid, false otherwise
713 *
714 * @throws IOException an exception occurred accessing the authentication provider.
715 */
716 public boolean authenticate(User user, String password)
717 throws IOException {
718 // @TODO should get this User out of our userCache, keyed by id
719 return securityAuthenticator.authenticate(user, password);
720 }
721
722 /** Returns a User, given their userId
723 *
724 * <p>This method will not load role or permissions data for the user.
725 *
726 * @param userId
727 * @return
728 */
729 public User getUser(long userId) {
730 // this cache has different User objects than the User objects in the role/user permission caches,
731 User user = (User) userCache.get(userId);
732 return user;
733 }
734
735
736 // why are these methods public ?
737 public List<Permission> loadRolePermissions(String role)
738 throws IOException {
739 return securityLoader.loadRolePermissions(role);
740 }
741
742 public List<Permission> loadUserRolePermissions(User user)
743 throws IOException {
744 return securityLoader.loadUserRolePermissions(user);
745 }
746
747
748 }