001package com.randomnoun.common.security.impl;
002
003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
005 */
006
007import java.io.IOException;
008import java.util.*;
009
010import org.apache.log4j.Logger;
011import org.springframework.dao.DataIntegrityViolationException;
012import org.springframework.jdbc.core.*;
013
014import com.randomnoun.common.CamelCaser;
015import com.randomnoun.common.Struct;
016import com.randomnoun.common.Text;
017import com.randomnoun.common.jexl.sql.SqlGenerator;
018import com.randomnoun.common.security.Permission;
019import com.randomnoun.common.security.SecurityContext;
020import com.randomnoun.common.security.SecurityLoader;
021import com.randomnoun.common.security.User;
022import com.randomnoun.common.security.impl.ResourceCriteriaImpl;
023import com.randomnoun.common.security.impl.SpringSecurityLoaderImpl;
024import com.randomnoun.common.spring.StringRowMapper;
025
026
027/**
028 * An implementation of the {@link com.randomnoun.common.security.SecurityLoader}
029 * class, using the Spring framework to populate the SecurityContext from a JDBC
030 * datasource.
031 * 
032 * <p>This security context used to optionally take a customerId (used to partition
033 * users across separate SaaS contexts), or an applicationId (used to partition
034 * permissions across separate software products). If not defined, then these 
035 * columns did not need to be present in the database. This functionality
036 * has been deprecated.
037 * 
038 * <p>I think we had String userids at one point as well, so look out for that.
039 *
040 * <p>This class has a number of initialisation properties that are specific
041 * to this class (in addition to those initialisation properties that are
042 * set by the SecurityContext itself):
043 *
044 * <ul>
045 * <li> {@link #INIT_JDBCTEMPLATE} - The Spring JdbcTemplate class used to retrieve
046 *   information from a database.
047 * <li> {@link #INIT_DATABASE_VENDOR} - Set to one of the SqlGenerator.DATABASE_* constants,
048 *   which specifies what syntax of SQL to use (DB2, Oracle or SqlServer).
049 * </ul>
050 * 
051 * @author knoxg
052 */
053public class SpringSecurityLoaderImpl
054        implements SecurityLoader
055{
056        
057        /** Logger for this class */
058        public static final Logger logger = Logger.getLogger(SpringSecurityLoaderImpl.class);
059
060        /** Properties used in this loader */
061        private Map<String, Object> properties = null;
062    
063        /** Used as parameter to {@link #convertPermissionList(List, int)} method */
064        private static final int PERMISSION_USER = 1;
065        /** Used as parameter to {@link #convertPermissionList(List, int)} method */
066        private static final int PERMISSION_ROLE = 2;
067        /** Used as parameter to {@link #convertPermissionList(List, int)} method */
068        private static final int PERMISSION_NONE = 3;
069    
070        /** Initialisation property key to set JdbcTemplate. */
071        public final static String INIT_JDBCTEMPLATE = "jdbcTemplate";
072
073        /* * Initialisation property key to set the username mask. */
074        // public final static String INIT_USERNAME_MASK = "usernameMask";
075
076        /** Database vendor for generated SQL. Should be one of the SqlGenerator.DB_* constants */
077        public final static String INIT_DATABASE_VENDOR = "databaseVendor";
078        
079        /** Boolean object version of SecurityContext.INIT_CASE_INSENSITIVE string; set to
080         * false if missing */
081        public final static String INIT_CASE_INSENSITIVE_OBJ = "caseInsensitiveObj";
082    
083        /** Column renamer for the shouty ROLETABLE table */
084        public final CamelCaser roleCamelCaser = new CamelCaser("roleId,roleName,description");
085    
086        /** Column renamer for the USERS table */
087        public final CamelCaser userCamelCaser = new CamelCaser("userId,name");
088    
089        /** Column renamer for the PERMISSION table */
090        public final CamelCaser permissionCamelCaser = new CamelCaser("roleName,userId,activityName,resourceName,resourceCriteria");
091    
092        /** Column renamer for the SECURITYAUDITS table */    
093        public final CamelCaser auditCamelCaser = new CamelCaser("userId,auditTime,auditDescription,resourceCriteria,authorised,authoriserId,authoriseTime");
094    
095
096        // we used to have staging tables for changes to the security model, which then
097        // had to be approved before they were transferred to the real security model. Remember that ? 
098        // 'four-eyes' security anyone ? 
099        
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