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
.
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
.
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);
+ }
+
+
+}