initial cut at allowing pluggable digest strategy for use in password handling in DaoAuthenticationProvider

This commit is contained in:
Colin Sampaleanu 2004-04-14 21:30:59 +00:00
parent 547b1ff4e3
commit aed9d2a1d8
6 changed files with 253 additions and 42 deletions

View File

@ -46,6 +46,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
//~ Instance fields ========================================================
private AuthenticationDao authenticationDao;
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
private boolean ignorePasswordCase = false;
private boolean ignoreUsernameCase = true;
@ -89,6 +90,21 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
return ignoreUsernameCase;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate
* passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
* default.
*
* @param passwordEncoder The passwordEncoder to use
*/
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
public PasswordEncoder getPasswordEncoder() {
return passwordEncoder;
}
public void afterPropertiesSet() throws Exception {
if (this.authenticationDao == null) {
throw new IllegalArgumentException(
@ -116,15 +132,9 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
throw new BadCredentialsException("Bad credentials presented");
}
if (!user.getPassword().toLowerCase().equals(authentication.getCredentials()
.toString()
.toLowerCase())) {
throw new BadCredentialsException("Bad credentials presented");
}
if ((!this.ignorePasswordCase)
&& (!user.getPassword().equals(authentication.getCredentials()
.toString()))) {
if (!passwordEncoder.isPasswordValid(user.getPassword(),
authentication.getCredentials().toString(), user,
ignorePasswordCase)) {
throw new BadCredentialsException("Bad credentials presented");
}
@ -133,7 +143,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
}
return new UsernamePasswordAuthenticationToken(user.getUsername(),
user.getPassword(), user.getAuthorities());
authentication.getCredentials().toString(), user.getAuthorities());
}
public boolean supports(Class authentication) {

View File

@ -0,0 +1,51 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.dao;
import org.apache.commons.codec.digest.DigestUtils;
/**
* <p>
* MD5 implementation of PasswordEncoder.<br/
* > The ignorePasswordCase parameter is not used for this implementation.<br/
* > A null password is encoded to the same value as an empty ("") password.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class MD5PasswordEncoder implements PasswordEncoder {
//~ Methods ================================================================
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(net.sf.acegisecurity.providers.dao.User, java.lang.String, boolean)
*/
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase) {
String pass1 = "" + encPass;
String pass2 = DigestUtils.md5Hex("" + rawPass);
return pass1.equals(pass2);
}
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#encodePassword(java.lang.String, java.lang.Object)
*/
public String encodePassword(String rawPass, Object saltSource) {
return DigestUtils.md5Hex("" + rawPass);
}
}

View File

@ -0,0 +1,38 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.dao;
import org.springframework.dao.DataAccessException;
/**
* <p>
* Describes authentication operations on a password, so that digest algorithms
* can be abstracted
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public interface PasswordEncoder {
//~ Methods ================================================================
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase)
throws DataAccessException;
public String encodePassword(String rawPass, Object saltSource);
}

View File

@ -0,0 +1,50 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.dao;
/**
* <p>
* Plaintext implementation of PasswordEncoder.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class PlaintextPasswordEncoder implements PasswordEncoder {
//~ Methods ================================================================
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(net.sf.acegisecurity.providers.dao.User, java.lang.String, boolean)
*/
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase) {
String pass1 = "" + encPass;
String pass2 = "" + rawPass;
if (!ignorePasswordCase) {
return pass1.equals(pass2);
} else {
return pass1.equalsIgnoreCase(pass2);
}
}
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#encodePassword(java.lang.String, java.lang.Object)
*/
public String encodePassword(String rawPass, Object saltSource) {
return rawPass;
}
}

View File

@ -0,0 +1,51 @@
/* Copyright 2004 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.acegisecurity.providers.dao;
import org.apache.commons.codec.digest.DigestUtils;
/**
* <p>
* SHA implementation of PasswordEncoder.<br/
* > The ignorePasswordCase parameter is not used for this implementation.<br/
* > A null password is encoded to the same value as an empty ("") password.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class SHAPasswordEncoder implements PasswordEncoder {
//~ Methods ================================================================
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(net.sf.acegisecurity.providers.dao.User, java.lang.String, boolean)
*/
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase) {
String pass1 = "" + encPass;
String pass2 = DigestUtils.shaHex("" + rawPass);
return pass1.equals(pass2);
}
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#encodePassword(java.lang.String, java.lang.Object)
*/
public String encodePassword(String rawPass, Object saltSource) {
return DigestUtils.shaHex("" + rawPass);
}
}

View File

@ -48,11 +48,14 @@ import javax.sql.DataSource;
* </p>
*
* <p>
* A default database structure is assumed, which most users of this class will
* A default database structure is assumed, (see {@link
* #DEF_USERS_BY_USERNAME_QUERY} and {@link
* #DEF_AUTHORITIES_BY_USERNAME_QUERY}, which most users of this class will
* need to override, if using an existing scheme. This may be done by setting
* the default query strings used, or if that does not provide enough
* flexibility, setting the actual {@link MappingSqlQuery} instances used to
* query the database.
* the default query strings used. If this does not provide enough
* flexibility, another strategy would be to subclass this class and override
* the {@link MappingSqlQuery} instances used, via the {@link
* #initMappingSqlQueries()} extension point.
* </p>
*
* @author Ben Alex
@ -68,10 +71,11 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
//~ Instance fields ========================================================
protected MappingSqlQuery authoritiesByUsernameMapping;
protected MappingSqlQuery usersByUsernameMapping;
protected String authoritiesByUsernameQuery;
protected String usersByUsernameQuery;
private MappingSqlQuery authoritiesByUsernameMapping;
private MappingSqlQuery usersByUsernameMapping;
private String authoritiesByUsernameQuery;
private String rolePrefix = "ROLE_";
private String usersByUsernameQuery;
//~ Constructors ===========================================================
@ -82,16 +86,6 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
//~ Methods ================================================================
/**
* Allows the default MappingSqlQuery used for retrieving authorities by
* username to be overriden. This may be used when overriding the query
* string alone is inadequate. Note that there is no point in setting this
* property and also specifying a query string, since there will be no
* way for the instance set by this property to get at the query string.
* As such, the MappingSqlQuery should be self contained.
*
* @param authoritiesByUsernameQuery The authoritiesByUsernameQuery to set.
*/
public void setAuthoritiesByUsernameMapping(
MappingSqlQuery authoritiesByUsernameQuery) {
this.authoritiesByUsernameMapping = authoritiesByUsernameQuery;
@ -120,15 +114,23 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
}
/**
* Allows the default MappingSqlQuery used for retrieving users by username
* to be overriden. This may be used when overriding the query string
* alone is inadequate. Note that there is no point in setting this
* property and also specifying a query string, since there will be no
* way for the instance set by this property to get at the query string.
* As such, the MappingSqlQuery should be self contained.
* Allows a default role prefix to be specified. If this is set to a
* non-empty value, then it is automatically prepended to any roles read
* in from the db. This may for example be used to add the
* <code>ROLE_</code> prefix expected to exist in role names (by default)
* by some other Acegi Security framework classes, in the case that the
* prefix is not already present in the db.
*
* @param usersByUsernameQuery The MappingSqlQuery to set.
* @param rolePrefix the new prefix
*/
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
public String getRolePrefix() {
return rolePrefix;
}
public void setUsersByUsernameMapping(MappingSqlQuery usersByUsernameQuery) {
this.usersByUsernameMapping = usersByUsernameQuery;
}
@ -183,8 +185,17 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
}
protected void initDao() throws ApplicationContextException {
usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());
authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());
initMappingSqlQueries();
}
/**
* Extension point to allow other MappingSqlQuery objects to be substituted
* in a subclass
*/
protected void initMappingSqlQueries() {
setUsersByUsernameMapping(new UsersByUsernameMapping(getDataSource()));
setAuthoritiesByUsernameMapping(new AuthoritiesByUsernameMapping(
getDataSource()));
}
//~ Inner Classes ==========================================================
@ -201,8 +212,8 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(rs
.getString("authority"));
String roleName = rolePrefix + rs.getString(1);
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
return authority;
}
@ -220,9 +231,9 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
String username = rs.getString("username");
String password = rs.getString("password");
boolean enabled = rs.getBoolean("enabled");
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
User user = new User(username, password, enabled,
new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});