more final version of the various PasswordEncoder implementations.

add unit tests for PasswordEncoder implementations.
remove ignore password case and ignore username case flags and handling from DaoAuthenticationProvider.
remove requirement described in JavaDoc for AuthenticationDao that it ignore case when returning a user by username. Implementations may still do so if configured as such.
This commit is contained in:
Colin Sampaleanu 2004-04-15 16:32:09 +00:00
parent 41a837f8cd
commit 5d9d734735
22 changed files with 274 additions and 150 deletions

View File

@ -0,0 +1,44 @@
/* 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>
* Convenience base for Digest password encoders
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public abstract class BaseDigestPasswordEncoder implements PasswordEncoder {
//~ Instance fields ========================================================
private boolean encodeHashAsBase64 = false;
//~ Methods ================================================================
/**
* The encoded password is normally returned as Hex (32 char) version of the
* hash bytes. Setting this property to true will cause the encoded pass to
* be returned as Base64 text, which will consume 24 characters.
*/
public void setEncodeHashAsBase64(boolean encodeHashAsBase64) {
this.encodeHashAsBase64 = encodeHashAsBase64;
}
public boolean getEncodeHashAsBase64() {
return encodeHashAsBase64;
}
}

View File

@ -47,8 +47,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
private AuthenticationDao authenticationDao;
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
private boolean ignorePasswordCase = false;
private boolean ignoreUsernameCase = true;
//~ Methods ================================================================
@ -60,36 +58,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
return authenticationDao;
}
/**
* Indicates whether the password comparison is case sensitive. Defaults to
* <code>false</code>, meaning an exact case match is required.
*
* @param ignorePasswordCase set to <code>true</code> for less stringent
* comparison
*/
public void setIgnorePasswordCase(boolean ignorePasswordCase) {
this.ignorePasswordCase = ignorePasswordCase;
}
public boolean isIgnorePasswordCase() {
return ignorePasswordCase;
}
/**
* Indicates whether the username search is case sensitive. Default to
* <code>true</code>, meaning an exact case match is not required.
*
* @param ignoreUsernameCase set to <code>false</code> for more stringent
* comparison
*/
public void setIgnoreUsernameCase(boolean ignoreUsernameCase) {
this.ignoreUsernameCase = ignoreUsernameCase;
}
public boolean isIgnoreUsernameCase() {
return ignoreUsernameCase;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate
* passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
@ -123,20 +91,12 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
throw new BadCredentialsException("Bad credentials presented");
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem
.getMessage());
}
if ((!this.ignoreUsernameCase)
&& (!user.getUsername().equals(authentication.getPrincipal()
.toString()))) {
throw new BadCredentialsException("Bad credentials presented");
.getMessage(), repositoryProblem);
}
if (!passwordEncoder.isPasswordValid(user.getPassword(),
authentication.getCredentials().toString(), user,
ignorePasswordCase)) {
authentication.getCredentials().toString(), user))
throw new BadCredentialsException("Bad credentials presented");
}
if (!user.isEnabled()) {
throw new DisabledException("User is disabled");

View File

@ -15,6 +15,7 @@
package net.sf.acegisecurity.providers.dao;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
@ -24,34 +25,39 @@ import org.apache.commons.codec.digest.DigestUtils;
* </p>
*
* <p>
* The ignorePasswordCase parameter is not used for this implementation.
* </p>
*
* <p>
* A null password is encoded to the same value as an empty ("") password.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class MD5PasswordEncoder implements PasswordEncoder {
public class MD5PasswordEncoder extends BaseDigestPasswordEncoder 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);
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(java.lang.String, java.lang.String, java.lang.Object)
*/
public boolean isPasswordValid(String encPass, String rawPass, Object saltSource) {
return pass1.equals(pass2);
}
String pass1 = "" + encPass;
String pass2 = encodeInternal("" + rawPass);
/* (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);
}
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 encodeInternal("" + rawPass);
}
private String encodeInternal(String input) {
if (!getEncodeHashAsBase64())
return DigestUtils.md5Hex(input);
byte[] encoded = Base64.encodeBase64(DigestUtils.md5(input));
return new String(encoded);
}
}

View File

@ -31,8 +31,8 @@ public interface PasswordEncoder {
//~ Methods ================================================================
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase)
Object saltSource)
throws DataAccessException;
public String encodePassword(String rawPass, Object saltSource);
public String encodePassword(String rawPass, Object saltSource) throws DataAccessException;
}

View File

@ -24,13 +24,32 @@ package net.sf.acegisecurity.providers.dao;
* @version $Id$
*/
public class PlaintextPasswordEncoder implements PasswordEncoder {
//~ Instance fields ========================================================
private boolean ignorePasswordCase = false;
//~ Methods ================================================================
/**
* Indicates whether the password comparison is case sensitive. Defaults to
* <code>false</code>, meaning an exact case match is required.
*
* @param ignorePasswordCase set to <code>true</code> for less stringent
* comparison
*/
public void setIgnorePasswordCase(boolean ignorePasswordCase) {
this.ignorePasswordCase = ignorePasswordCase;
}
public boolean isIgnorePasswordCase() {
return ignorePasswordCase;
}
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(net.sf.acegisecurity.providers.dao.User, java.lang.String, boolean)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(java.lang.String, java.lang.String, java.lang.Object)
*/
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase) {
public boolean isPasswordValid(String encPass, String rawPass, Object saltSource) {
String pass1 = "" + encPass;
String pass2 = "" + rawPass;

View File

@ -15,35 +15,30 @@
package net.sf.acegisecurity.providers.dao;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
/**
* <p>
* SHA implementation of PasswordEncoder.
* </p>
*
* <p>
* The ignorePasswordCase parameter is not used for this implementation.
* </p>
*
* <p>
* 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 ================================================================
public class SHAPasswordEncoder extends BaseDigestPasswordEncoder implements PasswordEncoder {
/* (non-Javadoc)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(net.sf.acegisecurity.providers.dao.User, java.lang.String, boolean)
* @see net.sf.acegisecurity.providers.dao.PasswordEncoder#isPasswordValid(java.lang.String, java.lang.String, java.lang.Object)
*/
public boolean isPasswordValid(String encPass, String rawPass,
Object saltSource, boolean ignorePasswordCase) {
public boolean isPasswordValid(String encPass, String rawPass, Object saltSource) {
String pass1 = "" + encPass;
String pass2 = DigestUtils.shaHex("" + rawPass);
String pass2 = encodeInternal("" + rawPass);
return pass1.equals(pass2);
}
@ -52,6 +47,15 @@ public class SHAPasswordEncoder implements PasswordEncoder {
* @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);
return encodeInternal("" + rawPass);
}
private String encodeInternal(String input) {
if (!getEncodeHashAsBase64())
return DigestUtils.shaHex(input);
byte[] encoded = Base64.encodeBase64(DigestUtils.sha(input));
return new String(encoded);
}
}

View File

@ -34,9 +34,11 @@ public interface AuthenticationDao {
//~ Methods ================================================================
/**
* Locates the user based on the username. The search is case insensitive,
* meaning the implementation must return any matching object irrespective
* of the mixture of uppercase and lowercase characters in the username.
* Locates the user based on the username. In the actual implementation,
* the search may possibly be case insensitive, or case insensitive
* depending on how the implementaion instance is configured. In this case,
* the User object that comes back may have a username that is of a different
* case than what was actually requested..
*
* @param username the username presented to the {@link
* DaoAuthenticationProvider}

View File

@ -36,8 +36,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -25,8 +25,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="jdbcDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -36,8 +36,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -34,8 +34,6 @@
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">

View File

@ -37,15 +37,6 @@ import org.springframework.dao.DataRetrievalFailureException;
* @version $Id$
*/
public class DaoAuthenticationProviderTests extends TestCase {
//~ Constructors ===========================================================
public DaoAuthenticationProviderTests() {
super();
}
public DaoAuthenticationProviderTests(String arg0) {
super(arg0);
}
//~ Methods ================================================================
@ -63,7 +54,6 @@ public class DaoAuthenticationProviderTests extends TestCase {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
assertTrue(!provider.isIgnorePasswordCase()); // default
try {
provider.authenticate(token);
@ -139,9 +129,6 @@ public class DaoAuthenticationProviderTests extends TestCase {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
assertTrue(provider.isIgnoreUsernameCase()); // default
provider.setIgnoreUsernameCase(false);
assertTrue(!provider.isIgnoreUsernameCase()); // changed
try {
provider.authenticate(token);
@ -151,32 +138,6 @@ public class DaoAuthenticationProviderTests extends TestCase {
}
}
public void testAuthenticateSuccessfulWithMixedCaseIfDefaultChanged() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
"KOAla");
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
assertTrue(!provider.isIgnorePasswordCase()); // default
provider.setIgnorePasswordCase(true);
assertTrue(provider.isIgnorePasswordCase()); // changed
Authentication result = provider.authenticate(token);
assertEquals("marissa", result.getPrincipal().toString());
}
public void testAuthenticateSuccessfulWithMixedCaseUsername() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("MaRiSSA",
"koala");
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
assertTrue(provider.isIgnoreUsernameCase()); // default
Authentication result = provider.authenticate(token);
assertEquals("marissa", result.getPrincipal().toString());
}
public void testAuthenticates() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
"koala");
@ -239,7 +200,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
private class MockAuthenticationDaoUserMarissa implements AuthenticationDao {
public User loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username.toLowerCase())) {
if ("marissa".equals(username)) {
return new User("marissa", "koala", true,
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")});
@ -253,7 +214,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
private class MockAuthenticationDaoUserPeter implements AuthenticationDao {
public User loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username.toLowerCase())) {
if ("peter".equals(username)) {
return new User("peter", "opal", false,
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")});

View File

@ -0,0 +1,47 @@
/* 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 junit.framework.TestCase;
/**
* <p>
* TestCase for PlaintextPasswordEncoder.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class MD5PasswordEncoderTest extends TestCase {
public void testBasicFunctionality() {
MD5PasswordEncoder pe = new MD5PasswordEncoder();
String raw = "abc123";
String badRaw = "abc321";
String encoded = pe.encodePassword(raw, null); // no SALT source
assertTrue(pe.isPasswordValid(encoded, raw, null));
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
assertTrue(encoded.length() == 32);
// now try Base64
pe.setEncodeHashAsBase64(true);
encoded = pe.encodePassword(raw, null); // no SALT source
assertTrue(pe.isPasswordValid(encoded, raw, null));
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
assertTrue(encoded.length() != 32);
}
}

View File

@ -0,0 +1,59 @@
/* 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 junit.framework.TestCase;
/**
* <p>
* TestCase for PlaintextPasswordEncoder.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class PlaintextPasswordEncoderTest extends TestCase {
public void testBasicFunctionality() {
PlaintextPasswordEncoder pe = new PlaintextPasswordEncoder();
String raw = "abc123";
String rawDiffCase = "AbC123";
String badRaw = "abc321";
// should be able to validate even without encoding
String encoded = raw;
assertTrue(pe.isPasswordValid(encoded, raw, null)); // no SALT source
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
// now make sure encoded version it gives us back is comparable as well
encoded = pe.encodePassword(raw, null);
assertTrue(pe.isPasswordValid(encoded, raw, null)); // no SALT source
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
// make sure default is not to ignore password case
encoded = pe.encodePassword(rawDiffCase, null);
assertFalse(pe.isPasswordValid(encoded, raw, null));
// now check for ignore password case
pe = new PlaintextPasswordEncoder();
pe.setIgnorePasswordCase(true);
// should be able to validate even without encoding
encoded = pe.encodePassword(rawDiffCase, null);
assertTrue(pe.isPasswordValid(encoded, raw, null));
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
}
}

View File

@ -0,0 +1,47 @@
/* 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 junit.framework.TestCase;
/**
* <p>
* TestCase for SHAPasswordEncoder.
* </p>
*
* @author colin sampaleanu
* @version $Id$
*/
public class SHAPasswordEncoderTest extends TestCase {
public void testBasicFunctionality() {
SHAPasswordEncoder pe = new SHAPasswordEncoder();
String raw = "abc123";
String badRaw = "abc321";
String encoded = pe.encodePassword(raw, null); // no SALT source
assertTrue(pe.isPasswordValid(encoded, raw, null));
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
assertTrue(encoded.length() == 40);
// now try Base64
pe.setEncodeHashAsBase64(true);
encoded = pe.encodePassword(raw, null); // no SALT source
assertTrue(pe.isPasswordValid(encoded, raw, null));
assertFalse(pe.isPasswordValid(encoded, badRaw, null));
assertTrue(encoded.length() != 40);
}
}

View File

@ -36,8 +36,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -850,15 +850,8 @@
<para><programlisting>&lt;bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
&lt;property name="authenticationDao"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
&lt;property name="ignorePasswordCase"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
&lt;property name="ignoreUsernameCase"&gt;&lt;value&gt;true&lt;/value&gt;&lt;/property&gt;
&lt;/bean&gt;</programlisting></para>
<para>By default the <literal>DaoAuthenticationProvider</literal> does
not require an exact match on usernames, but it does require an exact
match on passwords. This behavior can be configured with the optional
properties shown above.</para>
<para>For a class to be able to provide the
<literal>DaoAuthenticationProvider</literal> with access to an
authentication repository, it must implement the

View File

@ -48,8 +48,6 @@
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->

View File

@ -33,8 +33,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -43,8 +43,6 @@
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ -->

View File

@ -40,8 +40,6 @@
<!-- Authentication provider that queries our data access object -->
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
<property name="ignorePasswordCase"><value>false</value></property>
<property name="ignoreUsernameCase"><value>true</value></property>
</bean>
<!-- The authentication manager that iterates through our only authentication provider -->

View File

@ -1,5 +1,5 @@
#HSQL database
#Wed Apr 14 23:23:24 EDT 2004
#Thu Apr 15 12:20:59 EDT 2004
sql.strict_fk=true
readonly=false
sql.strong_fk=true