diff --git a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java index cd1249084b..0f06d285f3 100644 --- a/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java +++ b/core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java @@ -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) { diff --git a/core/src/main/java/org/acegisecurity/providers/dao/MD5PasswordEncoder.java b/core/src/main/java/org/acegisecurity/providers/dao/MD5PasswordEncoder.java new file mode 100644 index 0000000000..e51f359efd --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/MD5PasswordEncoder.java @@ -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; + + +/** + *
+ * MD5 implementation of PasswordEncoder.
The ignorePasswordCase parameter is not used for this implementation.
A null password is encoded to the same value as an empty ("") password.
+ *
+ * Describes authentication operations on a password, so that digest algorithms + * can be abstracted + *
+ * + * @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); +} diff --git a/core/src/main/java/org/acegisecurity/providers/dao/PlaintextPasswordEncoder.java b/core/src/main/java/org/acegisecurity/providers/dao/PlaintextPasswordEncoder.java new file mode 100644 index 0000000000..e289740732 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/PlaintextPasswordEncoder.java @@ -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; + +/** + *+ * Plaintext implementation of PasswordEncoder. + *
+ * + * @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; + } +} diff --git a/core/src/main/java/org/acegisecurity/providers/dao/SHAPasswordEncoder.java b/core/src/main/java/org/acegisecurity/providers/dao/SHAPasswordEncoder.java new file mode 100644 index 0000000000..9b830b0904 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/SHAPasswordEncoder.java @@ -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; + + +/** + *
+ * SHA implementation of PasswordEncoder.
The ignorePasswordCase parameter is not used for this implementation.
A null password is encoded to the same value as an empty ("") password.
+ *
- * 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. *
* * @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 + *ROLE_ 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")});