[java-identity-provider] branch main updated: IDP-2279 - incorrect filter template encoding
Daniel Fisher
dfisher at vt.edu
Sun Jun 16 13:56:02 UTC 2024
This is an automated email from the git hooks/post-receive script.
dfisher pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=60e312785c200a94b72efbef891bc0c732211449
The following commit(s) were added to refs/heads/main by this push:
new 60e312785 IDP-2279 - incorrect filter template encoding
60e312785 is described below
commit 60e312785c200a94b72efbef891bc0c732211449
Author: Daniel Fisher <dfisher at vt.edu>
AuthorDate: Sun Jun 16 09:47:38 2024 -0400
IDP-2279 - incorrect filter template encoding
Change filter template encoding from US_ASCII to UTF_8.
Add unit tests for multi-byte characters in the filter.
https://shibboleth.atlassian.net/browse/IDP-2279
---
.../authn/AbstractTemplateSearchDnResolver.java | 5 +-
.../authn/impl/LDAPCredentialValidatorTest.java | 296 ++++++++++++---------
.../shibboleth/idp/authn/impl/loginLDAPTest.ldif | 17 ++
3 files changed, 185 insertions(+), 133 deletions(-)
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractTemplateSearchDnResolver.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractTemplateSearchDnResolver.java
index 40e60b958..ec09a4fbd 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractTemplateSearchDnResolver.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractTemplateSearchDnResolver.java
@@ -14,6 +14,7 @@
package net.shibboleth.idp.authn;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -43,7 +44,7 @@ public abstract class AbstractTemplateSearchDnResolver extends SearchDnResolver
@Nonnull private final Template template;
/** Event handler used for escaping. */
- private ReferenceInsertionEventHandler eventHandler = new EscapingReferenceInsertionEventHandler();
+ private final ReferenceInsertionEventHandler eventHandler = new EscapingReferenceInsertionEventHandler();
/**
* Creates a new abstract template search DN resolver.
@@ -55,7 +56,7 @@ public abstract class AbstractTemplateSearchDnResolver extends SearchDnResolver
*/
public AbstractTemplateSearchDnResolver(@Nonnull final VelocityEngine engine,
@Nonnull @NotEmpty final String filter) throws VelocityException {
- template = Template.fromTemplate(engine, filter);
+ template = Template.fromTemplate(engine, filter, StandardCharsets.UTF_8);
setUserFilter(filter);
}
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
index 57a58de5b..17d2ea2b4 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
@@ -437,30 +437,14 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
doExtract();
final Event event = action.execute(src);
- AuthenticationResult result = ac.getAuthenticationResult();
- LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
- final AuthenticationWarningContext awc = ac.getSubcontext(AuthenticationWarningContext.class);
- assert awc != null && result != null;
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
+ final AuthenticationWarningContext awc = ac.getSubcontext(AuthenticationWarningContext.class);
+ assert awc != null;
ActionTestingSupport.assertEvent(event, "ExpiredPassword");
Assert.assertEquals(awc.getClassifiedWarnings().size(), 1);
Assert.assertTrue(awc.isClassifiedWarning("ExpiredPassword"));
-
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
}
@Test public void testExpiringPassword() throws ComponentInitializationException {
@@ -484,32 +468,13 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
-
- final AuthenticationResult result = ac.getAuthenticationResult();
- Assert.assertNotNull(result);
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
ActionTestingSupport.assertEvent(event, "ExpiringPassword");
-
final AuthenticationWarningContext awc = ac.getSubcontext(AuthenticationWarningContext.class);
- assert awc != null && result != null;
+ assert awc != null;
Assert.assertEquals(awc.getClassifiedWarnings().size(), 1);
Assert.assertTrue(awc.isClassifiedWarning("ExpiringPassword"));
-
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
}
@Test public void testAuthorized() throws ComponentInitializationException {
@@ -529,26 +494,8 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
-
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
-
- final AuthenticationResult result = ac.getAuthenticationResult();
- assert result != null;
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
}
@Test public void testComputedAndAuthorized() throws ComponentInitializationException {
@@ -578,26 +525,8 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
-
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
- final AuthenticationResult result = ac.getAuthenticationResult();
- assert result != null;
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
-
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
}
@Test public void testDefaultFilterSyntax() throws ComponentInitializationException {
@@ -623,28 +552,92 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
+ }
- final AuthenticationResult result = ac.getAuthenticationResult();
- assert result != null;
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
+ @Test public void testDefaultFilterSyntaxMultiByte() throws ComponentInitializationException {
+ final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
+ new DefaultConnectionFactory("ldap://localhost:10389"), VelocityEngine.newVelocityEngine(), "(uid={user})");
+ testResolver.setBaseDn("ou=people,dc=shibboleth,dc=net");
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
+
+ final Authenticator defaultFilterAuthenticator = new Authenticator(testResolver, authHandler);
+ getMockHttpServletRequest(action).addParameter("username", "RAPHAËL_WEIß");
+ getMockHttpServletRequest(action).addParameter("password", "changeit");
+
+ final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ assert ac != null;
+ ac.setAttemptedFlow(authenticationFlows.get(0));
+ validator.setAuthenticator(defaultFilterAuthenticator);
+ validator.initialize();
+
+ action.initialize();
+
+ doExtract();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertAuthSuccess(ac, "RAPHAËL_WEIß");
+ }
+
+ @Test public void testVelocityFilterSyntax() throws ComponentInitializationException {
+ final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
+ new DefaultConnectionFactory("ldap://localhost:10389"),
+ VelocityEngine.newVelocityEngine(),
+ "(uid=$usernamePasswordContext.username)");
+ testResolver.setBaseDn("ou=people,dc=shibboleth,dc=net");
+
+
+ final Authenticator defaultFilterAuthenticator = new Authenticator(testResolver, authHandler);
+ getMockHttpServletRequest(action).addParameter("username", "PETER_THE_PRINCIPAL");
+ getMockHttpServletRequest(action).addParameter("password", "changeit");
+
+ final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ assert ac != null;
+ ac.setAttemptedFlow(authenticationFlows.get(0));
+ validator.setAuthenticator(defaultFilterAuthenticator);
+ validator.initialize();
+
+ action.initialize();
+
+ doExtract();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
+ }
+
+ @Test public void testVelocityFilterSyntaxMultiByte() throws ComponentInitializationException {
+ final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
+ new DefaultConnectionFactory("ldap://localhost:10389"),
+ VelocityEngine.newVelocityEngine(),
+ "(uid=$usernamePasswordContext.username)");
+ testResolver.setBaseDn("ou=people,dc=shibboleth,dc=net");
+
+
+ final Authenticator defaultFilterAuthenticator = new Authenticator(testResolver, authHandler);
+ getMockHttpServletRequest(action).addParameter("username", "RAPHAËL_WEIß");
+ getMockHttpServletRequest(action).addParameter("password", "changeit");
+
+ final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ assert ac != null;
+ ac.setAttemptedFlow(authenticationFlows.get(0));
+ validator.setAuthenticator(defaultFilterAuthenticator);
+ validator.initialize();
+
+ action.initialize();
+
+ doExtract();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertAuthSuccess(ac, "RAPHAËL_WEIß");
}
- @Test public void testCombinedFilterSyntax() throws ComponentInitializationException {
+ @Test public void testCombinedVelocityFilterSyntax() throws ComponentInitializationException {
final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
new DefaultConnectionFactory("ldap://localhost:10389"),
VelocityEngine.newVelocityEngine(), "(|(mail=$usernamePasswordContext.username)(uid={user}))");
@@ -668,25 +661,62 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
+ }
- final AuthenticationResult result = ac.getAuthenticationResult();
- assert result != null;
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
+ @Test public void testCombinedVelocityFilterSyntaxMultiByte() throws ComponentInitializationException {
+ final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
+ new DefaultConnectionFactory("ldap://localhost:10389"),
+ VelocityEngine.newVelocityEngine(), "(&(mail=$usernamePasswordContext.username)(description=März Äpfel))");
+ testResolver.setBaseDn("ou=people,dc=shibboleth,dc=net");
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
+
+ final Authenticator defaultFilterAuthenticator = new Authenticator(testResolver, authHandler);
+ getMockHttpServletRequest(action).addParameter("username", "raphaël.weiß@shibboleth.net");
+ getMockHttpServletRequest(action).addParameter("password", "changeit");
+
+ final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ assert ac != null;
+ ac.setAttemptedFlow(authenticationFlows.get(0));
+ validator.setAuthenticator(defaultFilterAuthenticator);
+ validator.initialize();
+
+ action.initialize();
+
+ doExtract();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertAuthSuccess(ac, "raphaël.weiß@shibboleth.net");
+ }
+
+ @Test public void testCombinedVelocityFilterSyntaxMultiByteEscaped() throws ComponentInitializationException {
+ final TemplateSearchDnResolver testResolver = new TemplateSearchDnResolver(
+ new DefaultConnectionFactory("ldap://localhost:10389"),
+ VelocityEngine.newVelocityEngine(),
+ "(&(uid=$usernamePasswordContext.username)(description=M\\C3\\A4rz \\C3\\84pfel))");
+ testResolver.setBaseDn("ou=people,dc=shibboleth,dc=net");
+
+
+ final Authenticator defaultFilterAuthenticator = new Authenticator(testResolver, authHandler);
+ getMockHttpServletRequest(action).addParameter("username", "RAPHAËL_WEIß");
+ getMockHttpServletRequest(action).addParameter("password", "changeit");
+
+ final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ assert ac != null;
+ ac.setAttemptedFlow(authenticationFlows.get(0));
+ validator.setAuthenticator(defaultFilterAuthenticator);
+ validator.initialize();
+
+ action.initialize();
+
+ doExtract();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ assertAuthSuccess(ac, "RAPHAËL_WEIß");
}
@Test public void testMatchAndAuthorized() throws ComponentInitializationException {
@@ -708,24 +738,7 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- final AuthenticationErrorContext aec = ac.getSubcontext(AuthenticationErrorContext.class);
- Assert.assertNull(aec);
- final AuthenticationResult result = ac.getAuthenticationResult();
- assert result != null ;
- final LDAPResponseContext lrc = ac.getSubcontext(LDAPResponseContext.class);
- assert lrc != null;
- final AuthenticationResponse lar = lrc.getAuthenticationResponse();
- assert lar != null;
- Assert.assertEquals(lar.getAuthenticationResultCode(),
- AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
-
- final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
- Assert.assertNotNull(up);
- Assert.assertEquals(up.getName(), "PETER_THE_PRINCIPAL");
- final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
- Assert.assertNotNull(lp);
- Assert.assertEquals(lp.getName(), "PETER_THE_PRINCIPAL");
- Assert.assertNotNull(lp.getLdapEntry());
+ assertAuthSuccess(ac, "PETER_THE_PRINCIPAL");
}
@Test public void testAuthorizedAndKeepContext() throws ComponentInitializationException {
@@ -747,6 +760,27 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
ActionTestingSupport.assertProceedEvent(event);
}
+ private void assertAuthSuccess(final AuthenticationContext authContext, final String principalName) {
+ final AuthenticationErrorContext aec = authContext.getSubcontext(AuthenticationErrorContext.class);
+ Assert.assertNull(aec);
+ final AuthenticationResult result = authContext.getAuthenticationResult();
+ assert result != null;
+ final LDAPResponseContext lrc = authContext.getSubcontext(LDAPResponseContext.class);
+ assert lrc != null;
+ final AuthenticationResponse lar = lrc.getAuthenticationResponse();
+ assert lar != null;
+ Assert.assertEquals(lar.getAuthenticationResultCode(),
+ AuthenticationResultCode.AUTHENTICATION_HANDLER_SUCCESS);
+
+ final UsernamePrincipal up = result.getSubject().getPrincipals(UsernamePrincipal.class).iterator().next();
+ Assert.assertNotNull(up);
+ Assert.assertEquals(up.getName(), principalName);
+ final LdapPrincipal lp = result.getSubject().getPrincipals(LdapPrincipal.class).iterator().next();
+ Assert.assertNotNull(lp);
+ Assert.assertEquals(lp.getName(), principalName);
+ Assert.assertNotNull(lp.getLdapEntry());
+ }
+
private void doExtract() throws ComponentInitializationException {
final ExtractUsernamePasswordFromFormRequest extract = new ExtractUsernamePasswordFromFormRequest();
extract.setHttpServletRequestSupplier(action.getHttpServletRequestSupplier());
diff --git a/idp-authn-impl/src/test/resources/net/shibboleth/idp/authn/impl/loginLDAPTest.ldif b/idp-authn-impl/src/test/resources/net/shibboleth/idp/authn/impl/loginLDAPTest.ldif
index 7c48f70cd..335ca43b4 100644
--- a/idp-authn-impl/src/test/resources/net/shibboleth/idp/authn/impl/loginLDAPTest.ldif
+++ b/idp-authn-impl/src/test/resources/net/shibboleth/idp/authn/impl/loginLDAPTest.ldif
@@ -33,3 +33,20 @@ mail: paul.principal at shibboleth.net
mail: paulprincipal at shibboleth.net
description: test principal
+# dn: cn=Raphaël Weiß,ou=people,dc=shibboleth,dc=net
+dn:: Y249UmFwaGHDq2wgV2Vpw58sb3U9cGVvcGxlLGRjPXNoaWJib2xldGgsZGM9bmV0
+objectclass: inetOrgPerson
+# cn: Raphaël_Weiß
+cn:: UmFwaGHDq2wgV2Vpw58=
+# sn: Weiß
+sn:: V2Vpw58=
+# uid: RAPHAËL_WEIß
+uid:: UkFQSEHDi0xfV0VJw58=
+userpassword: changeit
+homephone: 555-111-4444
+# mail: raphaël.weiß@shibboleth.net
+mail:: cmFwaGHDq2wud2Vpw59Ac2hpYmJvbGV0aC5uZXQ=
+# mail: raphaëlweiß@shibboleth.net
+mail:: cmFwaGHDq2x3ZWnDn0BzaGliYm9sZXRoLm5ldA==
+# description: März Äpfel
+description:: TcOkcnogw4RwZmVs
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list