[java-idp-oidc] branch main updated: JOIDC-63 Missing required PKCE code challenges should raise an error in the authorization endpoint
Henri Mikkonen
henri.mikkonen at iki.fi
Tue Feb 22 16:02:34 UTC 2022
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=b140fd4ff9fbac3f84949789b55d0ee8d3ac71d1
The following commit(s) were added to refs/heads/main by this push:
new b140fd4f JOIDC-63 Missing required PKCE code challenges should raise an error in the authorization endpoint
b140fd4f is described below
commit b140fd4ff9fbac3f84949789b55d0ee8d3ac71d1
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Feb 22 18:01:32 2022 +0200
JOIDC-63 Missing required PKCE code challenges should raise an error in the authorization endpoint
https://shibboleth.atlassian.net/browse/JOIDC-63
Added a new validation action (ValidateCodeChallenge) to the authorize flow.
---
.../op/profile/impl/ValidateCodeChallenge.java | 170 ++++++++++++++
.../idp/flows/oidc/authorize/authorize-beans.xml | 7 +
.../idp/flows/oidc/authorize/authorize-flow.xml | 1 +
.../oidc/op/profile/flow/AuthorizeFlowTest.java | 115 ++++++++-
.../op/profile/impl/ValidateCodeChallengeTest.java | 258 +++++++++++++++++++++
5 files changed, 550 insertions(+), 1 deletion(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java
new file mode 100644
index 00000000..29e236b4
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallenge.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.shibboleth.idp.plugin.oidc.op.profile.impl;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestCodeChallengeLookupFunction;
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultRequestCodeChallengeMethodLookupFunction;
+import net.shibboleth.oidc.profile.config.logic.AllowPKCEPlainPredicate;
+import net.shibboleth.oidc.profile.config.logic.ForcePKCEPredicate;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Validates the presence of PKCE code challenge parameter from the incoming authentication request.
+ */
+public class ValidateCodeChallenge extends AbstractOIDCAuthenticationResponseAction {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(ValidateCodeChallenge.class);
+
+ /** Strategy used to determine whether to require PKCE. */
+ @Nonnull private Predicate<ProfileRequestContext> forcePKCECondition;
+
+ /** Strategy used to determine whether to allow plaintext PKCE. */
+ @Nonnull private Predicate<ProfileRequestContext> allowPKCEPlainCondition;
+
+ /** Strategy used to locate the code challenge. */
+ @Nonnull private Function<ProfileRequestContext, String> codeChallengeLookupStrategy;
+
+ /** Strategy used to locate the code challenge method. */
+ @Nonnull private Function<ProfileRequestContext, String> codeChallengeMethodLookupStrategy;
+
+ /** Whether PKCE is mandatory. */
+ private boolean forcePKCE;
+
+ /** Whether plain PKCE is allowed. */
+ private boolean plainPKCE;
+
+ /** PKCE code challenge. */
+ @Nullable private String codeChallenge;
+
+ /** PKCE code challenge method. */
+ @Nullable private String codeChallengeMethod;
+
+ /**
+ * Constructor.
+ */
+ public ValidateCodeChallenge() {
+ forcePKCECondition = new ForcePKCEPredicate();
+ allowPKCEPlainCondition = new AllowPKCEPlainPredicate();
+ codeChallengeLookupStrategy = new DefaultRequestCodeChallengeLookupFunction();
+ codeChallengeMethodLookupStrategy = new DefaultRequestCodeChallengeMethodLookupFunction();
+ }
+
+ /**
+ * Set the condition used to determine whether to require PKCE.
+ *
+ * @param condition condition to apply
+ */
+ public void setForcePKCECondition(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ forcePKCECondition = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+ /**
+ * Set the condition used to determine whether to allow plaintext PKCE.
+ *
+ * @param condition condition to apply
+ */
+ public void setAllowPKCEPlainCondition(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ allowPKCEPlainCondition = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+ /**
+ * Set the strategy used to locate the Code Challenge of the request.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setCodeChallengeLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ codeChallengeLookupStrategy =
+ Constraint.isNotNull(strategy, "Code challenge lookup strategy cannot be null");
+ }
+
+ /**
+ * Set the strategy used to locate the Code Challenge Method of the request.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setCodeChallengeMethodLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ codeChallengeMethodLookupStrategy =
+ Constraint.isNotNull(strategy, "Code challenge method lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ forcePKCE = forcePKCECondition.test(profileRequestContext);
+ plainPKCE = allowPKCEPlainCondition.test(profileRequestContext);
+
+ codeChallenge = codeChallengeLookupStrategy.apply(profileRequestContext);
+
+ if ((codeChallenge == null || codeChallenge.isEmpty()) && !forcePKCE) {
+ log.debug("{} No PKCE code challenge in request, nothing to do", getLogPrefix());
+ return false;
+ }
+
+ codeChallengeMethod = codeChallengeMethodLookupStrategy.apply(profileRequestContext);
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (codeChallenge == null || codeChallenge.isEmpty()) {
+ log.warn("{} No PKCE code challenge presented in authentication request" +
+ " even though required by the profile configuration", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.MISSING_PKCE_CODE_CHALLENGE);
+ return;
+ }
+ if (codeChallengeMethod == null || codeChallengeMethod.isEmpty() || "plain".equals(codeChallengeMethod)) {
+ if (!plainPKCE) {
+ log.warn("{} Plain PKCE code challenge method not allowed", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ return;
+ }
+ log.debug("{} Plain code challenge exists in the request and is accepted", getLogPrefix());
+ } else if ("S256".equals(codeChallengeMethod)) {
+ log.debug("{} S256 code challenge exists in the request", getLogPrefix());
+ } else {
+ log.warn("{} Unknown code challenge method: {}", getLogPrefix(), codeChallengeMethod);
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
index cf91cf11..85a953b8 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
@@ -172,6 +172,9 @@
<bean id="ValidateResponseType" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateResponseType"
scope="prototype" />
+ <bean id="ValidateCodeChallenge" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateCodeChallenge"
+ scope="prototype" />
+
<bean id="ValidateScope" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.ValidateScope" scope="prototype"
p:allowedScopeLookupStrategy="#{getObject('shibboleth.oidc.AllowedScopeStrategy') ?: getObject('shibboleth.oidc.DefaultAllowedScopeStrategy')}" />
@@ -387,6 +390,10 @@
value="#{T(com.nimbusds.oauth2.sdk.OAuth2Error).UNSUPPORTED_RESPONSE_TYPE}" />
<entry key="#{T(net.shibboleth.idp.authn.AuthnEventIds).NO_PASSIVE}"
value="#{T(com.nimbusds.openid.connect.sdk.OIDCError).LOGIN_REQUIRED}" />
+ <entry key="#{T(net.shibboleth.oidc.profile.core.OidcEventIds).MISSING_PKCE_CODE_CHALLENGE}"
+ value="#{T(net.shibboleth.oidc.profile.core.OidcError).MISSING_PKCE_CODE_CHALLENGE}" />
+ <entry key="#{T(net.shibboleth.oidc.profile.core.OidcEventIds).INVALID_PKCE_TRANSFORMATION_METHOD}"
+ value="#{T(net.shibboleth.oidc.profile.core.OidcError).INVALID_PKCE_TRANSFORMATION_METHOD}" />
</map>
</property>
</bean>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
index b3c49f15..7d2e6483 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-flow.xml
@@ -37,6 +37,7 @@
<evaluate expression="ValidateRequestObject" />
<evaluate expression="ValidateRedirectURI" />
<evaluate expression="ValidateResponseType" />
+ <evaluate expression="ValidateCodeChallenge" />
<evaluate expression="ValidateScope" />
<evaluate expression="SetRequestedClaimsToResponseContext" />
<evaluate expression="SetRequestedSubjectToResponseContext" />
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
index 01bf40b5..5ab419ae 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AuthorizeFlowTest.java
@@ -36,13 +36,13 @@ import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
-import com.nimbusds.oauth2.sdk.ErrorResponse;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.Scope;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
import net.shibboleth.idp.session.SessionException;
+import net.shibboleth.oidc.profile.core.OidcError;
/**
* Tests for the authorize-flow.
@@ -86,6 +86,116 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
Assert.assertNull(successResponse.getAccessToken());
Assert.assertNotNull(successResponse.getAuthorizationCode());
}
+
+ @Test
+ public void testWithAuthorizationCodeFlowUnforcedPKCE() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCEPlainUnforced&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri);
+ storeMetadata(storageService, "mockClientIdPKCEPlainUnforced", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEMissingChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri);
+ storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, OidcError.MISSING_PKCE_CODE_CHALLENGE.getDescription());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEUnknownChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unsupported");
+ storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, OidcError.INVALID_PKCE_TRANSFORMATION_METHOD.getDescription());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedPlainPKCEValidChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCEPlain&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
+ storeMetadata(storageService, "mockClientIdPKCEPlain", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedS256PKCEPlainChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=plain");
+ storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, OidcError.INVALID_PKCE_TRANSFORMATION_METHOD.getDescription());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedS256PKCEUnknownChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=unknown");
+ storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertErrorCode(result, "invalid_request");
+ assertErrorDescriptionContains(result, OidcError.INVALID_PKCE_TRANSFORMATION_METHOD.getDescription());
+ }
+
+ @Test
+ public void testWithAuthorizationCodeFlowForcedS256PKCEValidChallenge() throws IOException, ParseException, SessionException {
+ request.setMethod("GET");
+ request.setQueryString("client_id=mockClientIdPKCES256&response_type=code&scope=openid%20profile&redirect_uri="
+ + redirectUri + "&code_challenge=osdfojsfod&code_challenge_method=S256");
+ storeMetadata(storageService, "mockClientIdPKCES256", clientSecret, scope, redirectUri);
+
+ initializeThreadLocals();
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ final AuthenticationResponse responseMessage = parseSuccessResponse(result, AuthenticationResponse.class);
+ final AuthenticationSuccessResponse successResponse = responseMessage.toSuccessResponse();
+ Assert.assertEquals(successResponse.getRedirectionURI().toString(), redirectUri);
+ Assert.assertNull(successResponse.getIDToken());
+ Assert.assertNull(successResponse.getAccessToken());
+ Assert.assertNotNull(successResponse.getAuthorizationCode());
+ }
@Test
public void testWithAuthorizationCodeFlowNoScopes() throws IOException, ParseException, SessionException {
@@ -287,6 +397,9 @@ public class AuthorizeFlowTest extends AbstractOidcFlowTest {
@AfterMethod
public void removeMetadata() throws IOException {
removeMetadata(storageService, clientId);
+ removeMetadata(storageService, "mockClientIdPKCEPlainUnforced");
+ removeMetadata(storageService, "mockClientIdPKCEPlain");
+ removeMetadata(storageService, "mockClientIdPKCES256");
}
}
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java
new file mode 100644
index 00000000..8983c4bc
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateCodeChallengeTest.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.shibboleth.idp.plugin.oidc.op.profile.impl;
+
+import java.net.URISyntaxException;
+
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+import org.springframework.webflow.execution.Event;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+
+/** {@link ValidateCodeChallenge} unit test. */
+public class ValidateCodeChallengeTest extends BaseOIDCResponseActionTest {
+
+ private ValidateCodeChallenge action;
+
+ private boolean forcePkce;
+ private boolean allowPlain;
+
+ @BeforeMethod
+ private void init() throws ComponentInitializationException, URISyntaxException, ParseException {
+ action = new ValidateCodeChallenge();
+ action.setForcePKCECondition(prc -> forcePkce);
+ action.setAllowPKCEPlainCondition(prc -> allowPlain);
+ action.initialize();
+ }
+
+ @Test
+ public void testUnforcedAllowMissingChallenge() throws ComponentInitializationException {
+ forcePkce = false;
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForcedFailsWhenMissingChallenge() throws ComponentInitializationException {
+ forcePkce = true;
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.MISSING_PKCE_CODE_CHALLENGE);
+ }
+
+ @Test
+ public void testForcedFailsWhenEmptyChallenge() throws ComponentInitializationException, ParseException {
+ forcePkce = true;
+ setAuthenticationRequest(populateCodeChallenge("", null));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.MISSING_PKCE_CODE_CHALLENGE);
+ }
+
+ @Test
+ public void testUnforcedPNolainAllowedFailsWithUnknownMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "unsupported"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testUnforcedNoPlainAllowedFailsWithDefaultMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", null));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testUnforcedNoPlainAllowedFailsWithEmptyMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", ""));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testUnforcedNoPlainAllowedFailsWithPlainMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "plain"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testUnforcedNoPlainAllowedSuccessWithS256Method() throws ParseException {
+ forcePkce = false;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "S256"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForcedNoPlainAllowedFailsWithUnknownMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "unsupported"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testForcedNoPlainAllowedFailsWithDefaultMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", null));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testForcedNoPlainAllowedFailsWithEmptyMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", ""));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testForcedNoPlainAllowedFailsWithPlainMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "plain"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testForcedNoPlainAllowedSuccessWithS256Method() throws ParseException {
+ forcePkce = true;
+ allowPlain = false;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "S256"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testUnforcedPlainAllowedFailsWithUnknownMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "unsupported"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testUnforcedPlainAllowedSuccessWithDefaultMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", null));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testUnforcedPlainAllowedSuccessWithEmptyMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", ""));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testUnforcedPlainAllowedSuccesssWithPlainMethod() throws ParseException {
+ forcePkce = false;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "plain"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testUnforcedPlainAllowedSuccessWithS256Method() throws ParseException {
+ forcePkce = false;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "S256"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForcedPlainAllowedFailsWithUnknownMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "unsupported"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertEvent(event, OidcEventIds.INVALID_PKCE_TRANSFORMATION_METHOD);
+ }
+
+ @Test
+ public void testForcedPlainAllowedSuccessWithDefaultMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", null));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForcedPlainAllowedSuccessWithEmptyMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", ""));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForcedPlainAllowedSuccessWithPlainMethod() throws ParseException {
+ forcePkce = true;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "plain"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test
+ public void testForceoPlainAllowedSuccessWithS256Method() throws ParseException {
+ forcePkce = true;
+ allowPlain = true;
+ setAuthenticationRequest(populateCodeChallenge("asdsadasddsa", "S256"));
+ final Event event = action.execute(requestCtx);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ protected AuthenticationRequest populateCodeChallenge(final String challenge, final String challengeMethod)
+ throws ParseException {
+ final String authnRequest = request.toQueryString() + "&code_challenge=" + challenge;
+ return AuthenticationRequest.parse(challengeMethod == null ? authnRequest : authnRequest
+ + "&code_challenge_method=" + challengeMethod);
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list