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.jdbc.core.*;
012
013import com.randomnoun.common.Text;
014import com.randomnoun.common.security.Permission;
015import com.randomnoun.common.security.SecurityAuthenticator;
016import com.randomnoun.common.security.User;
017import com.randomnoun.common.security.impl.SpringSecurityAuthenticatorImpl;
018
019// ok. the USERID column in the table is actually a string. 
020// presumably the actual User.userId is sourced from some other column.
021
022// this implementation appears to favour querying on the USERID String,
023// so bear that in mind as well. It also doesn't populate the actual User.userId,
024// so don't use that at all.
025
026/**
027 * See SpringSecurityLoaderImpl. Maybe.
028 *
029 * 
030 * @author knoxg
031 */
032public class SpringSecurityAuthenticatorImpl
033        implements SecurityAuthenticator
034{
035        
036        /** Logger for this class */
037        public static final Logger logger = Logger.getLogger(SpringSecurityAuthenticatorImpl.class);
038
039        /** Properties used in this loader */
040        private Map<String, Object> properties = null;
041    
042        public static String INIT_TABLENAME = "tableName";
043        public static String INIT_USERNAME_COLUMN = "usernameColumn";
044        public static String INIT_PASSWORD_COLUMN = "passwordColumn";
045        
046        /** Odd. */
047        public static String INIT_JDBCTEMPLATE = "jdbcTemplate";
048        
049        String tableName;
050        String usernameColumn;
051        String passwordColumn;
052        
053        /** Initialise this loader.
054         *
055         * @see com.randomnoun.common.security.SecurityLoader#initialise(java.util.Map)
056         */
057        public void initialise(Map<String, Object> properties)
058        {
059                this.properties = properties;
060                if (properties.get(INIT_JDBCTEMPLATE)==null) { throw new NullPointerException("null INIT_JDBCTEMPLATE"); }
061        
062                tableName = Text.strDefault((String) properties.get(INIT_TABLENAME), "users");
063                usernameColumn = Text.strDefault((String) properties.get(INIT_USERNAME_COLUMN), "userId");
064                passwordColumn = Text.strDefault((String) properties.get(INIT_PASSWORD_COLUMN), "password");
065        }
066
067        /** Authenticates a user. 
068         * 
069         */
070        public boolean authenticate(User user, String password)
071        {
072                // check that the password is not empty
073                if (password == null || password.equals("")) {  
074                        return false;
075                }
076                JdbcTemplate jt = (JdbcTemplate)properties.get("jdbcTemplate");
077                String sql = 
078                  "SELECT " + passwordColumn  +
079                  " FROM " + tableName +  
080                  " WHERE " + usernameColumn + " = ?";
081                List<Object> sqlParams = new ArrayList<Object>(2);
082                sqlParams.add(user.getUsername());
083                boolean authenticated = false;  
084                try {           
085                        // TODO hash this, then perform the comparison in a stored procedure, 
086                        // then move it all to LDAP or OpenID
087                        String databasePassword = (String) jt.queryForObject(sql, sqlParams.toArray(), String.class);
088                        authenticated = password.equals(databasePassword);
089                } catch (Exception ex) {
090                        logger.error("Error authenticating user", ex);
091                        authenticated = false;   
092                }
093                return authenticated;
094        }
095                
096        
097        /** Resets the security context. 
098         * 
099         * <p>This security context holds no state, so this method does nothing.
100         */
101        public void resetSecurityContext() {
102                // no action necessary
103        }
104
105        public void saveUserRolesAndPermissions(User user, List<String> roles, List<Permission> userPermissions) throws IOException 
106        {
107                throw new UnsupportedOperationException("not implemented");
108        }
109
110        public void saveRolePermissions(String role, List<Permission> rolePermissions)
111                throws IOException 
112        {
113                throw new UnsupportedOperationException("not implemented");
114        }
115
116}
117