[java-idp-plugin-oidc-rp] branch main updated: Further flow test cleanups

Phil Smart philip.smart at jisc.ac.uk
Wed Feb 15 11:29:52 UTC 2023


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

philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=f9bca3dc44deceef450020387c69beccc1bc2015

The following commit(s) were added to refs/heads/main by this push:
     new f9bca3d  Further flow test cleanups
f9bca3d is described below

commit f9bca3dc44deceef450020387c69beccc1bc2015
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Feb 15 11:29:50 2023 +0000

    Further flow test cleanups
---
 ...MockAsymmetricJOSEObjectCredentialResolver.java |  60 +++
 .../OIDCRPFlowFromAuthenticationResponseTest.java  | 535 ++++++---------------
 .../oidc/rp/impl/OIDCRPFlowPreRedirectTest.java    |   2 +-
 .../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java  |  98 +++-
 .../plugin/authn/oidc/rp/impl/TestTokenHelper.java |   2 +-
 5 files changed, 308 insertions(+), 389 deletions(-)

diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockAsymmetricJOSEObjectCredentialResolver.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockAsymmetricJOSEObjectCredentialResolver.java
new file mode 100644
index 0000000..d81e93c
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/MockAsymmetricJOSEObjectCredentialResolver.java
@@ -0,0 +1,60 @@
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import org.opensaml.security.credential.Credential;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.jwk.AsymmetricJWK;
+
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Mock credential resolvers which builds a credential from the given key.*/
+public class MockAsymmetricJOSEObjectCredentialResolver implements JOSEObjectCredentialResolver {
+    
+    private final AsymmetricJWK key;
+    
+    private final String kid;
+    
+    private final JWEAlgorithm alg;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param keyIn the key rto create a credential for.
+     */
+    public MockAsymmetricJOSEObjectCredentialResolver(final AsymmetricJWK keyIn, final String kidIn, 
+            final JWEAlgorithm algIn) {
+        key = keyIn;
+        kid = kidIn;
+        alg = algIn;
+    }
+    
+    @Override
+    public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+        final BasicJWKCredential jwkCredential = new BasicJWKCredential();        
+        jwkCredential.setAlgorithm(alg);
+        jwkCredential.setKid(kid);                
+        try {
+            jwkCredential.setPrivateKey(key.toPrivateKey());
+            jwkCredential.setPublicKey(key.toPublicKey());
+        } catch (final JOSEException e) {
+            fail();
+        }                
+        return jwkCredential;
+    }
+
+    @Override
+    public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+        return List.of(resolveSingle(criteria));
+    }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowFromAuthenticationResponseTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowFromAuthenticationResponseTest.java
index 7bf0135..0a1a43c 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowFromAuthenticationResponseTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowFromAuthenticationResponseTest.java
@@ -9,20 +9,16 @@ import org.junit.Test;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.security.credential.BasicCredential;
-import org.opensaml.security.credential.Credential;
 import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 
 import com.nimbusds.jose.EncryptionMethod;
-import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWEAlgorithm;
 import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.JWSObject.State;
 import com.nimbusds.jose.jwk.Curve;
 import com.nimbusds.jose.jwk.KeyUse;
 import com.nimbusds.jose.jwk.RSAKey;
 import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
 import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
-import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ResponseType;
 import com.nimbusds.oauth2.sdk.id.ClientID;
 import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser;
@@ -31,28 +27,18 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.AccessTokenResponseContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.EndUserClaimsContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.context.UserInfoResponseContext;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.JWTUserInfoResponse;
-import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.PlainUserInfoResponse;
-import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
 import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
 import net.shibboleth.oidc.profile.config.JSONSecurityConfiguration;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
 import net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest;
-import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
-import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
 import net.shibboleth.oidc.security.credential.impl.BasicJOSEObjectCredentialResolver;
 import net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver;
 import net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver;
 import net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine;
 import net.shibboleth.oidc.security.jose.impl.BasicDecryptionConfiguration;
 import net.shibboleth.oidc.security.jose.impl.BasicSignatureValidationConfiguration;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-import net.shibboleth.utilities.java.support.resolver.ResolverException;
 import okhttp3.mockwebserver.MockResponse;
 import okhttp3.mockwebserver.MockWebServer;
 
@@ -62,14 +48,8 @@ import okhttp3.mockwebserver.MockWebServer;
  */
 public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     
-    /** 
-     * Test the flow from the external authorization request to the end of the flow.
-     * Using a MAC-signed id_token and plain UserInfo JSON Response.
-     * 
-     * @throws Exception on error.
-     */
-    @Test 
-    public void test_IDTokenHS256_PlainUserInfo() throws Exception {
+    /** Basic setup suitable for all tests.*/
+    private void basicSetup() {
         
         setFlowPath(FLOW);
         setFlowModelResources(flowResources);
@@ -80,55 +60,71 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
                 "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
         
         setMockProperties(mockProperties);
+    }
+    
+    /** Resume a flow using a default prc construction.*/
+    private ProfileRequestContext resumeBasicFlow() throws Exception {
         
-        final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createAccessTokenResponseJSON(
-                        OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
-                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null)));
-        // Second is plain userInfo
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID),"jdoe")));
-        mockOPServer.start(9918);
-        
-
         final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
                 .createFlowExecution(getFlowDefinition());
-        final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution); 
-                        
-        
-        updateFlowExecution(flowExecution);
+        final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution);                       
         
+        updateFlowExecution(flowExecution);        
         //set start view and ending event to transition on.
         externalContext.setEventId("proceed");
         setCurrentState("AuthnRequest");       
         resumeFlow(externalContext);
+        return prc;  
+    }
+    
+    /**
+     * Queue a mock response. Simulating a response from the OP.
+     * 
+     * @param mockOPServer the mock server
+     * @param code the response HTTP code
+     * @param body the response body
+     * @param contentType the content type header
+     */
+    private void queueMockServerResponse(final MockWebServer mockOPServer, final int code, 
+            final String body, final String contentType) {
+        mockOPServer.enqueue(new MockResponse().setResponseCode(code)
+                .setHeader("content-type", contentType)
+                .setBody(body));
+    }
+    
+    /** 
+     * Test the flow from the external authorization request to the end of the flow.
+     * Using a MAC-signed id_token and plain UserInfo JSON Response.
+     * 
+     * @throws Exception on error.
+     */
+    @Test 
+    public void test_IDTokenHS256_PlainUserInfo() throws Exception {
         
-        mockOPServer.shutdown();
+        basicSetup();
         
-        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);        
+        final MockWebServer mockOPServer = createSimpleServer();
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
+                OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
+                new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
+        final var userInfoResp = 
+                TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID),"jdoe");
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo
+        queueMockServerResponse(mockOPServer, 200, userInfoResp, "application/json");
+        mockOPServer.start(9918);
         
-        final var accessTokenResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
-        final var userInfoResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
-        final var endUserClaims = 
-                nestedPrc.getInboundMessageContext().getSubcontext(EndUserClaimsContext.class);
+        final var prc = resumeBasicFlow();        
+        mockOPServer.shutdown();        
         
-        assertNotNull(accessTokenResponse.getIdToken());
-        assertNotNull(userInfoResponse.getUserInfo());
-        assertTrue(userInfoResponse.getUserInfo() instanceof PlainUserInfoResponse);
-        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
-        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
-        assertEquals(signedJwt.getState(), State.VERIFIED);
+        // Assert test conditions
         
-        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());        
-        assertStandardEndUserClaimsSuccessCondition(endUserClaims.getEndUserClaims());
-       
-         
+        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc); 
+        
+        assertIdTokenSignatureAndClaimsVerified(nestedPrc);
+        assertPlainJSONObjectUserInfoToken(nestedPrc);
+        assertEndUserClaimsVerified(nestedPrc);         
     }
     
     /** 
@@ -140,56 +136,31 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     @Test 
     public void test_IDTokenHS256_InvalidPlainUserInfo() throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(   
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createAccessTokenResponseJSON(
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                         OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
-                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null)));
+                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
+        final var userInfoResp = 
+                TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID), null);
+        
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
         // Second is plain userInfo
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID), null)));
-        mockOPServer.start(9918);
+        queueMockServerResponse(mockOPServer, 200, userInfoResp, "application/json");
         
+        mockOPServer.start(9918);        
 
-        final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
-                .createFlowExecution(getFlowDefinition());
-        final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution); 
-                        
-        
-        updateFlowExecution(flowExecution);
-        
-        //set start view and ending event to transition on.
-        externalContext.setEventId("proceed");
-        setCurrentState("AuthnRequest");       
-        resumeFlow(externalContext);
+        final var prc = resumeBasicFlow();
         
         mockOPServer.shutdown();
         
-        assertFlowExecutionEnded();   
-        
-        final var nestedPrc = prc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class);        
-        final var accessTokenResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
-        
-        assertNotNull(accessTokenResponse.getIdToken());
-        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
-        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
-        assertEquals(signedJwt.getState(), State.VERIFIED);
-        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());        
+        // Assert test conditions
         
+        assertFlowExecutionEnded();         
+        assertIdTokenSignatureAndClaimsVerified(
+                prc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class));       
         // Should have failed to produce a result
         assertFlowEndedInErrorConditions(prc, "InvalidUserInfoClaims");  
     }
@@ -197,129 +168,74 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     @Test 
     public void test_IDTokenHS256_UserInfoHS256() throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/");
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createAccessTokenResponseJSON(
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                         OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
-                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null)));
-        // Second is userInfo        
-        final var userInfoToken = TestTokenHelper.createJWTUserInfoResponse(
+                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);     
+        final var userInfoResp = TestTokenHelper.createJWTUserInfoResponse(
                 OP_ISSUER_ID, List.of(CLIENT_ID), "jdoe", JWSAlgorithm.HS256, null, null, 
                 new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
         
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/jwt")
-                .setBody(userInfoToken.serialize()));
-        mockOPServer.start(9918);
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo
+        queueMockServerResponse(mockOPServer, 200, userInfoResp.serialize(), "application/jwt");
         
+        mockOPServer.start(9918);        
 
-        final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
-                .createFlowExecution(getFlowDefinition());
-        final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution);  
-                        
-        
-        updateFlowExecution(flowExecution);
-        
-        //set start view and ending event to transition on.
-        externalContext.setEventId("proceed");
-        setCurrentState("AuthnRequest");       
-        resumeFlow(externalContext);
+        final var prc = resumeBasicFlow();
         
         mockOPServer.shutdown();
         
-        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);        
-        
-        final var accessTokenResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
-        final var userInfoResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
-        final var endUserClaims = 
-                nestedPrc.getInboundMessageContext().getSubcontext(EndUserClaimsContext.class);
-        
-        assertNotNull(accessTokenResponse.getIdToken());
-        assertNotNull(userInfoResponse.getUserInfo());
-        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
-        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
-        assertEquals(signedJwt.getState(), State.VERIFIED);
-        
-        assertTrue(userInfoResponse.getUserInfo() instanceof JWTUserInfoResponse);
-        final var jwtUserInfoResponse = (JWTUserInfoResponse)(userInfoResponse.getUserInfo());
-        assertTrue(jwtUserInfoResponse.getResponseJwt() instanceof SignedJWT);
-        assertEquals(State.VERIFIED, ((SignedJWT)jwtUserInfoResponse.getResponseJwt()).getState());
-        
-        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());        
-        assertStandardEndUserClaimsSuccessCondition(endUserClaims.getEndUserClaims());   
+        // Assert test conditions
         
+        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);           
+        assertIdTokenSignatureAndClaimsVerified(nestedPrc);
+        assertUserInfoTokenSignatureVerified(nestedPrc);
+        assertEndUserClaimsVerified(nestedPrc);     
     }
     
     @Test 
     public void test_IDTokenHS256_DirA128CBC_HS256_UserInfoES256_RSA_OAEP_256A256GCM() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        
-        final var accessTokenResponseJson = TestTokenHelper.createAccessTokenResponseJSON(
+     
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                 OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, JWEAlgorithm.DIR, 
                 EncryptionMethod.A128CBC_HS256, 
                 new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), 
                 new DefaultClientSecretCredential(CLIENT_SECRET).toEncryptionCredential(
                         JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256));
-
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(accessTokenResponseJson));
-        // Second is userInfo      
+     
         final var sigKey = new ECKeyGenerator(Curve.P_256).keyID("123").generate();
         final RSAKey encKey = new RSAKeyGenerator(2048)
                 .keyID("1")
                 .keyUse(KeyUse.ENCRYPTION)
                 .generate();
-        final var userInfoToken = TestTokenHelper.createJWTUserInfoResponse(
+        final var userInfoResp = TestTokenHelper.createJWTUserInfoResponse(
                 OP_ISSUER_ID, List.of(CLIENT_ID), "jdoe", JWSAlgorithm.ES256, JWEAlgorithm.RSA_OAEP_256, 
                 EncryptionMethod.A256GCM, 
                 new BasicCredential(sigKey.toPublicKey(), sigKey.toPrivateKey()), 
                 new BasicCredential(encKey.toPublicKey(), encKey.toPrivateKey()));
         
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/jwt")
-                .setBody(userInfoToken.serialize()));
-        mockOPServer.start(9918);
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo
+        queueMockServerResponse(mockOPServer, 200, userInfoResp.serialize(), "application/jwt");
         
+        mockOPServer.start(9918);        
 
         final FlowExecutionImpl flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
                 .createFlowExecution(getFlowDefinition());
         
         final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution); 
         
-        final OIDCAuthorizationConfiguration partyConfig =
-                (OIDCAuthorizationConfiguration) prc.getSubcontext(AuthenticationContext.class)
-                    .getSubcontext(ProfileRequestContext.class)
-                    .getSubcontext(RelyingPartyContext.class)
-                    .getProfileConfig();
+        final OIDCAuthorizationConfiguration partyConfig = getRelyingPartyProfileConfig(prc);
         
         partyConfig.setClientCredential(
                 TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET));
@@ -333,27 +249,10 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         final var decryptConfig = new BasicDecryptionConfiguration();        
         decryptConfig.setContentEncryptionKeyCredentialResolver(
                 new ClientSecretCriterionCredentialResolver());
-       
-        decryptConfig.setKEKCredentialResolver(new JOSEObjectCredentialResolver() {
-            
-            @Override
-            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
-                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-                jwkCredential.setAlgorithm(JWEAlgorithm.RSA_OAEP_256);
-                jwkCredential.setKid(encKey.getKeyID());                
-                try {
-                    jwkCredential.setPrivateKey(encKey.toPrivateKey());
-                    jwkCredential.setPublicKey(encKey.toPublicKey());
-                } catch (final JOSEException e) {
-                    fail();
-                }                
-                return jwkCredential;
-            }            
-            @Override
-            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
-                return List.of(resolveSingle(criteria));
-            }
-        });      
+        
+        decryptConfig.setKEKCredentialResolver(
+                new MockAsymmetricJOSEObjectCredentialResolver(encKey, encKey.getKeyID(), JWEAlgorithm.RSA_OAEP_256));
+
         secConfig.setJwtDecryptionConfiguration(decryptConfig);    
         
         //Signature config for userinfo token
@@ -363,26 +262,9 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
                 new ExplicitKeySignedJWTTrustEngine(
                 new ChainingJOSEObjectCredentialResolver(List.of(
                         new ClientSecretCriterionCredentialResolver(),
-                new JOSEObjectCredentialResolver() {
-                    
-                    @Override
-                    public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
-                        final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-                        jwkCredential.setAlgorithm(JWEAlgorithm.RSA_OAEP_256);
-                        jwkCredential.setKid(sigKey.getKeyID());                
-                        try {
-                            jwkCredential.setPrivateKey(sigKey.toPrivateKey());
-                            jwkCredential.setPublicKey(sigKey.toPublicKey());
-                        } catch (final JOSEException e) {
-                            fail();
-                        }                
-                        return jwkCredential;
-                    }            
-                    @Override
-                    public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
-                        return List.of(resolveSingle(criteria));
-                    }
-                })), new BasicJOSEObjectCredentialResolver()));
+                        new MockAsymmetricJOSEObjectCredentialResolver(
+                                sigKey,sigKey.getKeyID(), JWEAlgorithm.RSA_OAEP_256)))
+                , new BasicJOSEObjectCredentialResolver()));
         
         secConfig.setJwtSignatureValidationConfiguration(sigValidation);  
         
@@ -397,29 +279,13 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         
         mockOPServer.shutdown();
         
-        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);        
-        
-        final var accessTokenResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
-        final var userInfoResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
-        final var endUserClaims = 
-                nestedPrc.getInboundMessageContext().getSubcontext(EndUserClaimsContext.class);
-        
-        assertNotNull(accessTokenResponse.getIdToken());
-        assertNotNull(userInfoResponse.getUserInfo());
-        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
-        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
-        assertEquals(signedJwt.getState(), State.VERIFIED);
-        
-        assertTrue(userInfoResponse.getUserInfo() instanceof JWTUserInfoResponse);
-        final var jwtUserInfoResponse = (JWTUserInfoResponse)(userInfoResponse.getUserInfo());
-        assertTrue(jwtUserInfoResponse.getResponseJwt() instanceof SignedJWT);
-        assertEquals(State.VERIFIED, ((SignedJWT)jwtUserInfoResponse.getResponseJwt()).getState());
-        
-        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());        
-        assertStandardEndUserClaimsSuccessCondition(endUserClaims.getEndUserClaims());   
-               
+        // Assert test conditions
+        
+        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);     
+        
+        assertIdTokenSignatureAndClaimsVerified(nestedPrc);
+        assertUserInfoTokenSignatureVerified(nestedPrc);
+        assertEndUserClaimsVerified(nestedPrc);                  
     }
     
     /**
@@ -431,37 +297,27 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     public void test_IDTokenHS256_RSA_OAEP_256_A256GCM_PlainUserInfo() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
+        basicSetup();
         
-        setMockProperties(mockProperties);
+        final MockWebServer mockOPServer = createSimpleServer();
         
         final RSAKey encKey = new RSAKeyGenerator(2048)
                 .keyID("1")
                 .keyUse(KeyUse.ENCRYPTION)
                 .generate();        
-        final var accessTokenResponseJson = TestTokenHelper.createAccessTokenResponseJSON(
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                 OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, JWEAlgorithm.RSA_OAEP_256, 
                 EncryptionMethod.A256GCM, 
                 new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), 
                 new BasicCredential(encKey.toPublicKey(), encKey.toPrivateKey()));
+
+        final var userInfoResp = 
+                TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID), "jdoe");
         
-        
-        final MockWebServer mockOPServer = createSimpleServer();
         // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(accessTokenResponseJson));
-        // Second is userInfo
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createPlainUserInfoResponseString(OP_ISSUER_ID, List.of(CLIENT_ID), "jdoe")));
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo
+        queueMockServerResponse(mockOPServer, 200, userInfoResp, "application/json");
         mockOPServer.start(9918);
         
 
@@ -470,11 +326,7 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         
         final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution);        
         
-        final OIDCAuthorizationConfiguration partyConfig =
-                (OIDCAuthorizationConfiguration) prc.getSubcontext(AuthenticationContext.class)
-                    .getSubcontext(ProfileRequestContext.class)
-                    .getSubcontext(RelyingPartyContext.class)
-                    .getProfileConfig();        
+        final OIDCAuthorizationConfiguration partyConfig = getRelyingPartyProfileConfig(prc);      
       
         final JSONSecurityConfiguration secConfig = new JSONSecurityConfiguration();
         
@@ -487,30 +339,11 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         secConfig.setJwtSignatureValidationConfiguration(sigValidation);   
         
         final var decryptConfig = new BasicDecryptionConfiguration();
-        decryptConfig.setKEKCredentialResolver(new JOSEObjectCredentialResolver() {
-            
-            @Override
-            public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
-                final BasicJWKCredential jwkCredential = new BasicJWKCredential();
-                jwkCredential.setAlgorithm(JWEAlgorithm.RSA_OAEP_256);
-                jwkCredential.setKid(encKey.getKeyID());                
-                try {
-                    jwkCredential.setPrivateKey(encKey.toPrivateKey());
-                    jwkCredential.setPublicKey(encKey.toPublicKey());
-                } catch (final JOSEException e) {
-                    fail();
-                }                
-                return jwkCredential;
-            }            
-            @Override
-            public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
-                return List.of(resolveSingle(criteria));
-            }
-        });
+        decryptConfig.setKEKCredentialResolver(
+                new MockAsymmetricJOSEObjectCredentialResolver(encKey,encKey.getKeyID(), JWEAlgorithm.RSA_OAEP_256));
 
         secConfig.setJwtDecryptionConfiguration(decryptConfig); 
         partyConfig.setSecurityConfiguration(secConfig);
-
                              
         updateFlowExecution(flowExecution);
         
@@ -521,31 +354,17 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         
         mockOPServer.shutdown();
         
-        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc);        
-        
-        final var accessTokenResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
-        final var userInfoResponse = 
-                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
-        final var endUserClaims = 
-                nestedPrc.getInboundMessageContext().getSubcontext(EndUserClaimsContext.class);
+        // Assert test conditions
         
-        assertNotNull(accessTokenResponse.getIdToken());
-        assertNotNull(userInfoResponse.getUserInfo());
-        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
-        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
-        assertEquals(signedJwt.getState(), State.VERIFIED);
-        
-        assertTrue(userInfoResponse.getUserInfo() instanceof PlainUserInfoResponse);      
-        
-        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());        
-        assertStandardEndUserClaimsSuccessCondition(endUserClaims.getEndUserClaims());  
-      
+        final var nestedPrc = assertStandardEndFlowSuccessConditions(prc); 
+        assertIdTokenSignatureAndClaimsVerified(nestedPrc);
+        assertPlainJSONObjectUserInfoToken(nestedPrc);
+        assertEndUserClaimsVerified(nestedPrc);      
        
     }
     
     /**
-     * Test a plain UserInfo JWT type. This can not happen, and should trigger an error.
+     * Test a plain UserInfo JWT type. This can not happen, and should trigger an error on signature validation.
      * 
      * @throws Exception on error.
      */
@@ -553,45 +372,26 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     public void test_IDTokenHS256_PlainJWTUserInfoResponse() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createAccessTokenResponseJSON(
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                         OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
-                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null)));
-        // Second is userInfo
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/jwt")
-                .setBody(TestTokenHelper.createPlainUserInfoResponseJSON(OP_ISSUER_ID,CLIENT_ID)
-                        .serialize()));
-        mockOPServer.start(9918);
-        
+                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
+        final var userInfoResp = 
+                TestTokenHelper.createPlainJWTUserInfoResponseJSON(OP_ISSUER_ID,CLIENT_ID)
+                        .serialize();        
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo (tell it is a JWT type when it is not)
+        queueMockServerResponse(mockOPServer, 200, userInfoResp, "application/jwt");
+        mockOPServer.start(9918);        
 
-        final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
-                .createFlowExecution(getFlowDefinition());
-        final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution);           
-        
-        updateFlowExecution(flowExecution);
-        
-        //set start view and ending event to transition on.
-        externalContext.setEventId("proceed");
-        setCurrentState("AuthnRequest");       
-        resumeFlow(externalContext);
+        final var prc = resumeBasicFlow();
         
         mockOPServer.shutdown();
         
+        // Assert test conditions
         assertFlowEndedInErrorConditions(prc, "InvalidMessage");
            
     }
@@ -600,30 +400,20 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     public void test_IDTokenHS256_UserInfoHS256_WithACRAMRTranslation() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/");
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final MockWebServer mockOPServer = createSimpleServer();
-        // First is token exchange
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/json")
-                .setBody(TestTokenHelper.createAccessTokenResponseJSON(
+        final var accessTokenResp = TestTokenHelper.createAccessTokenResponseJSON(
                         OP_ISSUER_ID, CLIENT_ID, List.of(CLIENT_ID), JWSAlgorithm.HS256, null, null, 
-                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null)));
-        // Second is userInfo
-        final var userInfoToken = TestTokenHelper.createJWTUserInfoResponse(
+                        new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
+        final var userInfoResp = TestTokenHelper.createJWTUserInfoResponse(
                 OP_ISSUER_ID, List.of(CLIENT_ID), "jdoe", JWSAlgorithm.HS256, null, null, 
                 new DefaultClientSecretCredential(CLIENT_SECRET).toSigningCredential(), null);
-        mockOPServer.enqueue(new MockResponse().setResponseCode(200)
-                .setHeader("content-type", "application/jwt")
-                .setBody(userInfoToken.serialize()));
+        
+        // First is token exchange
+        queueMockServerResponse(mockOPServer, 200, accessTokenResp, "application/json");
+        // Second is plain userInfo
+        queueMockServerResponse(mockOPServer, 200, userInfoResp.serialize(), "application/jwt");
         mockOPServer.start(9918);
         
 
@@ -643,6 +433,8 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         
         mockOPServer.shutdown();
         
+        // Assert test conditions
+        
         assertStandardEndFlowSuccessConditions(prc);  
         // Add checks for added ACRs and AMRs
         assertNotNull(prc.getSubcontext(SubjectCanonicalizationContext.class).getSubject()
@@ -662,15 +454,7 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     public void testUnsupportedOIDCFlow() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(  
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
-        
-        setMockProperties(mockProperties);
+        basicSetup();
         
         final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
                 .createFlowExecution(getFlowDefinition());
@@ -693,10 +477,6 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
         resumeFlow(externalContext);
   
         assertFlowEndedInErrorConditions(prc);
-        // Ensure flow did not produce an end-user message context
-        assertNull(prc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class)
-                .getInboundMessageContext().getSubcontext(EndUserClaimsContext.class));
-
     }
     
     /** 
@@ -709,16 +489,7 @@ public class OIDCRPFlowFromAuthenticationResponseTest extends OIDCRPFlowTest {
     public void testErrorAuthenticationResponse() 
             throws Exception {
         
-        setFlowPath(FLOW);
-        setFlowModelResources(flowResources);
-        setSubflows(subflows);        
-        
-        final Map<String,String> mockProperties = Map.of(
-                "idp.service.clientinfo.failFast","false",
-                "idp.entityID", "http://idp.example.com/",
-                "idp.authn.oidc.rp.provider.proxyIssuer",OP_ISSUER_ID);
-        
-        setMockProperties(mockProperties);
+        basicSetup();
 
         final FlowExecutionImpl flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
                 .createFlowExecution(getFlowDefinition());
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowPreRedirectTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowPreRedirectTest.java
index 763b084..3a8f6ab 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowPreRedirectTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowPreRedirectTest.java
@@ -25,7 +25,7 @@ import okhttp3.mockwebserver.MockResponse;
 import okhttp3.mockwebserver.MockWebServer;
 
 /**
- * RP Flow tests for flows actions that built the authentication request before being redirected to the OP. Uses
+ * RP Flow tests for flows actions that build the authentication request before being redirected to the OP. Uses
  * configuration from the loaded XML configuration files — unlike {@link OIDCRPFlowFromAuthenticationResponseTest}
  * which needs to build the configuration programatically because the initial seeding of the configuration only happens
  * pre-authn redirect. 
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index 8a71389..16e79ed 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -49,6 +49,7 @@ import org.springframework.webflow.engine.impl.FlowExecutionImpl;
 import org.springframework.webflow.test.MockFlowBuilderContext;
 
 import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.oauth2.sdk.ParseException;
 import com.nimbusds.oauth2.sdk.ResponseMode;
 import com.nimbusds.oauth2.sdk.ResponseType;
@@ -71,6 +72,8 @@ import net.shibboleth.idp.plugin.authn.oidc.rp.context.EndUserClaimsContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
 import net.shibboleth.idp.plugin.authn.oidc.rp.context.UserInfoResponseContext;
+import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.JWTUserInfoResponse;
+import net.shibboleth.idp.plugin.authn.oidc.rp.messaging.PlainUserInfoResponse;
 import net.shibboleth.idp.plugin.authn.oidc.rp.principal.OIDCSubjectIdentifierPrincipal;
 import net.shibboleth.idp.plugin.authn.test.flow.AbstractAuthnXmlFlowExecutionTests;
 import net.shibboleth.idp.plugin.authn.test.flow.mock.MockFlowBuilder;
@@ -484,6 +487,19 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
                 });
     }
     
+    /**
+     * Return the Profile configuration from the relying party context.
+     * 
+     * @param prc the prc
+     * @return the relying party configuration
+     */
+    protected OIDCAuthorizationConfiguration getRelyingPartyProfileConfig(final ProfileRequestContext prc) {
+        return (OIDCAuthorizationConfiguration) prc.getSubcontext(AuthenticationContext.class)
+                .getSubcontext(ProfileRequestContext.class)
+                .getSubcontext(RelyingPartyContext.class)
+                .getProfileConfig();
+    }
+    
     /**
      * Assert the basic set of conditions expected at the end of the entire authentication flow.
      * 
@@ -555,10 +571,13 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
             @Nonnull final String error) {
         
         assertFlowExecutionEnded();        
-        // No result
+        // No subject result
         assertNull(rootPrc.getSubcontext(SubjectCanonicalizationContext.class));
-        // Is there an authn result?
+        // No an authn result
         assertNull(rootPrc.getSubcontext(AuthenticationContext.class).getAuthenticationResult());
+        // Ensure flow did not produce an end-user message context
+        assertNull(rootPrc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class)
+                .getInboundMessageContext().getSubcontext(EndUserClaimsContext.class));
         
         assertPreviousEventContextError(rootPrc, error);
     }
@@ -571,10 +590,13 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
     protected void assertFlowEndedInErrorConditions(@Nonnull final ProfileRequestContext rootPrc) {
         
         assertFlowExecutionEnded();        
-        // No result
+        // No subject result
         assertNull(rootPrc.getSubcontext(SubjectCanonicalizationContext.class));
-        // Is there an authn result?
+        // No an authn result
         assertNull(rootPrc.getSubcontext(AuthenticationContext.class).getAuthenticationResult());
+        // Ensure flow did not produce an end-user message context
+        assertNull(rootPrc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class)
+                .getInboundMessageContext().getSubcontext(EndUserClaimsContext.class));
     }
     
     /**
@@ -642,6 +664,72 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
 
     }
     
-   
+    /**
+     * Assert the id_token exists, has had its signature verified, and the claims contained in the token are accurate.
+     * 
+     * @param nestedPrc the nested profile request context
+     * 
+     * @throws java.text.ParseException on error
+     */
+    protected void assertIdTokenSignatureAndClaimsVerified(final ProfileRequestContext nestedPrc) 
+            throws java.text.ParseException {
+        final var accessTokenResponse = 
+                nestedPrc.getInboundMessageContext().getSubcontext(AccessTokenResponseContext.class);
+        assertNotNull(accessTokenResponse.getIdToken());
+        assertTrue(accessTokenResponse.getIdToken() instanceof SignedJWT);
+        final var signedJwt = (SignedJWT) accessTokenResponse.getIdToken();
+        assertEquals(signedJwt.getState(), com.nimbusds.jose.JWSObject.State.VERIFIED);
+        assertStandardIdTokenClaimsSuccessCondition(signedJwt.getJWTClaimsSet());
+    }
+    
+    /**
+     * Assert the user info response JWT exists, and has had its signature verified.
+     * 
+     * @param nestedPrc the nested profile request context
+     * 
+     * @throws java.text.ParseException on error
+     */
+    protected void assertUserInfoTokenSignatureVerified(final ProfileRequestContext nestedPrc) 
+            throws java.text.ParseException {
+        final var userInfoResponse = 
+                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
+        assertNotNull(userInfoResponse.getUserInfo());
+        assertTrue(userInfoResponse.getUserInfo() instanceof JWTUserInfoResponse);
+        final var jwtResponse = (JWTUserInfoResponse) userInfoResponse.getUserInfo();
+        final var signedJwt = (SignedJWT) jwtResponse.getResponseJwt();
+        assertEquals(signedJwt.getState(), com.nimbusds.jose.JWSObject.State.VERIFIED);
+        
+    }
+    
+    /**
+     * Assert a plain JSON object user info response.
+     * 
+     * @param nestedPrc the nested profile request context
+     * 
+     * @throws java.text.ParseException on error
+     */
+    protected void assertPlainJSONObjectUserInfoToken(final ProfileRequestContext nestedPrc) 
+            throws java.text.ParseException {
+        final var userInfoResponse = 
+                nestedPrc.getInboundMessageContext().getSubcontext(UserInfoResponseContext.class);
+        assertNotNull(userInfoResponse.getUserInfo());
+        assertTrue(userInfoResponse.getUserInfo() instanceof PlainUserInfoResponse);
+        
+    }
+    
+    /**
+     * Assert end-user claims exist, and the claims are accurate.
+     * 
+     * @param nestedPrc the nested profile request context
+     * 
+     * @throws java.text.ParseException on error
+     */
+    protected void assertEndUserClaimsVerified(final ProfileRequestContext nestedPrc) 
+            throws java.text.ParseException {
+        final var endUserClaims = 
+                nestedPrc.getInboundMessageContext().getSubcontext(EndUserClaimsContext.class);
+        assertStandardEndUserClaimsSuccessCondition(endUserClaims.getEndUserClaims());        
+    }
+    
    
 }
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
index 7271d6c..59995ab 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
@@ -268,7 +268,7 @@ public final class TestTokenHelper {
      * @return the signed JWT
      * @throws JOSEException on error
      */
-    public static PlainJWT createPlainUserInfoResponseJSON(final String issuer, final String audience) 
+    public static PlainJWT createPlainJWTUserInfoResponseJSON(final String issuer, final String audience) 
             throws JOSEException {        
         
         final var payload = createBasicUserInfoClaims(issuer, List.of(audience), "jdoe");        

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list