diff --git a/core/src/main/java/org/springframework/security/providers/UsernamePasswordAuthenticationToken.java b/core/src/main/java/org/springframework/security/providers/UsernamePasswordAuthenticationToken.java index a1d892e5b6..8f5a0aa62f 100644 --- a/core/src/main/java/org/springframework/security/providers/UsernamePasswordAuthenticationToken.java +++ b/core/src/main/java/org/springframework/security/providers/UsernamePasswordAuthenticationToken.java @@ -20,9 +20,10 @@ import org.springframework.security.GrantedAuthority; /** * An {@link org.springframework.security.Authentication} implementation that is designed for simple presentation of a - * username and password.

The principal and credentials should be set with an - * Object that provides the respective property via its Object.toString() method. The - * simplest such Object to use is String.

+ * username and password. + *

The principal and credentials should be set with an Object that provides + * the respective property via its Object.toString() method. The simplest such Object to use + * is String.

* * @author Ben Alex * @version $Id$ @@ -36,13 +37,11 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT //~ Constructors =================================================================================================== -/** + /** * This constructor can be safely used by any code that wishes to create a * UsernamePasswordAuthenticationToken, as the {@link * #isAuthenticated()} will return false. * - * @param principal DOCUMENT ME! - * @param credentials DOCUMENT ME! */ public UsernamePasswordAuthenticationToken(Object principal, Object credentials) { super(null); @@ -51,12 +50,10 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT setAuthenticated(false); } -/** - * This constructor should only be used by - * AuthenticationManager or - * AuthenticationProvider implementations that are satisfied - * with producing a trusted (ie {@link #isAuthenticated()} = - * true) authentication token. + /** + * This constructor should only be used by AuthenticationManager or AuthenticationProvider + * implementations that are satisfied with producing a trusted (ie {@link #isAuthenticated()} = true) + * authentication token. * * @param principal * @param credentials @@ -79,8 +76,7 @@ public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationT return this.principal; } - public void setAuthenticated(boolean isAuthenticated) - throws IllegalArgumentException { + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor containing GrantedAuthority[]s instead"); diff --git a/ntlm/src/main/java/org/springframework/security/ui/ntlm/NtlmUsernamePasswordAuthenticationToken.java b/ntlm/src/main/java/org/springframework/security/ui/ntlm/NtlmUsernamePasswordAuthenticationToken.java index c92d05d0bb..4fb465ef4a 100755 --- a/ntlm/src/main/java/org/springframework/security/ui/ntlm/NtlmUsernamePasswordAuthenticationToken.java +++ b/ntlm/src/main/java/org/springframework/security/ui/ntlm/NtlmUsernamePasswordAuthenticationToken.java @@ -18,32 +18,40 @@ package org.springframework.security.ui.ntlm; import jcifs.smb.NtlmPasswordAuthentication; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.util.AuthorityUtils; /** - * An NTLM-specific {@link UsernamePasswordAuthenticationToken} that allows - * any provider to bypass the problem of an empty password since NTLM does - * not retrieve the user's password from the PDC. - * + * An NTLM-specific {@link UsernamePasswordAuthenticationToken} that allows any provider to bypass the problem of an + * empty password since NTLM does not retrieve the user's password from the PDC. + * * @author Sylvain Mougenot */ public class NtlmUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken { private static final long serialVersionUID = 1L; - - /** - * Spring Security often checks password ; but we do not have one. This is the replacement password + + /** + * Dummy authority array which is passed to the constructor of the parent class, + * ensuring that the "authenticated" property is set to "true" by default. See SEC-609. + */ + private static final GrantedAuthority[] NTLM_AUTHENTICATED = + AuthorityUtils.stringArrayToAuthorityArray(new String[] {"NTLM_AUTHENTICATED"}); + + /** + * Spring Security often checks password ; but we do not have one. This is the replacement password */ public static final String DEFAULT_PASSWORD = ""; /** * Create an NTLM {@link UsernamePasswordAuthenticationToken} using the * JCIFS {@link NtlmPasswordAuthentication} object. - * + * * @param ntlmAuth The {@link NtlmPasswordAuthentication} object. * @param stripDomain Uses just the username if true, * otherwise use the username and domain name. */ public NtlmUsernamePasswordAuthenticationToken(final NtlmPasswordAuthentication ntlmAuth, final boolean stripDomain) { - super((stripDomain) ? ntlmAuth.getUsername() : ntlmAuth.getName(), DEFAULT_PASSWORD); + super((stripDomain) ? ntlmAuth.getUsername() : ntlmAuth.getName(), DEFAULT_PASSWORD, NTLM_AUTHENTICATED); } } diff --git a/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java b/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java index 39f100c13d..affb43d54a 100755 --- a/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java +++ b/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java @@ -69,6 +69,10 @@ public class NtlmAwareLdapAuthenticator extends BindAuthenticator { return super.authenticate(authentication); } + if (!authentication.isAuthenticated()) { + throw new BadCredentialsException("Unauthenticated NTLM authentication token found"); + } + if (logger.isDebugEnabled()) { logger.debug("authenticate(NtlmUsernamePasswordAuthenticationToken) - start"); //$NON-NLS-1$ } diff --git a/ntlm/src/main/test/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticatorTests.java b/ntlm/src/main/test/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticatorTests.java new file mode 100644 index 0000000000..8f9989c07f --- /dev/null +++ b/ntlm/src/main/test/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticatorTests.java @@ -0,0 +1,50 @@ +package org.springframework.security.ui.ntlm.ldap.authenticator; + +import org.springframework.security.BadCredentialsException; +import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.ui.ntlm.NtlmUsernamePasswordAuthenticationToken; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; + +import jcifs.smb.NtlmPasswordAuthentication; +import org.junit.Test; + +/** + * @author Luke Taylor + * @version $Id$ + */ +public class NtlmAwareLdapAuthenticatorTests { + /** + * See SEC-609. + */ + @Test(expected = BadCredentialsException.class) + public void unauthenticatedTokenIsRejected() { + NtlmAwareLdapAuthenticator authenticator = new NtlmAwareLdapAuthenticator( + new DefaultSpringSecurityContextSource("ldap://blah")); + + NtlmUsernamePasswordAuthenticationToken token = new NtlmUsernamePasswordAuthenticationToken( + new NtlmPasswordAuthentication("blah"), false); + token.setAuthenticated(false); + + authenticator.authenticate(token); + } + + @Test + public void authenticatedTokenIsAccepted() { + NtlmAwareLdapAuthenticator authenticator = new NtlmAwareLdapAuthenticator(new DefaultSpringSecurityContextSource("ldap://blah")) { + // mimic loading of user + protected DirContextOperations loadUser(String aUserDn, String aUserName) { + return new DirContextAdapter(); + } + }; + + authenticator.setUserDnPatterns(new String[] {"somepattern"}); + + NtlmUsernamePasswordAuthenticationToken token = new NtlmUsernamePasswordAuthenticationToken( + new NtlmPasswordAuthentication("blah"), false); + + authenticator.authenticate(token); + } + + +}