]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CC-740: Adding support for salting user passwords.
authorRichard Millet <remillet@gmail.com>
Fri, 16 Aug 2019 22:31:51 +0000 (15:31 -0700)
committerRichard Millet <remillet@gmail.com>
Sat, 31 Aug 2019 19:15:32 +0000 (12:15 -0700)
20 files changed:
services/JaxRsServiceProvider/src/main/webapp/WEB-INF/applicationContext-security.xml
services/account/pstore/pom.xml
services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/TokenStorageClient.java
services/account/service/src/main/java/org/collectionspace/services/account/storage/csidp/UserStorageClient.java
services/authentication/jaxb/src/main/resources/authentication_identity_provider.xsd
services/authentication/pstore/build.xml
services/authentication/pstore/pom.xml
services/authentication/pstore/src/main/resources/db/postgresql/authentication.sql
services/authentication/pstore/src/test/resources/META-INF/persistence.xml
services/authentication/service/pom.xml
services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceSaltSource.java [new file with mode: 0644]
services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceUser.java
services/authentication/service/src/main/java/org/collectionspace/authentication/realm/CSpaceRealm.java
services/authentication/service/src/main/java/org/collectionspace/authentication/realm/db/CSpaceDbRealm.java
services/authentication/service/src/main/java/org/collectionspace/authentication/spring/CSpaceUserDetailsService.java
services/authorization/pstore/build.xml
services/authorization/pstore/pom.xml
services/authorization/service/src/main/java/org/collectionspace/services/authorization/AuthZ.java
services/common/src/main/java/org/collectionspace/services/common/authorization_mgt/AuthorizationCommon.java
services/common/src/main/java/org/collectionspace/services/common/security/SecurityUtils.java

index bab5d159a5e8e9a9628443f706ab9c4379d2e034..a12b8e497f564e1f244209c1e1748e75f9c2209e 100644 (file)
@@ -90,6 +90,7 @@
 
     <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
         <property name="userDetailsService" ref="userDetailsService" />
+        <property name="saltSource" ref="saltSource"/>
         <property name="passwordEncoder">
             <bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
                 <constructor-arg value="256"/>
             </bean>
         </property>
     </bean>
+    
+    <bean id="saltSource" class="org.collectionspace.authentication.CSpaceSaltSource">
+        <property name="userPropertyToUse" value="salt" />
+    </bean>
 
     <bean id="userDetailsService" class="org.collectionspace.authentication.spring.CSpaceUserDetailsService">
         <constructor-arg>
                     <util:map>
                         <entry key="dsJndiName" value="CspaceDS" />
                         <entry key="principalsQuery" value="select passwd from users where username=?" />
+                        <entry key="saltQuery" value="select salt from users where username=?" />
                         <entry key="rolesQuery" value="select r.rolename from roles as r, accounts_roles as ar where ar.user_id=? and ar.role_id=r.csid" />
                         <entry key="tenantsQueryWithDisabled" value="select t.id, t.name from accounts_common as a, accounts_tenants as at, tenants as t where a.userid=? and a.csid = at.TENANTS_ACCOUNTS_COMMON_CSID and at.tenant_id = t.id order by t.id" />
                         <entry key="tenantsQueryNoDisabled" value="select t.id, t.name from accounts_common as a, accounts_tenants as at, tenants as t where a.userid=? and a.csid = at.TENANTS_ACCOUNTS_COMMON_CSID and at.tenant_id = t.id and NOT t.disabled order by t.id" />
index b54900e0f901f94fee981c3eeec7a41b2fe14cc8..6e8654a398e98d346e53c9d35193d508c591986b 100644 (file)
                        <artifactId>property-listener-injector</artifactId>
                </dependency>
                <!-- External dependencies -->
-               <dependency>
-                       <groupId>mysql</groupId>
-                       <artifactId>mysql-connector-java</artifactId>
-               </dependency>
                <dependency>
                        <groupId>org.postgresql</groupId>
                        <artifactId>postgresql</artifactId>
+                       <version>${postgres.driver.version}</version>                   
                </dependency>
                <!-- CollectionSpace dependencies -->
                <dependency>
                                                        </componentProperties>
                                                </configuration>
                                                <dependencies>
-                                                       <dependency>
-                                                               <groupId>mysql</groupId>
-                                                               <artifactId>mysql-connector-java</artifactId>
-                                                       </dependency>
                                                        <dependency>
                                                                <groupId>org.postgresql</groupId>
                                                                <artifactId>postgresql</artifactId>
+                                                               <version>${postgres.driver.version}</version>
                                                        </dependency>
                                                </dependencies>
                                        </plugin>
index 747ee40ef1ac8697f45a62dd2f749b73f4e74a8c..7a69d118abf58e42903b91faff9d22e9095edc61 100644 (file)
@@ -186,7 +186,7 @@ public class TokenStorageClient {
             throw new BadRequestException(e.getMessage());
         }
         String secEncPasswd = SecurityUtils.createPasswordHash(
-                userId, new String(password));
+                userId, new String(password), null);
         return secEncPasswd;
     }
 }
index b274c21bc2c645cad3b14515219d0b2125fc0ddc..a0b86daa6f9ced381165e631f76151f909baea66 100644 (file)
@@ -28,6 +28,8 @@
 package org.collectionspace.services.account.storage.csidp;
 
 import java.util.Date;
+import java.util.UUID;
+
 import javax.persistence.Query;
 
 import org.collectionspace.services.authentication.User;
@@ -61,7 +63,9 @@ public class UserStorageClient {
     public User create(String userId, byte[] password) throws Exception {
         User user = new User();
         user.setUsername(userId);
-        user.setPasswd(getEncPassword(userId, password));
+        String salt = UUID.randomUUID().toString();
+        user.setPasswd(getEncPassword(userId, password, salt));
+        user.setSalt(salt);
         user.setCreatedAtItem(new Date());
         return user;
     }
@@ -111,7 +115,7 @@ public class UserStorageClient {
             throws DocumentNotFoundException, Exception {
         User userFound = get(jpaTransactionContext, userId);
         if (userFound != null) {
-            userFound.setPasswd(getEncPassword(userId, password));
+            userFound.setPasswd(getEncPassword(userId, password, userFound.getSalt()));
             userFound.setUpdatedAtItem(new Date());
             if (logger.isDebugEnabled()) {
                 logger.debug("updated user=" + JaxbUtils.toString(userFound, User.class));
@@ -144,7 +148,7 @@ public class UserStorageClient {
         }
     }
 
-    private String getEncPassword(String userId, byte[] password) throws BadRequestException {
+    private String getEncPassword(String userId, byte[] password, String salt) throws BadRequestException {
         //jaxb unmarshaller already unmarshal xs:base64Binary, no need to b64 decode
         //byte[] bpass = Base64.decodeBase64(accountReceived.getPassword());
         try {
@@ -153,7 +157,7 @@ public class UserStorageClient {
             throw new BadRequestException(e.getMessage());
         }
         String secEncPasswd = SecurityUtils.createPasswordHash(
-                userId, new String(password));
+                userId, new String(password), salt);
         return secEncPasswd;
     }
 }
index 3ead8c19282917b2f9c077edbeba160ff4cc6db5..6971c27157ee24b7fc15630a7fbbfeb89c304f83 100644 (file)
                         </xs:appinfo>
                     </xs:annotation>
                 </xs:element>
+                <xs:element name="salt" type="xs:string" minOccurs="1" maxOccurs="1">
+                    <xs:annotation>
+                        <xs:appinfo>
+                            <hj:basic>
+                                <orm:column name="salt" length="128" nullable="false" default=""/>
+                            </hj:basic>
+                        </xs:appinfo>
+                    </xs:annotation>
+                </xs:element>
                 <xs:element name="createdAt" type="xs:dateTime">
                     <xs:annotation>
                         <xs:appinfo>
                         </xs:appinfo>
                     </xs:annotation>
                 </xs:element>
-
+                <xs:element name="lastLogin" type="xs:dateTime">
+                    <xs:annotation>
+                        <xs:appinfo>
+                            <hj:basic>
+                                <orm:column name="lastLogin" />
+                            </hj:basic>
+                        </xs:appinfo>
+                    </xs:annotation>
+                </xs:element>
             </xs:sequence>
         </xs:complexType>
     </xs:element>
index 44c6a13f60f87ef79922e12013f651bc58a8e861..3f472893b4381d5b05e744f083b90b0f71ebb233 100644 (file)
         <property name="src.hibernate.cfg" value="${basedir}/src/test/resources/hibernate.cfg.xml"/>
         <property name="dest.hibernate.cfg" value="${basedir}/target/test-classes/hibernate.cfg.xml"/>
         <delete file="${dest.hibernate.cfg}" verbose="true" />
-        <filter token="DB_CSPACE_URL" value="${db.jdbc.cspace.url}" />
+        <filter token="DB_CSPACE_URL" value="${db.jdbc.cspace.url.encoded}" />
         <filter token="DB_DRIVER_CLASS" value="${db.jdbc.driver.class}" />
         <filter token="DB_CSPACE_USER" value="${db.cspace.user}" />
         <filter token="DB_CSPACE_PASSWORD" value="${env.DB_CSPACE_PASSWORD}" /> <!-- double-sub from ${db.cspace.user.password} fails -->
index 5e26ecf5c90ad5da215659a62e99309a41c7d075..6451e5058764409279f0ded4294f9d02696e8370 100644 (file)
                             </componentProperties>
                         </configuration>
                         <dependencies>
-                            <dependency>
-                                <groupId>mysql</groupId>
-                                <artifactId>mysql-connector-java</artifactId>
-                            </dependency>
                                                        <dependency>
                                                                <groupId>org.postgresql</groupId>
                                                                <artifactId>postgresql</artifactId>
+                                                               <version>${postgres.driver.version}</version>
                                                        </dependency>
                          </dependencies>
                     </plugin>
index 4760478b5abce276bf46269d98cc2b463f166696..a8be95c9394cef65484ed33ad0e944029dbcff62 100644 (file)
@@ -1,7 +1,9 @@
 CREATE TABLE IF NOT EXISTS users (
   username VARCHAR(128) NOT NULL PRIMARY KEY,
   created_at TIMESTAMP NOT NULL,
+  lastLogin TIMESTAMP,
   passwd VARCHAR(128) NOT NULL,
+  salt VARCHAR(128)
   updated_at TIMESTAMP
 );
 
index 59673d1db1f8b75527796f5955451a3bb86d1e5d..2844198043b96983f0c62a86f9b0cf660223fc95 100644 (file)
@@ -3,6 +3,7 @@
 http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     <persistence-unit name="org.collectionspace.services.authentication">
         <class>org.collectionspace.services.authentication.User</class>
+        <class>org.collectionspace.services.authentication.Token</class>
         <properties>
             <property name="hibernate.ejb.cfgfile" value="hibernate.cfg.xml"/>
 
index efd814e575c4e4131470200b34f53fd6dfc43852..2fb839b037d7e22da79de3f892a33e12f579726a 100644 (file)
             <version>${spring.security.oauth2.version}</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+                       <groupId>org.postgresql</groupId>
+                       <artifactId>postgresql</artifactId>
+            <scope>provided</scope>
+               </dependency>
     </dependencies>
 
     <build>
diff --git a/services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceSaltSource.java b/services/authentication/service/src/main/java/org/collectionspace/authentication/CSpaceSaltSource.java
new file mode 100644 (file)
index 0000000..34c3471
--- /dev/null
@@ -0,0 +1,13 @@
+package org.collectionspace.authentication;
+
+import org.springframework.security.authentication.dao.ReflectionSaltSource;
+import org.springframework.security.core.userdetails.UserDetails;
+
+public class CSpaceSaltSource extends ReflectionSaltSource {
+
+       @Override
+       public Object getSalt(UserDetails user) {
+               return super.getSalt(user);
+       }
+
+}
index 8cdd002c657cf8eabe114ea73abfd534badc9aca..ed0931210a9be0daec2336acf88b9442c4b4f3cd 100644 (file)
@@ -20,6 +20,7 @@ public class CSpaceUser extends User {
 
     private Set<CSpaceTenant> tenants;
     private CSpaceTenant primaryTenant;
+    private String salt;
     
     /**
      * Creates a CSpaceUser with the given username, hashed password, associated
@@ -30,7 +31,7 @@ public class CSpaceUser extends User {
      * @param tenants the tenants associated with the user
      * @param authorities the authorities that have been granted to the user
      */
-    public CSpaceUser(String username, String password,
+    public CSpaceUser(String username, String password, String salt,
             Set<CSpaceTenant> tenants,
             Set<? extends GrantedAuthority> authorities) {
 
@@ -42,12 +43,13 @@ public class CSpaceUser extends User {
                 authorities);
 
         this.tenants = tenants;
+        this.salt = salt;
         
         if (!tenants.isEmpty()) {
             primaryTenant = tenants.iterator().next();
         }
     }
-
+    
     /**
      * Retrieves the tenants associated with the user.
      * 
@@ -66,4 +68,12 @@ public class CSpaceUser extends User {
         return primaryTenant;
     }
     
+    /**
+     * Returns a "salt" string to use when encrypting a user's password
+     * @return
+     */
+    public String getSalt() {
+       return salt != null ? salt : "";
+    }
+    
 }
index 0b55b88a06a3123f575553de1d7be31b6d2b9a4f..c70a14ccc5f6935f8ec05acaac79aabae930660a 100644 (file)
@@ -38,6 +38,14 @@ import org.collectionspace.authentication.CSpaceTenant;
  * Interface for the CollectionSpace realm.
  */
 public interface CSpaceRealm {
+       
+       /**
+        * Retrieves the "salt" used to encrypt the user's password
+        * @param username
+        * @return
+        * @throws AccountException
+        */
+       public String getSalt(String username) throws AccountException;
 
     /**
      * Retrieves the hashed password used to authenticate a user.
index 2b13bf7ebfffe1b2512179ea517d2a92f099ca33..62045711143b0b4903b4cabdc555f683d0b65cdf 100644 (file)
@@ -68,6 +68,7 @@ import javax.sql.DataSource;
 import org.collectionspace.authentication.AuthN;
 import org.collectionspace.authentication.CSpaceTenant;
 import org.collectionspace.authentication.realm.CSpaceRealm;
+import org.postgresql.util.PSQLState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,6 +81,7 @@ public class CSpaceDbRealm implements CSpaceRealm {
     
     private String datasourceName;
     private String principalsQuery;
+    private String saltQuery;
     private String rolesQuery;
     private String tenantsQueryNoDisabled;
     private String tenantsQueryWithDisabled;
@@ -140,6 +142,10 @@ public class CSpaceDbRealm implements CSpaceRealm {
         if (tmp != null) {
             principalsQuery = tmp.toString();
         }
+        tmp = options.get("saltQuery");
+        if (tmp != null) {
+               saltQuery = tmp.toString();
+        }
         tmp = options.get("rolesQuery");
         if (tmp != null) {
             rolesQuery = tmp.toString();
@@ -642,5 +648,68 @@ public class CSpaceDbRealm implements CSpaceRealm {
 
                return result;
        }
+
+       @Override
+       public String getSalt(String username) throws AccountException {
+        String salt = null;
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            conn = getConnection();
+            // Get the salt
+            if (logger.isDebugEnabled()) {
+                logger.debug("Executing query: " + saltQuery + ", with username: " + username);
+            }
+            ps = conn.prepareStatement(saltQuery);
+            ps.setString(1, username);
+            rs = ps.executeQuery();
+            if (rs.next() == false) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug(saltQuery + " returned no matches from db");
+                }
+                throw new AccountNotFoundException("No matching username found");
+            }
+
+            salt = rs.getString(1);
+        } catch (SQLException ex) {
+               // Assuming PostgreSQL
+            if (PSQLState.UNDEFINED_COLUMN.getState().equals(ex.getSQLState())) {
+               String msg = "'USERS' table is missing 'salt' column for password encyrption.  Assuming existing passwords are unsalted.";
+               logger.warn(msg);
+            } else {
+                AccountException ae = new AccountException("Authentication query failed: " + ex.getLocalizedMessage());
+                ae.initCause(ex);
+                throw ae;
+            }
+        } catch (AccountNotFoundException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            AccountException ae = new AccountException("Unknown Exception");
+            ae.initCause(ex);
+            throw ae;
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException ex) {
+                }
+            }
+        }
+        
+        return salt;
+    }
     
 }
index 5085d159090c6971141cbe89f7ba05bc7851df21..fba9868ffe0cfebb215284e838a595f600c4356c 100644 (file)
@@ -74,11 +74,13 @@ public class CSpaceUserDetailsService implements UserDetailsService {
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         String password = null;
+        String salt = null;
         Set<CSpaceTenant> tenants = null;
         Set<GrantedAuthority> grantedAuthorities = null;
         
         try {
             password = realm.getPassword(username);
+            salt = realm.getSalt(username);
             tenants = getTenants(username);
             grantedAuthorities = getAuthorities(username);
         }
@@ -89,12 +91,15 @@ public class CSpaceUserDetailsService implements UserDetailsService {
             throw new AuthenticationServiceException(e.getMessage(), e);
         }
         
-        return
+        CSpaceUser cspaceUser = 
             new CSpaceUser(
                 username,
                 password,
+                salt,
                 tenants,
                 grantedAuthorities);
+                
+        return cspaceUser;
     }
     
     protected Set<GrantedAuthority> getAuthorities(String username) throws AccountException {
index 1a599a2a3e9dad5c0e1296b88ac262b06d6f3949..ec73e8f9c229b21c29f4a708568b3b73c232625d 100644 (file)
         <property name="src.hibernate.cfg" value="${basedir}/src/test/resources/hibernate.cfg.xml"/>
         <property name="dest.hibernate.cfg" value="${basedir}/target/test-classes/hibernate.cfg.xml"/>
         <delete file="${dest.hibernate.cfg}" verbose="true" />
-        <filter token="DB_CSPACE_URL" value="${db.jdbc.cspace.url}" />
+        <filter token="DB_CSPACE_URL" value="${db.jdbc.cspace.url.encoded}" />
         <filter token="DB_DRIVER_CLASS" value="${db.jdbc.driver.class}" />
         <filter token="DB_CSPACE_USER" value="${db.cspace.user}" />
         <filter token="DB_CSPACE_PASSWORD" value="${env.DB_CSPACE_PASSWORD}" /> <!-- double-sub from ${db.cspace.user.password} fails -->
index 8557e668cba74ca1ab8f0942728e67cae240a26c..147e4117f6623f1081b8160a5e95f60f2d861d3e 100644 (file)
                             </componentProperties>
                         </configuration>
                         <dependencies>
-                            <dependency>
-                                <groupId>mysql</groupId>
-                                <artifactId>mysql-connector-java</artifactId>
-                            </dependency>
                                                        <dependency>
                                                                <groupId>org.postgresql</groupId>
                                                                <artifactId>postgresql</artifactId>
+                                                               <version>${postgres.driver.version}</version>
                                                        </dependency>
                          </dependencies>
                     </plugin>
index 016954d53a2b11957393d19bbe69babc025449a6..d37156b860ea10fbb1be53a0d3ed11063e5bcfb4 100644 (file)
@@ -277,7 +277,7 @@ public class AuthZ {
        
        HashSet<CSpaceTenant> tenantSet = new HashSet<CSpaceTenant>();
        tenantSet.add(tenant);
-       CSpaceUser principal = new CSpaceUser(user, password, tenantSet, grantedAuthorities);
+       CSpaceUser principal = new CSpaceUser(user, password, null, tenantSet, grantedAuthorities);
        
         Authentication authRequest = new UsernamePasswordAuthenticationToken(principal, password, grantedAuthorities);
         SecurityContextHolder.getContext().setAuthentication(authRequest);
index 66e3acfd56d39f8cb868e511f4768f4c65d72bfe..ed28f4766678eb556f94ca8d41e0e1ce65e83338 100644 (file)
@@ -142,8 +142,8 @@ public class AuthorizationCommon {
        final private static String QUERY_USERS_SQL = 
                "SELECT username FROM users WHERE username LIKE '"
                        +TENANT_ADMIN_ACCT_PREFIX+"%' OR username LIKE '"+TENANT_READER_ACCT_PREFIX+"%'";
-       final private static String INSERT_USER_SQL = 
-                       "INSERT INTO users (username,passwd, created_at) VALUES (?,?, now())";
+       final private static String INSERT_USER_SQL =
+                       "INSERT INTO users (username,passwd,salt, created_at) VALUES (?,?,?, now())";
        final private static String INSERT_ACCOUNT_SQL = 
                        "INSERT INTO accounts_common "
                                        + "(csid, email, userid, status, screen_name, metadata_protection, roles_protection, created_at) "
@@ -466,10 +466,12 @@ public class AuthorizationCommon {
                for(String tName : tenantInfo.values()) {
                        String adminAcctName = getDefaultAdminUserID(tName);
                        if(!usersInRepo.contains(adminAcctName)) {
+                               String salt = UUID.randomUUID().toString();
                                String secEncPasswd = SecurityUtils.createPasswordHash(
-                                               adminAcctName, DEFAULT_ADMIN_PASSWORD);
+                                               adminAcctName, DEFAULT_ADMIN_PASSWORD, salt);
                                pstmt.setString(1, adminAcctName);      // set username param
                                pstmt.setString(2, secEncPasswd);       // set passwd param
+                               pstmt.setString(3, salt);
                                if (logger.isDebugEnabled()) {
                                        logger.debug("createDefaultUsersAndAccounts adding user: "
                                                        +adminAcctName+" for tenant: "+tName);
@@ -483,10 +485,12 @@ public class AuthorizationCommon {
 
                        String readerAcctName =  getDefaultReaderUserID(tName);
                        if(!usersInRepo.contains(readerAcctName)) {
+                               String salt = UUID.randomUUID().toString();
                                String secEncPasswd = SecurityUtils.createPasswordHash(
-                                               readerAcctName, DEFAULT_READER_PASSWORD);
+                                               readerAcctName, DEFAULT_READER_PASSWORD, salt);
                                pstmt.setString(1, readerAcctName);     // set username param
                                pstmt.setString(2, secEncPasswd);       // set passwd param
+                               pstmt.setString(3, salt);
                                if (logger.isDebugEnabled()) {
                                        logger.debug("createDefaultUsersAndAccounts adding user: "
                                                        +readerAcctName+" for tenant: "+tName);
@@ -583,11 +587,13 @@ public class AuthorizationCommon {
                }
                rs.close();
                if(!foundTMgrUser) {
+                       String salt = UUID.randomUUID().toString();
                        pstmt = conn.prepareStatement(INSERT_USER_SQL); // create a statement
                        String secEncPasswd = SecurityUtils.createPasswordHash(
-                                       TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD);
+                                       TENANT_MANAGER_USER, DEFAULT_TENANT_MANAGER_PASSWORD, salt);
                        pstmt.setString(1, TENANT_MANAGER_USER);        // set username param
                        pstmt.setString(2, secEncPasswd);       // set passwd param
+                       pstmt.setString(3, salt);
                        if (logger.isDebugEnabled()) {
                                logger.debug("findOrCreateTenantManagerUserAndAccount adding tenant manager user: "
                                                +TENANT_MANAGER_USER);
index f45dd5a3971a5c41f12a2bf01c2ec050b4dffb6b..37d7c6cd3e6abd6891555b57b5a0f1c522d0bcf8 100644 (file)
@@ -44,11 +44,41 @@ import javax.ws.rs.core.UriInfo;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
+import org.springframework.security.authentication.encoding.BasePasswordEncoder;
 import org.jboss.crypto.digest.DigestCallback;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.security.Base64Encoder;
 import org.jboss.security.Base64Utils;
 
+/**
+ * Extends Spring Security's base class for encoding passwords.  We use only the
+ * mergePasswordAndSalt() method.
+ * @author remillet
+ *
+ */
+class CSpacePasswordEncoder extends BasePasswordEncoder {
+       public CSpacePasswordEncoder() {
+               //Do nothing
+       }
+
+       String mergePasswordAndSalt(String password, String salt) {
+               return this.mergePasswordAndSalt(password, salt, false);
+       }
+
+       @Override
+       public String encodePassword(String rawPass, Object salt) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+}
+
 /**
  *
  * @author 
@@ -65,7 +95,6 @@ public class SecurityUtils {
     public static final String RFC2617_ENCODING = "RFC2617";
     private static char MD5_HEX[] = "0123456789abcdef".toCharArray();
     
-
     /**
      * createPasswordHash creates password has using configured digest algorithm
      * and encoding
@@ -73,13 +102,14 @@ public class SecurityUtils {
      * @param password in cleartext
      * @return hashed password
      */
-    public static String createPasswordHash(String username, String password) {
+    public static String createPasswordHash(String username, String password, String salt) {
         //TODO: externalize digest algo and encoding
         return createPasswordHash("SHA-256", //digest algo
                 "base64", //encoding
                 null, //charset
                 username,
-                password);
+                password,
+                salt);
     }
 
     /**
@@ -311,26 +341,31 @@ public class SecurityUtils {
         return result;
     }
     
-    public static String createPasswordHash(String hashAlgorithm, String hashEncoding, String hashCharset, String username, String password)
+    public static String createPasswordHash(String hashAlgorithm, String hashEncoding, String hashCharset,
+               String username, String password, String salt)
     {
-        return createPasswordHash(hashAlgorithm, hashEncoding, hashCharset, username, password, null);
+        return createPasswordHash(hashAlgorithm, hashEncoding, hashCharset, username, password, salt, null);
     }
 
-    public static String createPasswordHash(String hashAlgorithm, String hashEncoding, String hashCharset, String username, String password, DigestCallback callback)
+    public static String createPasswordHash(String hashAlgorithm, String hashEncoding, String hashCharset,
+               String username, String password, String salt, DigestCallback callback)
     {
+       CSpacePasswordEncoder passwordEncoder = new CSpacePasswordEncoder();
+       String saltedPassword = passwordEncoder.mergePasswordAndSalt(password, salt); //
+         
         String passwordHash = null;
         byte passBytes[];
         try
         {
             if(hashCharset == null)
-                passBytes = password.getBytes();
+                passBytes = saltedPassword.getBytes();
             else
-                passBytes = password.getBytes(hashCharset);
+                passBytes = saltedPassword.getBytes(hashCharset);
         }
         catch(UnsupportedEncodingException uee)
         {
             logger.error((new StringBuilder()).append("charset ").append(hashCharset).append(" not found. Using platform default.").toString(), uee);
-            passBytes = password.getBytes();
+            passBytes = saltedPassword.getBytes();
         }
         try
         {