initial cut at allowing pluggable digest strategy for use in password handling in DaoAuthenticationProvider
This commit is contained in:
parent
547b1ff4e3
commit
aed9d2a1d8
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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")});
|
||||
|
||||
|
|
Loading…
Reference in New Issue