View Javadoc
1   package com.randomnoun.common.security.impl;
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.*;
9   
10  import org.apache.log4j.Logger;
11  import org.springframework.dao.DataIntegrityViolationException;
12  import org.springframework.jdbc.core.*;
13  
14  import com.randomnoun.common.CamelCaser;
15  import com.randomnoun.common.Struct;
16  import com.randomnoun.common.Text;
17  import com.randomnoun.common.jexl.sql.SqlGenerator;
18  import com.randomnoun.common.security.Permission;
19  import com.randomnoun.common.security.SecurityContext;
20  import com.randomnoun.common.security.SecurityLoader;
21  import com.randomnoun.common.security.User;
22  import com.randomnoun.common.security.impl.ResourceCriteriaImpl;
23  import com.randomnoun.common.security.impl.SpringSecurityLoaderImpl;
24  import com.randomnoun.common.spring.StringRowMapper;
25  
26  
27  /**
28   * An implementation of the {@link com.randomnoun.common.security.SecurityLoader}
29   * class, using the Spring framework to populate the SecurityContext from a JDBC
30   * datasource.
31   * 
32   * <p>This security context used to optionally take a customerId (used to partition
33   * users across separate SaaS contexts), or an applicationId (used to partition
34   * permissions across separate software products). If not defined, then these 
35   * columns did not need to be present in the database. This functionality
36   * has been deprecated.
37   * 
38   * <p>I think we had String userids at one point as well, so look out for that.
39   *
40   * <p>This class has a number of initialisation properties that are specific
41   * to this class (in addition to those initialisation properties that are
42   * set by the SecurityContext itself):
43   *
44   * <ul>
45   * <li> {@link #INIT_JDBCTEMPLATE} - The Spring JdbcTemplate class used to retrieve
46   *   information from a database.
47   * <li> {@link #INIT_DATABASE_VENDOR} - Set to one of the SqlGenerator.DATABASE_* constants,
48   *   which specifies what syntax of SQL to use (DB2, Oracle or SqlServer).
49   * </ul>
50   * 
51   * @author knoxg
52   */
53  public class SpringSecurityLoaderImpl
54  	implements SecurityLoader
55  {
56  	
57  	/** Logger for this class */
58  	public static final Logger logger = Logger.getLogger(SpringSecurityLoaderImpl.class);
59  
60  	/** Properties used in this loader */
61  	private Map<String, Object> properties = null;
62      
63  	/** Used as parameter to {@link #convertPermissionList(List, int)} method */
64  	private static final int PERMISSION_USER = 1;
65  	/** Used as parameter to {@link #convertPermissionList(List, int)} method */
66  	private static final int PERMISSION_ROLE = 2;
67  	/** Used as parameter to {@link #convertPermissionList(List, int)} method */
68  	private static final int PERMISSION_NONE = 3;
69      
70  	/** Initialisation property key to set JdbcTemplate. */
71  	public final static String INIT_JDBCTEMPLATE = "jdbcTemplate";
72  
73  	/* * Initialisation property key to set the username mask. */
74  	// public final static String INIT_USERNAME_MASK = "usernameMask";
75  
76  	/** Database vendor for generated SQL. Should be one of the SqlGenerator.DB_* constants */
77  	public final static String INIT_DATABASE_VENDOR = "databaseVendor";
78  	
79  	/** Boolean object version of SecurityContext.INIT_CASE_INSENSITIVE string; set to
80  	 * false if missing */
81  	public final static String INIT_CASE_INSENSITIVE_OBJ = "caseInsensitiveObj";
82      
83  	/** Column renamer for the shouty ROLETABLE table */
84  	public final CamelCaser roleCamelCaser = new CamelCaser("roleId,roleName,description");
85      
86  	/** Column renamer for the USERS table */
87  	public final CamelCaser userCamelCaser = new CamelCaser("userId,name");
88      
89  	/** Column renamer for the PERMISSION table */
90  	public final CamelCaser permissionCamelCaser = new CamelCaser("roleName,userId,activityName,resourceName,resourceCriteria");
91      
92  	/** Column renamer for the SECURITYAUDITS table */    
93  	public final CamelCaser auditCamelCaser = new CamelCaser("userId,auditTime,auditDescription,resourceCriteria,authorised,authoriserId,authoriseTime");
94      
95  
96  	// we used to have staging tables for changes to the security model, which then
97  	// had to be approved before they were transferred to the real security model. Remember that ? 
98  	// 'four-eyes' security anyone ? 
99  	
100 	/** Return the name of the USERS table that this security loader will retrieve data from */
101 	private String userTable() {
102 		return "users";
103 	}
104     
105 	/** Return the name of the USERROLE table that this security loader will retrieve data from */
106 	private String userRoleTable() {
107 		return "userRole";
108 	}
109 
110 	/** Return the name of the ROLETABLE table that this security loader will retrieve data from */
111 	private String roleTable() {
112 		return "roleTable";
113 	}
114 
115 	/** Return the name of the SECURITYTABLE table that this security loader will retrieve data from */
116 	private String securityTable() {
117 		return "securityTable";
118 	}
119 
120 	/*
121 	private String roleTableSequence() {
122 		return "SEQ_ROLETABLE";
123 	}
124 	
125     
126 	private boolean isAuditEnabled() {
127 		Boolean enabled = (Boolean) properties.get(INIT_AUDIT_ENABLED);
128 		if (enabled==null) {
129 			return Boolean.TRUE;
130 		}
131 		return enabled;
132 	}
133 	
134 	/ * * Return the username to be used to audit any security operations performed by this security loader  * /
135 	private String auditUsername() {
136 		String auditUser = (String) properties.get(INIT_AUDIT_USERNAME);
137 		if (auditUser==null) {
138 			throw new IllegalStateException("Audit user required for all mutable security context operations");            
139 		}
140 		return auditUser;
141 	}
142 	*/
143 
144 	/** Retrieve the database vendor from the security loaders properties map.
145 	 * @return the database vendor */
146 	private String getDatabaseVendor() {
147 		return (String) properties.get(INIT_DATABASE_VENDOR);
148 	}
149 	
150 	
151 	/** Returns true if this security context is case-insensitive, false otherwise
152 	 * 
153 	 * @return true if this security context is case-insensitive, false otherwise
154 	 */
155 	private boolean getCaseInsensitive() {
156 		// @TODO: cache this
157 		return ((Boolean) properties.get(INIT_CASE_INSENSITIVE_OBJ)).booleanValue();
158 	}
159 	
160 	/** Return the sql for a string comparison for a username field, taking
161 	 * case sensitivity into account.
162 	 * 
163 	 * @param lhs expression to lowercase (if required) 
164 	 *
165 	 * @return
166 	 */
167 	private String lowerSql(String lhs) {
168 		if (getCaseInsensitive()) {
169 			String vendor = getDatabaseVendor();
170 			if (vendor.equals(SqlGenerator.DATABASE_DB2)) {
171 				return "LOWER(" + lhs + ")";
172 			} else if (vendor.equals(SqlGenerator.DATABASE_ORACLE)) {
173 				return "LOWER(" + lhs + ")";
174 			} else if (vendor.equals(SqlGenerator.DATABASE_SQLSERVER)) {
175 				return "LOWER(" + lhs + ")";
176 			} else if (vendor.equals(SqlGenerator.DATABASE_MYSQL)) {
177 				return "LOWER(" + lhs + ")";
178 			} else {
179 				throw new IllegalStateException("Case-insensitivity security contexts" +
180 				  " not supported for database type '" + vendor + "'");
181 			}
182 		} else {
183 			return lhs;
184 		}
185 	}
186 	
187 	/** Converts a value to lowercase, but only if case insensitivity is required */
188 	private String lower(String value) {
189 		if (getCaseInsensitive()) {
190 			return value.toLowerCase();
191 		} else {
192 			return value;
193 		}
194 	}
195 	
196 	/** Converts a long into an object suitable to be passed to the database
197 	 * as a roleId or permissionId. 
198 	 * 
199 	 * @param var object to convert
200 	 * 
201 	 * @return a Long representation of the object (or Integer for JET DBs)
202 	 */
203 	private Object toSequenceType(long var) {
204 		String vendor = getDatabaseVendor();
205 		if (vendor.equals(SqlGenerator.DATABASE_JET)) {
206 			return new Integer((int) var);
207 		} else {
208 			return new Long(var);
209 		}
210 	}
211     
212 	/** Initialise this loader.
213 	 *
214 	 * <p>The properties Map passed into this method must contain the following
215 	 * attributes.
216 	 *
217 	 * <attributes>
218 	 *   jdbcTemplate - a JdbcTemplate object connected to a datasource
219 	 *   databaseVendor - one of the SqlGenerator.DATABASE_* constants, defining what 
220 	 *     syntax of SQL to generate from this class.
221 	 * </attributes>
222 	 *
223 	 * @see com.randomnoun.common.security.SecurityLoader#initialise(java.util.Map)
224 	 */
225 	public void initialise(Map<String, Object> properties)
226 	{
227 		this.properties = properties;
228 		//String tableSuffix = (String) properties.get(INIT_TABLE_SUFFIX);
229 		//if (tableSuffix == null) { throw new NullPointerException("null INIT_TABLE_SUFFIX"); }
230 		if (properties.get(INIT_JDBCTEMPLATE)==null) { throw new NullPointerException("null INIT_JDBCTEMPLATE"); }
231 		if (properties.get(INIT_DATABASE_VENDOR)==null) { throw new NullPointerException("null INIT_DATABASE_VENDOR"); }
232 		String vendor = (String) properties.get(INIT_DATABASE_VENDOR);
233 		if (!(vendor.equals(SqlGenerator.DATABASE_DB2) ||
234 		  vendor.equals(SqlGenerator.DATABASE_ORACLE) ||
235 		  vendor.equals(SqlGenerator.DATABASE_SQLSERVER) ||
236 		  vendor.equals(SqlGenerator.DATABASE_MYSQL) ||
237 		  vendor.equals(SqlGenerator.DATABASE_JET))) {
238 			throw new IllegalArgumentException("Invalid INIT_DATABASE_VENDOR property '" + vendor + "'");
239 		}
240 
241 		// '' should only be allowed when staging contexts are disabled
242 		/*
243 		if (!(tableSuffix.equals("_WORK") || tableSuffix.equals("_LIVE") ||
244 			tableSuffix.equals("")))
245 		{
246 			throw new IllegalArgumentException("INIT_TABLE_SUFFIX must be set to '', '_WORK' or '_LIVE'");
247 		}
248 		*/
249         
250 		String caseInsensitive = (String) properties.get(SecurityContext.INIT_CASE_INSENSITIVE);
251 		if (Text.isBlank(caseInsensitive)) {
252 			caseInsensitive = "false";
253 		}
254 		properties.put(INIT_CASE_INSENSITIVE_OBJ, Boolean.valueOf(caseInsensitive));
255 		
256 		/*
257 		it's still OK to call read-only methods on the staging security context without an audit user  
258          
259 		if (tableSuffix.equals("_WORK") && properties.get(INIT_AUDIT_USERNAME)==null) {
260 			throw new IllegalArgumentException(
261 			  "Must include audit username when operating on staging security context");
262 		}*/
263         
264 	}
265 
266 	/** Load all role permissions.
267 	 *
268 	 * {@inheritDoc}
269 	 *
270 	 * @return A List of Permission objects for all roles in the current application. Does
271 	 * not return Permissions that are not explicitly associated with a role in the security table.
272 	 *
273 	 * @throws IOException if an error occured loading from the database. This IOException
274 	 *   will always contain a spring DataAccessException which can be accessed in its .getCause()
275 	 *   method.
276 	 *
277 	 * @see com.randomnoun.common.security.SecurityLoader#loadAllRolePermissions()
278 	 */
279 	public List<Permission> loadAllRolePermissions()
280 		throws IOException
281 	{
282 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
283 		String loadAllRolePermissionsSql = 
284 		  "SELECT roleName, activityName, resourceName, resourceCriteria " +
285 		  "FROM " + roleTable() + ", " + securityTable() + ", permission, resources " + 
286 		  "WHERE " +
287 		  " (" + securityTable() + ".roleId = " + roleTable() + ".roleId) " +
288 		  " AND " + "(" + securityTable() + ".permissionId = permission.permissionId) " +
289 		  " AND " + "(permission.resourceId = resources.resourceId)";
290 		List<Object> sqlParams = new ArrayList<Object>(2);  
291 		List<Map<String, Object>> list = jt.query(loadAllRolePermissionsSql,
292 		  sqlParams.toArray(),
293 		  new ColumnMapRowMapper());
294 		if (logger.isDebugEnabled()) {
295 			logger.debug(Struct.structuredListToString("loadAllRolePermissions", list));
296 		}
297 		permissionCamelCaser.renameList(list);
298 		return convertPermissionList(list, PERMISSION_ROLE);
299 	}
300 
301 	/** Retrieve per-user permission objects.
302 	 *
303 	 * {@inheritDoc}
304 	 *
305 	 * @throws IOException if an error occured loading from the database. This IOException
306 	 *   will always contain a spring DataAccessException which can be accessed in its .getCause()
307 	 *   method.
308 	 *
309 	 * @see com.randomnoun.common.security.SecurityLoader#loadUserPermission()
310 	 */
311 	public List<Permission> loadUserPermissions(User user)
312 		throws IOException
313 	{
314 		JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
315         
316 		String sqlPermissions = 
317 		  "SELECT activityName, resourceName, resourceCriteria " +
318 		  "FROM " + securityTable() + ", permission, resources " + 
319 		  "WHERE " +
320 		  " " + securityTable() + ".roleId IS NULL " +
321 		  " AND (" + lowerSql(securityTable() + ".userId") + " = ?) " +
322 		  " AND (" + securityTable() + ".permissionId = permission.permissionId) " +
323 		  " AND (permission.resourceId = resources.resourceId) ORDER BY resourceName, activityName";
324 		List<Object> sqlParams = new ArrayList<Object>(2);  
325 		sqlParams.add(lower(user.getUsername()));
326 		List<Map<String, Object>> list = jt.query(sqlPermissions, sqlParams.toArray(), new ColumnMapRowMapper());
327 		
328 		if (logger.isDebugEnabled()) {
329 		  logger.debug(Struct.structuredListToString("loadAllUserPermissions [2]", list));
330 		}
331 		permissionCamelCaser.renameList(list);
332 		return convertPermissionList(list, PERMISSION_USER);                
333 	}
334     
335 
336 	/** Retrieve a list of roles applied to a particular user
337 	 *  for the current application context.
338 	 *
339 	 * @return List of roles, represented as Strings
340 	 *
341 	 * @see com.randomnoun.common.security.SecurityLoader#loadRolesForUser()
342 	 */
343 	public List<String> loadUserRoles(User user)
344 	{
345 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
346 		String sql = "SELECT roleName " + 
347 		  " FROM " + roleTable() + "," + userRoleTable() + 		  
348 		  " WHERE " +
349 		  roleTable() + ".roleId = " + userRoleTable() + ".roleId " +
350 		  " AND " + lowerSql(userRoleTable() + ".userId") + " = ?";
351 		logger.debug("loadRolesForUser: " + sql + "; " + user.getUsername());
352 		List<Object> sqlParams = new ArrayList<Object>(3);
353 		sqlParams.add(lower(user.getUsername()));		  
354 		List<String> list = jt.query(sql, sqlParams.toArray(), new StringRowMapper());
355 		return list;
356 	}
357 
358 
359 	/**
360 	 * Return List of Permission associated with a particular role
361 	 * 
362 	 * @param role
363 	 * @return A List of Permission objects that apply to that role
364 	 */    
365 	public List<Permission> loadRolePermissions(String role)       
366 	{
367 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
368 		long roleId = findRoleIdByName(role);
369 		String sql = 
370 		  "SELECT roleName, activityName, resourceName, resourceCriteria " +
371 		  "FROM " + roleTable() + ", " + securityTable() + ", permission, resources " + 
372 		  "WHERE " + 
373 		  " (" + securityTable() + ".roleId = ?) " +
374 		  " AND (" + roleTable() + ".roleId = " + securityTable() + ".roleId) " +
375 		  " AND (" + securityTable() + ".permissionId = permission.permissionId) " +
376 		  " AND (permission.resourceId = resources.resourceId) " +
377 		  " ORDER BY resourceName, activityName";
378 		List<Object> sqlParams = new ArrayList<Object>(2);
379 		sqlParams.add(toSequenceType(roleId));
380 		List<Map<String, Object>> list = jt.query(sql, sqlParams.toArray(), new ColumnMapRowMapper());
381 		permissionCamelCaser.renameList(list);
382 		return convertPermissionList(list, PERMISSION_ROLE);
383 	}
384 
385 	/**
386 	 * Return List of Permissions containing permissions contained for all roles
387 	 * for a particular user.
388 	 * 
389 	 * <p>Note that if a user contains multiple roles that have permissions that apply to
390 	 * the same activity/resource combinations, then that will be reflected
391 	 * in the returned list. 
392 	 * 
393 	 * @param userid Name of user we are interested in.
394 	 * @return A List of Maps 
395 	 */
396 	public List<Permission> loadUserRolePermissions(User user)       
397 	{                    
398 		JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
399 		String sql ="SELECT activityName, resourceName, resourceCriteria " +
400 		  "FROM " + securityTable() + ", " + roleTable() + ", permission, resources " + 
401 		  "WHERE (" + securityTable() + ".roleId IN (" +
402 			"SELECT " + userRoleTable() + ".roleId " +
403 			"FROM " + userRoleTable() + ", " + roleTable() + 
404 			" WHERE " + userRoleTable() + ".roleId = " + roleTable() + ".roleId " +
405 			" AND " + lowerSql("userId") + " = ?)) " +
406 			" AND (" + securityTable() + ".permissionId = permission.permissionId) " +
407 			" AND (permission.resourceId = resources.resourceId)";
408 		List<Object> sqlParams = new ArrayList<Object>(2);
409 		sqlParams.add(user.getUsername());
410 		List<Map<String, Object>> list = jt.query(sql, sqlParams.toArray(), new ColumnMapRowMapper());
411                 
412 		// take out duplicates
413 		// Can't use DISTINCT on queries that contain CLOBs. Goddamn oracle.
414 		ArrayList<Map<String, Object>> list2 = new ArrayList<Map<String, Object>>();
415 		for (int x = 0; x < list.size(); x++) {
416 			Map<String, Object> row = list.get(x);
417 			if (!list2.contains(row)) {
418 				list2.add(row);   
419 			}
420 		}
421 		permissionCamelCaser.renameList(list2);
422 		return convertPermissionList(list2, PERMISSION_NONE); // role perm here ?
423 		          
424 	}
425 
426 
427 	/**
428 	 * Return a List of all Permissions available to this application
429 	 * 
430 	 * @return a List of Permissions available to this application
431 	 */    
432 	public List<Permission> loadAllPermissions()       
433 	{
434 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
435 		String sql =
436 		  "SELECT activityName, resourceName" +
437 		  " FROM permission, resources " + 
438 		  " WHERE " +
439 		  " permission.resourceId = resources.resourceId " +
440 		  "ORDER BY resourceName, activityName";
441 		List<Object> sqlParams = new ArrayList<Object>(2);
442 		List<Map<String, Object>> list = jt.query(sql, sqlParams.toArray(), new ColumnMapRowMapper());
443 		permissionCamelCaser.renameList(list);
444 		return convertPermissionList(list, PERMISSION_NONE);
445 	}
446     
447 
448 
449 	/** Private method to convert a list of PERMISSION rows (as returned by Spring)
450 	 *  into Permission Objects.
451 	 *
452 	 * <p>On reflection, probably should have used a Spring RowMapper for this. Oh well. It works.
453 	 *
454 	 * @param list  The list to convert
455 	 * @return  A List of Permission objects
456 	 */
457 	private List<Permission> convertPermissionList(List<Map<String, Object>> list, int permissionType)
458 	{
459 		String resourceType;
460 		String expressionString;
461 		Permission permission;
462 		List<Permission> result = new ArrayList<Permission>(list.size());
463         
464 		for (Iterator<Map<String, Object>> i = list.iterator(); i.hasNext(); ) {
465 			Map<String, Object> map = i.next();
466 			resourceType = (String) map.get("resourceName");
467 			expressionString = (String) map.get("resourceCriteria");
468 			ResourceCriteriaImpl resourceCriteriaImpl = null;
469 			if (expressionString != null && !expressionString.equals("")) {
470 				try {
471 					resourceCriteriaImpl = new ResourceCriteriaImpl(expressionString);
472 				} catch (Exception ce) {
473 					throw new DataIntegrityViolationException(
474 						"Invalid criteria found in SECURITY.RESOURCECRITERIA: '" +
475 						expressionString + "'", ce);
476 				}
477 			}
478 			
479 			if (permissionType == PERMISSION_ROLE) {
480 				permission = new Permission((String)map.get("roleName"),
481 				  (String)map.get("activityName"), resourceType, resourceCriteriaImpl);
482 			} else if (permissionType == PERMISSION_USER) {
483 				User user = new User();
484 				user.setUsername((String) map.get("userId"));
485 				permission = new Permission( user,
486 				  (String)map.get("activityName"), resourceType, resourceCriteriaImpl);
487 			} else if (permissionType == PERMISSION_NONE) {
488 				permission = new Permission((String)map.get("activityName"), resourceType);
489 				
490 			} else {
491 				throw new IllegalArgumentException("Unknown permission type '" + permissionType + "'");
492 			}
493 			result.add(permission);
494 		}
495 		return result;
496 	}
497 
498 	// if you want to do this, subclass it
499 	public User loadUser(long userId) throws IOException {
500 		throw new IOException("loadUser() not implemented");
501 		
502 		/*
503 		// tempted to go through all these methods and change userId to an actual number rather than a varchar.
504 		// sounds fair to me.
505 		
506 		JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
507 		String sql = 
508 		  "SELECT " + userTable() + ".userId " + // so userId's a string is it ? terrific.
509 		  " FROM " + userTable();
510 		List<String> list = jt.query(sql, new StringRowMapper());
511 		List<User> result = new ArrayList<User>(list.size());
512 		for (Iterator i = list.iterator(); i.hasNext(); ) {
513 			String username = (String) i.next();
514 			User user = new User();
515 			user.setUsername(username);  // this is horrible, but it's consistent with what's in here at the moment.
516 			result.add(user);
517 		}
518 		return result;
519 		*/
520 		
521 	}
522 	
523 	/** Retrieve a list of users in the current application context.
524 	 *
525 	 * {@inheritDoc}
526 	 *
527 	 * @throws IOException if an error occured loading from the database. This IOException
528 	 *   will always contain a spring DataAccessException which can be accessed via
529 	 *   {@link java.io.Throwable#getCause} method.
530 	 *
531 	 * @see com.randomnoun.common.security.SecurityLoader#loadAllUsers()
532 	 */
533 	public List<User> loadAllUsers()
534 		throws IOException
535 	{
536 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
537 		String sql = 
538 		  "SELECT " + userTable() + ".userId " + 
539 		  " FROM " + userTable();
540 		List<String> list = jt.query(sql, new StringRowMapper());
541 		List<User> result = new ArrayList<User>(list.size());
542 		for (Iterator<String> i = list.iterator(); i.hasNext(); ) {
543 			String username = (String) i.next();
544 			User user = new User();
545 			user.setUsername(username);
546 			result.add(user);
547 		}
548 		return result;
549 	}
550 
551 	/** Retrieve a list of all the resources under security for the current application context.
552 	 *
553 	 * @return List of maps, each map represents resource
554 	 *
555 	 * @see com.randomnoun.common.security.SecurityLoader#loadAllResources()
556 	 */
557 	public List<String> loadAllResources() {
558 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
559 		String sql =
560 		  "SELECT resourceName " + 
561 		  "FROM resources ";
562 		List<Object> sqlParams = new ArrayList<Object>(2);
563 		List<String> list = jt.query(sql, sqlParams.toArray(), new StringRowMapper());
564 		return list;
565 	}
566 
567 
568 	/** Retrieve a list of all the activities that can be applied to resource
569 	 *  for the current application context.
570 	 *
571 	 * @return List of maps, each map represents an activity.
572 	 *
573 	 * @see com.randomnoun.common.security.SecurityLoader#loadAllActivities()
574 	 */
575 	public List<String> loadAllActivities(String resourceName)
576 	{
577 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
578 		String sql =
579 		  "SELECT activityName " + 
580 		  "FROM permission, resources " +
581 		  "WHERE " +
582 		  " resourceName = ? " +
583 		  " AND permission.resourceId = resources.resourceId ";
584 		List<Object> sqlParams = new ArrayList<Object>(3);
585 		sqlParams.add(resourceName);
586 		List<String> list = jt.query(sql, sqlParams.toArray(), new StringRowMapper());
587 		return list;
588 	}
589 
590 	/** Retrieve a list of all the roles that can be applied to a user
591 	 *  for the current application context.
592 	 *
593 	 * @return List of maps, each map represents a role.
594 	 *
595 	 * @see com.randomnoun.common.security.SecurityLoader#loadAllRoles()
596 	 */
597 	public List<String> loadAllRoles()
598 	{
599 		JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
600 		String sql = "SELECT roleName " +
601 		  " FROM " + roleTable();
602 		List<Object> sqlParams = new ArrayList<Object>(2);
603 		List<String> list = jt.query(sql, sqlParams.toArray(), new StringRowMapper());
604 		return list;
605 	}
606 
607 
608 	/**
609 	 * Returns List of maps, where each map represents the details of a particular role.
610 	 */
611 	public List<Map<String, Object>> loadAllRoleDetails()
612 	{
613 		logger.debug("SpringSecurityLoaderImpl.loadAllRoleDetails(): 1. Entering");
614 		JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
615 		String sql = 
616 		  "SELECT roleId, roleName, description" +
617 		  " FROM " + roleTable(); 
618 		List<Object> sqlParams = new ArrayList<Object>(2);
619 		List<Map<String,Object>> list = jt.queryForList(sql, sqlParams.toArray());
620 		roleCamelCaser.renameList(list);
621 		return list;
622 	}
623     
624 	/**
625 	 * Returns List of maps, where each map represents the details of a particular user.
626 	 */
627 	public List<Map<String, Object>> loadAllUserDetails()
628 	{
629 		JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
630 		String sql = "SELECT userId, name " +
631 		  " FROM " + userTable(); 
632 		List<Object> sqlParams = new ArrayList<Object>(1);
633 		List<Map<String,Object>> list = jt.queryForList(sql, sqlParams.toArray());
634 		userCamelCaser.renameList(list);
635 		return list;
636 	}
637 
638 	/**
639 	 * Returns the ROLEID of a role, given its name
640 	 *
641 	 * @param role Name of the role to find
642 	 *
643 	 */
644 	private long findRoleIdByName(String role)        
645 	{
646 		try {
647 			JdbcTemplate jt = (JdbcTemplate) properties.get("jdbcTemplate");
648 			logger.debug("findRoleIdByName('" + role + "') called");
649 			String tablename = roleTable();
650 			String sql =
651 			  "SELECT roleId " +
652 			  "FROM " + tablename + 
653 			  " WHERE roleName = ? ";
654 			List<Object> sqlParams = new ArrayList<Object>(3);
655 			sqlParams.add(role);
656 			long key = jt.queryForObject(sql, sqlParams.toArray(), Long.class);
657 			logger.debug("findRoleIdByName('" + role + "') returning " + key);
658 			return key;
659 		} catch (org.springframework.dao.IncorrectResultSizeDataAccessException irsdae) {
660 			throw (IllegalArgumentException) new IllegalArgumentException(
661 			  "Could not find role '" + role + "' in " + roleTable()).initCause(irsdae);
662 		}
663 	}
664     
665 
666 	/** Resets the security context. 
667 	 * 
668 	 * <p>This security context holds no state, so this method does nothing.
669 	 */
670 	public void resetSecurityContext() {
671 		// no action necessary
672 	}
673 
674 	public void saveUserRolesAndPermissions(User user, List<String> roles, List<Permission> userPermissions) throws IOException 
675 	{
676 		throw new UnsupportedOperationException("not implemented");
677 	}
678 
679 	public void saveRolePermissions(String role, List<Permission> rolePermissions)
680 		throws IOException 
681 	{
682 		throw new UnsupportedOperationException("not implemented");
683 	}
684 
685 
686 
687 }
688