[java-idp-oidc] branch main updated: JOIDC-64 - Refactor client authn on OAuth2 endpoints into a login flow

Scott Cantor cantor.2 at osu.edu
Tue Dec 21 22:14:30 UTC 2021


This is an automated email from the git hooks/post-receive script.

scantor 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=b2984c21a1071c50c5781b96fc6a3089fae7e095

The following commit(s) were added to refs/heads/main by this push:
     new b2984c21 JOIDC-64 - Refactor client authn on OAuth2 endpoints into a login flow
b2984c21 is described below

commit b2984c21a1071c50c5781b96fc6a3089fae7e095
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Dec 21 17:14:27 2021 -0500

    JOIDC-64 - Refactor client authn on OAuth2 endpoints into a login flow
    
    https://shibboleth.atlassian.net/browse/JOIDC-64
    
    Implement JWT validator (subject to existing bugs).
---
 .../oidc/op/authn/impl/JWTCredentialValidator.java | 204 ++++++++++++++++
 .../impl/ValidateEndpointAuthentication.java       | 243 -------------------
 .../authn/OAuth2Client/OAuth2Client-beans.xml      |   3 +-
 .../op/authn/impl/JWTCredentialValidatorTest.java  | 219 +++++++++++++++++
 .../plugin/oidc/op/profile/flow/TokenFlowTest.java |   4 +-
 .../impl/ValidateEndpointAuthenticationTest.java   | 258 ---------------------
 6 files changed, 427 insertions(+), 504 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidator.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidator.java
new file mode 100644
index 00000000..dbfc8aec
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidator.java
@@ -0,0 +1,204 @@
+/*
+ * 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.authn.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+import net.shibboleth.idp.authn.AbstractCredentialValidator;
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.idp.plugin.oidc.op.authn.context.OAuth2ClientAuthenticationContext;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.oidc.security.impl.JWTSignatureValidationUtil;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.xmlsec.context.SecurityParametersContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.JWTAuthentication;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+
+/**
+ * A validator that handles authentication via signed JWT.
+ * 
+ * <p>For now, implemented via Nimbus APIs.</p>
+ * 
+ * TODO: there will be additional validation checks added once implemented on the older branch
+ */
+ at ThreadSafeAfterInit
+public class JWTCredentialValidator extends AbstractCredentialValidator {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(JWTCredentialValidator.class);
+    
+    /** Strategy that will return {@link OAuth2ClientAuthenticationContext}. */
+    @Nonnull private Function<ProfileRequestContext,OAuth2ClientAuthenticationContext> clientAuthContextLookupStrategy;
+
+    /** Strategy used to locate the {@link SecurityParametersContext} to use for verification. */
+    @Nonnull private Function<ProfileRequestContext,SecurityParametersContext> securityParametersLookupStrategy;
+
+    /** Whether to save the JWT in the Java Subject's public credentials. */
+    private boolean saveTokenToCredentialSet;
+    
+    /** Constructor. */
+    public JWTCredentialValidator() {
+        // PRC -> AuthenticationContext -> OAuth2ClientAuthenticationContext
+        clientAuthContextLookupStrategy = new ChildContextLookup<>(OAuth2ClientAuthenticationContext.class).compose(
+                new ChildContextLookup<>(AuthenticationContext.class));
+        // PRC -> RP -> SPC
+        securityParametersLookupStrategy = new ChildContextLookup<>(SecurityParametersContext.class).compose(
+                new ChildContextLookup<>(RelyingPartyContext.class));
+    }
+    
+    /**
+     * Set the strategy used to return the {@link OAuth2ClientAuthenticationContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setOAuth2ClientAuthenticationLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,OAuth2ClientAuthenticationContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+    
+        clientAuthContextLookupStrategy =
+                Constraint.isNotNull(strategy, "OAuth2ClientAuthenticationContext lookup strategy cannot be null");
+    }
+    
+    /**
+     * Set the strategy used to locate the {@link SecurityParametersContext} to use.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setSecurityParametersLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,SecurityParametersContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+        securityParametersLookupStrategy =
+                Constraint.isNotNull(strategy, "SecurityParameterContext lookup strategy cannot be null");
+    }
+
+    
+    /**
+     * Set whether to save the JWT in the Java Subject's public credentials.
+     * 
+     * <p>Defaults to true</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setSaveTokenToCredentialSet(final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        saveTokenToCredentialSet = flag;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    @Nullable protected Subject doValidate(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final AuthenticationContext authenticationContext,
+            @Nullable final WarningHandler warningHandler,
+            @Nullable final ErrorHandler errorHandler) throws Exception {
+        
+        final OAuth2ClientAuthenticationContext clientAuthContext =
+                clientAuthContextLookupStrategy.apply(profileRequestContext);
+        if (clientAuthContext == null || clientAuthContext.getClientAuthentication() == null) {
+            log.debug("{} No OAuth 2.0 client authentication information found", getLogPrefix());
+            return null;
+        }
+        
+        final ClientAuthentication clientAuth = clientAuthContext.getClientAuthentication();
+        if (!ClientAuthenticationMethod.CLIENT_SECRET_JWT.equals(clientAuth.getMethod()) &&
+                !ClientAuthenticationMethod.PRIVATE_KEY_JWT.equals(clientAuth.getMethod())) {
+            log.debug("{} OAuth client authentication for '{}' of unsupported type: {}", getLogPrefix(),
+                    clientAuth.getClientID(), clientAuth.getMethod());
+            return null;
+        }
+        
+        if (!(clientAuth instanceof JWTAuthentication)) {
+            log.warn("{} OAuth client authentication object of unexpected type: {}", getLogPrefix(),
+                    clientAuth.getClass().getSimpleName());
+            log.info("{} Login by '{}' failed", getLogPrefix(), clientAuth.getClientID());
+            final LoginException e = new LoginException(AuthnEventIds.INVALID_CREDENTIALS); 
+            if (errorHandler != null) { 
+                errorHandler.handleError(profileRequestContext, authenticationContext, e,
+                        AuthnEventIds.INVALID_CREDENTIALS);
+            }
+            throw e;
+        }
+        
+        final JWTAuthentication jwtAuth = (JWTAuthentication) clientAuth;
+        final String errorEventId = JWTSignatureValidationUtil.validateSignature(
+                securityParametersLookupStrategy.apply(profileRequestContext), jwtAuth.getClientAssertion(),
+                AuthnEventIds.INVALID_CREDENTIALS);
+        if (errorEventId != null) {
+            log.info("{} Login by '{}' failed", getLogPrefix(), clientAuth.getClientID());
+            final LoginException e = new LoginException(errorEventId); 
+            if (errorHandler != null) { 
+                errorHandler.handleError(profileRequestContext, authenticationContext, e,
+                        AuthnEventIds.INVALID_CREDENTIALS);
+            }
+            throw e;
+        }
+
+        log.info("{} Login by '{}' succeeded", getLogPrefix(), clientAuth.getClientID());
+        
+        return populateSubject(clientAuth.getClientID(), jwtAuth.getClientAssertion());
+    }
+
+   /**
+    * Builds a subject with "standard" content from the validation.
+    *
+    * @param clientId client ID
+    * @param token the token validated
+    * 
+    * @return the decorated subject
+    */
+   @Nonnull protected Subject populateSubject(@Nonnull @NotEmpty final ClientID clientId,
+           @Nonnull final SignedJWT token) {
+      
+       final Subject subject = new Subject();
+       subject.getPrincipals().add(new UsernamePrincipal(clientId.getValue()));
+       if (saveTokenToCredentialSet) {
+           subject.getPublicCredentials().add(token);
+       }
+      
+       return super.populateSubject(subject);
+   }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java
deleted file mode 100644
index cba47e49..00000000
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthentication.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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.Set;
-import java.util.function.Function;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.opensaml.messaging.context.navigate.ChildContextLookup;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-import org.opensaml.xmlsec.context.SecurityParametersContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.nimbusds.jwt.SignedJWT;
-import com.nimbusds.oauth2.sdk.AbstractOptionallyAuthenticatedRequest;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
-import com.nimbusds.oauth2.sdk.auth.JWTAuthentication;
-import com.nimbusds.oauth2.sdk.auth.PlainClientSecret;
-import com.nimbusds.oauth2.sdk.auth.Secret;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
-
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
-import net.shibboleth.oidc.profile.config.navigate.TokenEndpointAuthMethodLookupFunction;
-import net.shibboleth.oidc.security.impl.JWTSignatureValidationUtil;
-import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
-import net.shibboleth.utilities.java.support.component.ComponentSupport;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * Validates the endpoint authentication with the token_endpoint_auth_method stored to the client's metadata.
- */
-public class ValidateEndpointAuthentication extends AbstractOIDCRequestAction<AbstractOptionallyAuthenticatedRequest> {
-
-    /** Class logger. */
-    @Nonnull private Logger log = LoggerFactory.getLogger(ValidateEndpointAuthentication.class);
-    
-    /** Strategy that will return {@link OIDCMetadataContext}. */
-    @Nonnull private Function<ProfileRequestContext, OIDCMetadataContext> oidcMetadataContextLookupStrategy;
-    
-    /** Strategy to obtain enabled token endpoint authentication methods. */
-    @Nullable private Function<ProfileRequestContext, Set<ClientAuthenticationMethod>> 
-        tokenEndpointAuthMethodsLookupStrategy;
-    
-    /** The attached OIDC metadata context. */
-    @Nullable private OIDCMetadataContext oidcMetadataContext;
-    
-    /*** The signature validation parameters. */
-    @Nullable private OIDCSignatureValidationParameters signatureValidationParameters;
-
-    /**
-     * Strategy used to locate the {@link SecurityParametersContext} to use for signing.
-     */
-    @Nonnull private Function<ProfileRequestContext, SecurityParametersContext> securityParametersLookupStrategy;
-
-    
-    /**
-     * Constructor.
-     */
-    public ValidateEndpointAuthentication() {
-        oidcMetadataContextLookupStrategy = new ChildContextLookup<>(OIDCMetadataContext.class).compose(
-                new InboundMessageContextLookup());
-        tokenEndpointAuthMethodsLookupStrategy = new TokenEndpointAuthMethodLookupFunction();
-        securityParametersLookupStrategy = new ChildContextLookup<>(SecurityParametersContext.class);
-    }
-        
-    /**
-     * Set the strategy used to return the {@link OIDCMetadataContext}.
-     * 
-     * @param strategy The lookup strategy.
-     */
-    public void setOidcMetadataContextLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
-        oidcMetadataContextLookupStrategy =
-                Constraint.isNotNull(strategy, "OIDCMetadataContext lookup strategy cannot be null");
-    }
-    
-    /**
-     * Set strategy to obtain enabled token endpoint authentication methods.
-     * @param strategy What to set.
-     */
-    public void setTokenEndpointAuthMethodsLookupStrategy(@Nonnull final Function<ProfileRequestContext, 
-            Set<ClientAuthenticationMethod>> strategy) {
-        tokenEndpointAuthMethodsLookupStrategy = Constraint.isNotNull(strategy, 
-                "Strategy to obtain enabled token endpoint authentication methods cannot be null");
-        
-    }
-    
-    /**
-     * Set the strategy used to locate the {@link SecurityParametersContext} to use.
-     * 
-     * @param strategy lookup strategy
-     */
-    public void setSecurityParametersLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, SecurityParametersContext> strategy) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-
-        securityParametersLookupStrategy =
-                Constraint.isNotNull(strategy, "SecurityParameterContext lookup strategy cannot be null");
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        if (!super.doPreExecute(profileRequestContext)) {
-            return false;
-        }
-        
-        oidcMetadataContext = oidcMetadataContextLookupStrategy.apply(profileRequestContext);
-        if (oidcMetadataContext == null) {
-            log.error("{} OICDMetadataContext is null", getLogPrefix());
-            // TODO: should this be an error signal?
-            return false;
-        }
-        return true;
-    }
-    
-    // Checkstyle: CyclomaticComplexity OFF
-
-    /** {@inheritDoc} */
-    @Override
-    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        final AbstractOptionallyAuthenticatedRequest request = getRequest();
-        final OIDCClientInformation clientInformation = oidcMetadataContext.getClientInformation();
-        final OIDCClientMetadata clientMetadata = clientInformation.getOIDCMetadata();
-        final ClientAuthenticationMethod clientAuthMethod = clientMetadata.getTokenEndpointAuthMethod() != null ? 
-                clientMetadata.getTokenEndpointAuthMethod() : ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
-        final ClientAuthentication clientAuth = request.getClientAuthentication();
-        final Set<ClientAuthenticationMethod> enabledMethods = 
-                tokenEndpointAuthMethodsLookupStrategy.apply(profileRequestContext);
-                
-        if (enabledAndEquals(enabledMethods, clientAuthMethod, ClientAuthenticationMethod.NONE)) {
-           log.debug("{} None authentication is requested and enabled, nothing to do", getLogPrefix());
-           return;
-        } else if (enabledAndEquals(enabledMethods, clientAuthMethod, 
-                ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
-            if (clientAuth instanceof ClientSecretBasic) {
-                if (validateSecret((ClientSecretBasic)clientAuth, clientInformation)) {
-                    return;
-                }
-            } else {
-                log.warn("{} Unrecognized client authentication {} for client_secret_basic", getLogPrefix(), 
-                        request.getClientAuthentication());
-            }
-        } else if (enabledAndEquals(enabledMethods, clientAuthMethod, ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
-            if (clientAuth instanceof ClientSecretPost) {
-                if (validateSecret((ClientSecretPost)clientAuth, clientInformation)) {
-                    return;
-                }
-            } else {
-                log.warn("{} Unrecognized client authentication {} for client_secret_post", getLogPrefix(), 
-                        request.getClientAuthentication());
-            }
-        } else if (enabledAndEquals(enabledMethods, clientAuthMethod, ClientAuthenticationMethod.CLIENT_SECRET_JWT)
-                || enabledAndEquals(enabledMethods, clientAuthMethod, ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
-            if (clientAuth instanceof JWTAuthentication) {
-                final SignedJWT jwt = ((JWTAuthentication) clientAuth).getClientAssertion();
-                final String errorEventId = JWTSignatureValidationUtil.validateSignature(
-                        securityParametersLookupStrategy.apply(profileRequestContext), jwt, EventIds.ACCESS_DENIED);
-                if (errorEventId != null) {
-                    ActionSupport.buildEvent(profileRequestContext, errorEventId);
-                }
-                return;
-            }
-        } else {
-            log.warn("{} Unsupported client authentication method {}", getLogPrefix(), clientAuth.getMethod());
-        }
-        ActionSupport.buildEvent(profileRequestContext, EventIds.ACCESS_DENIED);
-    }
-    
-    // Checkstyle: CyclomaticComplexity ON
-    
-    /**
-     * Checks whether the requested authentication method is enabled and matching to the desired method.
-     * @param enabledMethods The list of enabled authentication method.
-     * @param requestedMethod The requested authentication method to be checked.
-     * @param desiredMethod The desired authentication method.
-     * @return True if enabled and matching, false otherwise.
-     */
-    protected boolean enabledAndEquals(final Set<ClientAuthenticationMethod> enabledMethods, 
-            final ClientAuthenticationMethod requestedMethod, final ClientAuthenticationMethod desiredMethod) {
-        if (requestedMethod.equals(desiredMethod)) {
-            if (enabledMethods == null || enabledMethods.isEmpty()) {
-                log.warn("{} List of enabled methods is empty, all methods are disabled", getLogPrefix());
-                return false;
-            }
-            if (!enabledMethods.contains(requestedMethod)) {
-                log.warn("{} The requested method {} is not enabled", getLogPrefix(), requestedMethod);
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-    
-    /**
-     * Validates the given client secret against the one stored in the client's metadata.
-     * @param secret The secret to be validated.
-     * @param clientInformation The client metadata.
-     * @return True if the secret was valid, false otherwise.
-     */
-    protected boolean validateSecret(final PlainClientSecret secret, final OIDCClientInformation clientInformation) {
-        final Secret clientSecret = secret.getClientSecret();
-        if (clientSecret == null) {
-            log.warn("{} The client secret was null and cannot be validated", getLogPrefix());
-            return false;
-        }
-        //TODO: should support other than plaintext storage
-        if (clientSecret.equals(clientInformation.getSecret())) {
-            log.debug("{} The client secret successfully verified", getLogPrefix());
-            return true;
-        }
-        log.warn("{} The client secret validation failed", getLogPrefix());
-        return false;
-    }
-    
-}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml
index e3c66b11..3ebbed75 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml
@@ -59,7 +59,8 @@
     <util:list id="DefaultOAuth2ClientValidators">
         <bean class="net.shibboleth.idp.plugin.oidc.op.authn.impl.OIDCClientInfoCredentialValidator"
             p:id="oauth2-clientinfo" />
-        <!-- TODO: Add JWT Validators once implemented -->
+        <bean class="net.shibboleth.idp.plugin.oidc.op.authn.impl.JWTCredentialValidator"
+            p:id="oauth2-jwt" />
     </util:list>
     
     <!-- Validator parent beans -->
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidatorTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidatorTest.java
new file mode 100644
index 00000000..6a6416fa
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/authn/impl/JWTCredentialValidatorTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.authn.impl;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collections;
+import java.util.Date;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.xmlsec.context.SecurityParametersContext;
+import org.springframework.webflow.execution.Event;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.oauth2.sdk.AuthorizationCode;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.TokenRequest;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
+import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.impl.ValidateCredentials;
+import net.shibboleth.idp.authn.impl.testing.BaseAuthenticationContextTest;
+import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.idp.plugin.oidc.op.authn.context.OAuth2ClientAuthenticationContext;
+import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/**
+ * Unit tests for {@link JWTCredentialValidator}.
+ */
+public class JWTCredentialValidatorTest extends BaseAuthenticationContextTest {
+    
+    ClientID clientId;
+    Secret clientSecret;
+    
+    URI endpointUri;
+    
+    RSAPrivateKey rsaPrivateKey;
+    RSAPublicKey rsaPublicKey;
+
+    private JWTCredentialValidator validator;
+    private ValidateCredentials action;
+    
+    @BeforeClass
+    public void initKeys() throws NoSuchAlgorithmException {
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        final KeyPair keyPair = keyGen.genKeyPair();
+        rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+        rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+    }
+    
+    @BeforeMethod
+    public void setUo() throws URISyntaxException, ComponentInitializationException {
+        super.setUp();
+        
+        clientId = new ClientID("mockId");
+        clientSecret = new Secret("secret1234567890secret1234567890secret1234567890");
+        endpointUri = new URI("https://mock.example.org/");
+
+        validator = new JWTCredentialValidator();
+        validator.setId("test");
+        validator.setSecurityParametersLookupStrategy(new ChildContextLookup<>(SecurityParametersContext.class));
+        validator.initialize();
+        
+        action = new ValidateCredentials();
+        action.setValidators(Collections.singletonList(validator));
+        action.initialize();
+    }
+    
+    protected void completeSetup(final TokenRequest request, final ClientAuthenticationMethod storedMethod,
+            final boolean sameSecret) throws NoSuchAlgorithmException, JOSEException {
+
+        final OIDCMetadataContext oidcContext = new OIDCMetadataContext();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setTokenEndpointAuthMethod(storedMethod);
+        
+        BasicJWKCredential credential = null;
+        final OIDCSignatureValidationParameters params = new OIDCSignatureValidationParameters();
+        if (storedMethod.equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
+            params.setSignatureAlgorithm("RS256");
+            credential = new BasicJWKCredential();
+            credential.setAlgorithm(JWSAlgorithm.parse("RS256"));
+            final RSAKey rsaKey;
+            if (sameSecret) {
+                rsaKey = new RSAKey.Builder(rsaPublicKey).build();
+            } else {
+                final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+                keyGen.initialize(1024);
+                rsaKey = new RSAKey.Builder((RSAPublicKey)keyGen.genKeyPair().getPublic()).build();
+            }
+            credential.setPublicKey(rsaKey.toPublicKey());
+        } else if (storedMethod.equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
+            params.setSignatureAlgorithm("HS256");
+            credential = new BasicJWKCredential();
+            credential.setAlgorithm(JWSAlgorithm.parse("HS256"));
+            if (sameSecret) {
+                credential.setSecretKey(new SecretKeySpec(clientSecret.getValueBytes(), "NONE"));
+            } else {
+                credential.setSecretKey(new SecretKeySpec("secret1234567890secret1234567890secretWRONG".getBytes(), "NONE"));
+            }
+        }
+        
+        if (credential != null) {
+            final SecurityParametersContext secCtx =
+                    (SecurityParametersContext) prc.addSubcontext(new SecurityParametersContext());
+            params.getValidationCredentials().add(credential);
+            secCtx.setSignatureSigningParameters(params);
+        }
+        
+        final OIDCClientInformation clientInformation = 
+                new OIDCClientInformation(clientId, new Date(), metadata, clientSecret);
+        oidcContext.setClientInformation(clientInformation);
+        prc.getInboundMessageContext().addSubcontext(oidcContext);
+    }
+    
+    protected void initializeTokenRequest(final ClientAuthenticationMethod method, final boolean success)
+            throws JOSEException, NoSuchAlgorithmException {
+
+        final ClientAuthentication clientAuth;
+        if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
+            clientAuth = new ClientSecretJWT(clientId, endpointUri, JWSAlgorithm.HS256, clientSecret);
+        } else if (method.equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
+            clientAuth = new PrivateKeyJWT(clientId, endpointUri, JWSAlgorithm.RS256, rsaPrivateKey, null, null);
+        } else {
+            clientAuth = null;
+        }
+
+        final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class, true);
+        ac.setAttemptedFlow(authenticationFlows.get(0));
+        ac.getSubcontext(OAuth2ClientAuthenticationContext.class, true).setClientAuthentication(clientAuth);
+        
+        final AuthorizationGrant authzGrant = new AuthorizationCodeGrant(new AuthorizationCode(), null);
+        completeSetup(new TokenRequest(null, clientAuth, authzGrant), method, success);
+    }
+    
+    @Test
+    public void testSecretJwt() throws JOSEException, NoSuchAlgorithmException {
+        initializeTokenRequest(ClientAuthenticationMethod.CLIENT_SECRET_JWT, true);
+
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertProceedEvent(event);
+        
+        final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+        Assert.assertNotNull(ac.getAuthenticationResult());
+        Assert.assertEquals(ac.getAuthenticationResult().getSubject().getPrincipals(UsernamePrincipal.class).iterator()
+                .next().getName(), clientId.getValue());
+    }
+
+    @Test
+    public void testPrivateKeyJwt() throws JOSEException, NoSuchAlgorithmException {
+        initializeTokenRequest(ClientAuthenticationMethod.PRIVATE_KEY_JWT, true);
+        
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertProceedEvent(event);
+        
+        final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+        Assert.assertNotNull(ac.getAuthenticationResult());
+        Assert.assertEquals(ac.getAuthenticationResult().getSubject().getPrincipals(UsernamePrincipal.class).iterator()
+                .next().getName(), clientId.getValue());
+    }
+
+    @Test
+    public void testFailingSecretJwt() throws JOSEException, NoSuchAlgorithmException {
+        initializeTokenRequest(ClientAuthenticationMethod.CLIENT_SECRET_JWT, false);
+
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
+    }
+
+    @Test
+    public void testFailingPrivateKeyJwt() throws JOSEException, NoSuchAlgorithmException {
+        initializeTokenRequest(ClientAuthenticationMethod.PRIVATE_KEY_JWT, false);
+        
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
+    }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
index bc7cc61e..3e953e2f 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/TokenFlowTest.java
@@ -239,7 +239,7 @@ public class TokenFlowTest extends AbstractOidcFlowTest {
                 Instant.now().plusSeconds(30))).getValue();
     }
 
-    @Test(enabled=false)
+    @Test
     public void testValidSecretJWT() throws ParseException, IOException, NoSuchAlgorithmException, URISyntaxException,
         DataSealerException, ComponentInitializationException, JOSEException {
         ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
@@ -248,7 +248,7 @@ public class TokenFlowTest extends AbstractOidcFlowTest {
         Assert.assertNotNull(response.getTokens().getAccessToken());
     }
 
-    @Test(enabled=false)
+    @Test
     public void testValidSecretJWTNoAlg() throws ParseException, IOException, NoSuchAlgorithmException,
         URISyntaxException, DataSealerException, ComponentInitializationException, JOSEException {
         ClientSecretJWT clientAuth = buildSecretJwtAuth(clientSecret);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java
deleted file mode 100644
index 4b3b267b..00000000
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateEndpointAuthenticationTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * 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.URI;
-import java.net.URISyntaxException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.util.Date;
-import java.util.Set;
-import java.util.function.Function;
-
-import javax.crypto.spec.SecretKeySpec;
-
-import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.xmlsec.context.SecurityParametersContext;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
-import org.testng.Assert;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.jwk.RSAKey;
-import com.nimbusds.oauth2.sdk.AuthorizationCode;
-import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
-import com.nimbusds.oauth2.sdk.AuthorizationGrant;
-import com.nimbusds.oauth2.sdk.TokenRequest;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretPost;
-import com.nimbusds.oauth2.sdk.auth.PrivateKeyJWT;
-import com.nimbusds.oauth2.sdk.auth.Secret;
-import com.nimbusds.oauth2.sdk.id.ClientID;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
-import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
-
-import net.shibboleth.idp.plugin.oidc.op.messaging.context.OIDCMetadataContext;
-import net.shibboleth.idp.profile.context.navigate.AbstractRelyingPartyLookupFunction;
-import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
-import net.shibboleth.idp.profile.testing.ActionTestingSupport;
-import net.shibboleth.idp.profile.testing.RequestContextBuilder;
-import net.shibboleth.oidc.security.credential.BasicJWKCredential;
-import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-
-/**
- * Unit tests for {@link ValidateEndpointAuthentication}.
- */
-public class ValidateEndpointAuthenticationTest {
-    
-    ClientID clientId;
-    Secret clientSecret;
-    
-    URI endpointUri;
-    
-    RSAPrivateKey rsaPrivateKey;
-    RSAPublicKey rsaPublicKey;
-    
-    @BeforeClass
-    public void initKeys() throws NoSuchAlgorithmException {
-        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
-        keyGen.initialize(2048);
-        final KeyPair keyPair = keyGen.genKeyPair();
-        rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
-        rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
-    }
-    
-    @BeforeMethod
-    public void init() throws URISyntaxException {
-        clientId = new ClientID("mockId");
-        clientSecret = new Secret("secret1234567890secret1234567890secret1234567890");
-        endpointUri = new URI("https://mock.example.org/");
-    }
-    
-    protected RequestContext initializeRequestCtx(final TokenRequest request, 
-            final ClientAuthenticationMethod storedMethod, boolean sameSecret) throws Exception {
-        final RequestContext requestCtx = new RequestContextBuilder().setInboundMessage(request).buildRequestContext();
-
-        final ProfileRequestContext prc = new WebflowRequestContextProfileRequestContextLookup().apply(requestCtx);
-        
-        final OIDCMetadataContext oidcContext = new OIDCMetadataContext();
-        final OIDCClientMetadata metadata = new OIDCClientMetadata();
-        metadata.setTokenEndpointAuthMethod(storedMethod);
-        final Secret secret = sameSecret ? clientSecret : new Secret("WRONG1234567890secret1234567890secret1234567890");
-        if (storedMethod != null) {
-            BasicJWKCredential credential = null;
-            final OIDCSignatureValidationParameters params = new OIDCSignatureValidationParameters();
-            
-            if (storedMethod.equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
-                params.setSignatureAlgorithm("RS256");
-                credential = new BasicJWKCredential();
-                credential.setAlgorithm(JWSAlgorithm.parse("RS256"));
-                final RSAKey rsaKey;
-                if (sameSecret) {
-                    rsaKey = new RSAKey.Builder(rsaPublicKey).build();
-                } else {
-                    final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
-                    keyGen.initialize(1024);
-                    rsaKey = new RSAKey.Builder((RSAPublicKey)keyGen.genKeyPair().getPublic()).build();
-                }
-                credential.setPublicKey(rsaKey.toPublicKey());
-            } else if (storedMethod.equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
-                params.setSignatureAlgorithm("HS256");
-                credential = new BasicJWKCredential();
-                credential.setAlgorithm(JWSAlgorithm.parse("HS256"));
-                credential.setSecretKey(new SecretKeySpec(secret.getValueBytes(), "NONE"));
-            }
-            
-            if (credential != null) {
-                final SecurityParametersContext secCtx =
-                        (SecurityParametersContext) prc.addSubcontext(new SecurityParametersContext());
-                params.getValidationCredentials().add(credential);
-                secCtx.setSignatureSigningParameters(params);
-            }
-        }
-        final OIDCClientInformation clientInformation = 
-                new OIDCClientInformation(clientId, new Date(), metadata, secret);
-        oidcContext.setClientInformation(clientInformation);
-        prc.getInboundMessageContext().addSubcontext(oidcContext);
-        return requestCtx;
-    }
-    
-    protected TokenRequest initializeTokenRequest(final ClientAuthenticationMethod method) throws JOSEException {
-        final ClientAuthentication clientAuth;
-        if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) {
-            clientAuth = new ClientSecretBasic(clientId, clientSecret);
-        } else if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) {
-            clientAuth = new ClientSecretPost(clientId, clientSecret);
-        } else if (method.equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) {
-            clientAuth = new ClientSecretJWT(clientId, endpointUri, JWSAlgorithm.HS256, clientSecret);
-        } else if (method.equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
-            clientAuth = new PrivateKeyJWT(clientId, endpointUri, JWSAlgorithm.RS256, rsaPrivateKey, null, null);
-        } else {
-            clientAuth = null;
-        }
-        AuthorizationGrant authzGrant = new AuthorizationCodeGrant(new AuthorizationCode(), null);
-        return new TokenRequest(null, clientAuth, authzGrant);        
-    }
-    
-    protected ValidateEndpointAuthentication constructAction(final Function<ProfileRequestContext, 
-            Set<ClientAuthenticationMethod>> newFunction) throws ComponentInitializationException {
-        final ValidateEndpointAuthentication action = new ValidateEndpointAuthentication();
-        if (newFunction != null) {
-            action.setTokenEndpointAuthMethodsLookupStrategy(newFunction);
-        }
-        action.initialize();
-        return action;
-    }
-    
-    @Test
-    public void testNoEnabledMethods() throws Exception {
-        final ValidateEndpointAuthentication action = constructAction(null);
-        final Event event = 
-                action.execute(initializeRequestCtx(
-                        initializeTokenRequest(ClientAuthenticationMethod.CLIENT_SECRET_BASIC), null, true));
-        ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
-    }
-    
-    protected void testClientAuth(final ClientAuthenticationMethod clientAuth, final boolean success) throws Exception {
-        final ValidateEndpointAuthentication action = 
-                constructAction(new ListMethodsFunction(clientAuth));
-        final Event event = 
-                action.execute(initializeRequestCtx(
-                        initializeTokenRequest(clientAuth), clientAuth, success));
-        if (success) {
-            Assert.assertNull(event);
-        } else {
-            ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
-        }
-    }
-
-    protected void testSuccessClientAuth(final ClientAuthenticationMethod clientAuth) throws Exception {
-        testClientAuth(clientAuth, true);
-    }
-
-    protected void testFailingClientAuth(final ClientAuthenticationMethod clientAuth) throws Exception {
-        testClientAuth(clientAuth, false);
-    }
-    
-    @Test
-    public void testBasic() throws Exception {
-        testSuccessClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
-    }
-
-    @Test
-    public void testPost() throws Exception {
-        testSuccessClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_POST);
-    }
-
-    @Test
-    public void testSecretJwt() throws Exception {
-        testSuccessClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT);
-    }
-
-    @Test
-    public void testPrivateKeyJwt() throws Exception {
-        testSuccessClientAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
-    }
-
-    @Test
-    public void testFailingBasic() throws Exception {
-        testFailingClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
-    }
-
-    @Test
-    public void testFailingPost() throws Exception {
-        testFailingClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_POST);
-    }
-
-    @Test
-    public void testFailingSecretJwt() throws Exception {
-        testFailingClientAuth(ClientAuthenticationMethod.CLIENT_SECRET_JWT);
-    }
-
-    @Test
-    public void testFailingPrivateKeyJwt() throws Exception {
-        testFailingClientAuth(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
-    }
-
-    class ListMethodsFunction extends AbstractRelyingPartyLookupFunction<Set<ClientAuthenticationMethod>> {
-
-        private Set<ClientAuthenticationMethod> set;
-        
-        public ListMethodsFunction(ClientAuthenticationMethod... methods) {
-            set = Set.of(methods);
-        }
-        
-        @Override
-        public Set<ClientAuthenticationMethod> apply(ProfileRequestContext input) {
-            return set;
-        }
-    }
-
-}
\ 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