[java-idp-oidc] 03/04: JOIDC-201 - Support for OAuth 2.0 Demonstrating Proof of Possession (DPoP)

Henri Mikkonen henri.mikkonen at iki.fi
Fri May 17 09:18:36 UTC 2024


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

hjmikkon pushed a commit to branch main
in repository java-idp-oidc.

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

commit a4f3f645330fdf4005f364a66028d7c293db200f
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri May 17 12:14:13 2024 +0300

    JOIDC-201 - Support for OAuth 2.0 Demonstrating Proof of Possession (DPoP)
    
    https://shibboleth.atlassian.net/browse/JOIDC-201
    
    - Require valid access token hash claim in DPoP proof within the UserInfo endpoint
      - user info flow test now covers the use of "ath"
    - Included "dpop_signing_alg_values_supported" claim in the OP metadata skeleton
---
 ...oPAccessTokenHashFromRequestLookupFunction.java | 100 +++++++++++++++++++
 .../idp/service/relying-party/postconfig.xml       |  26 ++++-
 .../oidc/op/static/openid-configuration.json       |   8 ++
 .../oidc/op/profile/flow/AbstractOidcFlowTest.java |  34 +++++--
 .../plugin/oidc/op/profile/flow/UserInfoTest.java  |  77 ++++++++++++++-
 ...cessTokenHashFromRequestLookupFunctionTest.java | 108 +++++++++++++++++++++
 6 files changed, 342 insertions(+), 11 deletions(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunction.java
new file mode 100644
index 00000000..aec6711c
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunction.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed 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.logic;
+
+import java.util.Enumeration;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.util.Base64URL;
+import com.nimbusds.oauth2.sdk.ParseException;
+import com.nimbusds.oauth2.sdk.dpop.DPoPUtils;
+import com.nimbusds.oauth2.sdk.token.DPoPAccessToken;
+
+import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * A function that calculates a hash of the DPoP access token from the {@link HttpServletRequest} if found.
+ * 
+ * @since 4.2.0
+ */
+public class DPoPAccessTokenHashFromRequestLookupFunction extends AbstractIdentifiableInitializableComponent
+    implements Function<ProfileRequestContext, String> {
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DPoPAccessTokenHashFromRequestLookupFunction.class);
+
+    /** Supplier for the {@link HttpServletRequest}. */
+    @NonnullAfterInit private Supplier<HttpServletRequest> httpServletRequestSupplier;
+
+    /**
+     * Set the supplier for the {@link HttpServletRequest}.
+     * 
+     * @param strategy What to set.
+     */
+    public void setHttpServletRequestSupplier(final @Nonnull Supplier<HttpServletRequest> supplier) {
+        httpServletRequestSupplier = Constraint.isNotNull(supplier, "Http servlet request supplier cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        if (httpServletRequestSupplier == null) {
+            throw new ComponentInitializationException("Http servlet request supplier cannot be null");
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override @Nullable
+    public String apply(final @Nullable ProfileRequestContext input) {
+        checkComponentActive();
+        final HttpServletRequest httpServletRequest = httpServletRequestSupplier.get();
+        if (httpServletRequest == null) {
+            return null;
+        }
+        final Enumeration<String> authorizationHeaders = httpServletRequest.getHeaders("Authorization");
+        if (authorizationHeaders == null) {
+            return null;
+        }
+        while (authorizationHeaders.hasMoreElements()) {
+            try {
+                final DPoPAccessToken token = DPoPAccessToken.parse(authorizationHeaders.nextElement());
+                if (token != null) {
+                    final Base64URL hash = DPoPUtils.computeSHA256(token);
+                    if (hash != null) {
+                        return hash.toString();
+                    }
+                }
+            } catch (final ParseException e) {
+                // ignore, could not parse the DPoPAccessToken
+            } catch (final JOSEException e) {
+                log.warn("Could not compute SHA256 hash for the DPoP access token", e);
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index 2e3faf09..03a5e6d5 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -27,7 +27,7 @@
         p:deniedUserInfoAttributes="%{idp.oidc.deniedUserInfoAttributes:}"
         p:issuedClaimsValidator-ref="DefaultUserInfoJWTClaimsValidator"
         p:unregisteredClientPolicy="#{getObject('shibboleth.oidc.DefaultUnregisteredClientPolicy')}"
-        p:dpopProofClaimsValidator-ref="DefaultDPoPProofClaimsValidator"
+        p:dpopProofClaimsValidator-ref="DefaultUserInfoDPoPProofClaimsValidator"
         p:dpopProofSignatureValidationConfiguration-ref="DPoPSignatureValidationConfiguration" />
         
     <bean id="OIDC.Registration" parent="AbstractOIDCProfile" lazy-init="true"
@@ -422,7 +422,7 @@
         <property name="dpopProofClaimsValidatorLookupStrategy">
             <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="dpopProofClaimsValidator"
                 p:propertyType="#{T(net.shibboleth.oidc.jwt.claims.ClaimsValidator)}"
-                p:defaultValue-ref="DefaultDPoPProofClaimsValidator" />
+                p:defaultValue-ref="DefaultUserInfoDPoPProofClaimsValidator" />
         </property>
         <property name="dpopProofSignatureValidationConfigurationLookupStrategy">
             <bean parent="shibboleth.MDDrivenBeanProperty" p:propertyName="dpopProofSignatureValidationConfiguration"
@@ -1000,6 +1000,10 @@
         class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
         p:claimValidators-ref="DPoPProofClaimsValidators" />
 
+    <bean id="DefaultUserInfoDPoPProofClaimsValidator"
+        class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
+        p:claimValidators-ref="UserInfoDPoPProofClaimsValidators" />
+
     <util:list id="DPoPProofClaimsValidators" value-type="net.shibboleth.oidc.jwt.claims.ClaimsValidator">
         <ref bean="ExpiryClaimsValidator" />
         <ref bean="NotBeforeClaimsValidator" />
@@ -1022,4 +1026,22 @@
         </bean>
     </util:list>
 
+    <bean id="UserInfoDPoPProofClaimsValidators" parent="DPoPProofClaimsValidators"
+        class="org.springframework.beans.factory.config.ListFactoryBean">
+        <property name="sourceList">
+            <list merge="true">
+                <bean class="net.shibboleth.oidc.security.jwt.claims.impl.ExactMatchClaimsValidator" p:claimName="ath">
+                    <property name="valueToMatchLookupStrategy">
+                        <bean parent="shibboleth.BiFunctions.Expression" c:expression="#custom.apply(null)">
+                            <property name="customObject">
+                                <bean class="net.shibboleth.idp.plugin.oidc.op.profile.logic.DPoPAccessTokenHashFromRequestLookupFunction"
+                                    p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"/>
+                            </property>
+                        </bean>
+                    </property>
+                </bean>
+            </list>
+        </property>
+    </bean>
+
 </beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
index 7276dbe2..d0270d5b 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/static/openid-configuration.json
@@ -84,6 +84,14 @@
       "ES384",
       "ES512"
    ],
+   "dpop_signing_alg_values_supported":[
+      "RS256",
+      "RS384",
+      "RS512",
+      "ES256",
+      "ES384",
+      "ES512"
+   ],
    "token_endpoint_auth_methods_supported":[
       "client_secret_basic",
       "client_secret_post",
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
index ae0d9885..a290d890 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/AbstractOidcFlowTest.java
@@ -84,6 +84,7 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
 import com.nimbusds.oauth2.sdk.dpop.DPoPProofFactory;
 import com.nimbusds.oauth2.sdk.dpop.DefaultDPoPProofFactory;
 import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.oauth2.sdk.token.AccessToken;
 import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
 import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
@@ -604,18 +605,37 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
     }
 
     protected static SignedJWT buildDPoPProof(final String method, final String uri) {
+        return buildDPoPProof(method, uri, null);
+    }
+
+    protected static SignedJWT buildDPoPProof(final String method, final String uri, final AccessToken accessToken) {
+        return buildDPoPProof(defaultDPoPProofKey(), JWSAlgorithm.ES256, method, uri, accessToken);
+    }
+
+    protected static SignedJWT buildDPoPProof(final JWK jwk, final JWSAlgorithm alg, final String method,
+            final String uri, final AccessToken accessToken) {
         try {
-            ECKey jwk = new ECKeyGenerator(Curve.P_256)
-                    .keyID("1")
-                    .generate();
-            DPoPProofFactory proofFactory = new DefaultDPoPProofFactory(
-                    jwk,
-                    JWSAlgorithm.ES256);
-            return proofFactory.createDPoPJWT(method, new URI(uri));
+            DPoPProofFactory proofFactory = new DefaultDPoPProofFactory(jwk, alg);
+            if (accessToken == null) {
+                return proofFactory.createDPoPJWT(method, new URI(uri));
+            } else {
+                return proofFactory.createDPoPJWT(method, new URI(uri), accessToken);
+            }
         } catch (JOSEException | URISyntaxException e) {
             Assert.fail("Could not create DPoP proof", e);
         }
         return null;
+
     }
 
+    protected static ECKey defaultDPoPProofKey() {
+        try {
+            return new ECKeyGenerator(Curve.P_256)
+                    .keyID("1")
+                    .generate();
+        } catch (JOSEException e) {
+            Assert.fail("Could not initialize DPoP proof key", e);
+        }
+        return null;
+    }
 }
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
index 2ae1705b..8a73e8b8 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/UserInfoTest.java
@@ -35,6 +35,7 @@ import org.testng.annotations.Test;
 
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.ECKey;
 import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
@@ -316,7 +317,7 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
 
     @SuppressWarnings("null")
     @Test
-    public void testSuccessOnlySubjectWithDPoPNoAudience() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+    public void testFailWithDPoP_noAth() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
         ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
         final SignedJWT dpopProof = buildDPoPProof("POST", "http://localhost/idp/profile/oidc/userinfo");
         final AccessTokenClaimsSet claims =
@@ -325,6 +326,42 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
         final DPoPAccessToken token = new DPoPAccessToken(claims.serialize(getDataSealer()));
         request.addHeader("DPoP", dpopProof.serialize());
 
+        storeMetadata(storageService, clientId, "mockSecret", scope);
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_DPOP_PROOF_CODE);
+    }
+
+    @SuppressWarnings("null")
+    @Test
+    public void testFailWithDPoP_nonMatchingAth() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
+        final SignedJWT dpopProof = buildDPoPProof("POST", "http://localhost/idp/profile/oidc/userinfo", new DPoPAccessToken("mock"));
+        final AccessTokenClaimsSet claims =
+                buildDPoPAccessTokenClaimsSet((dpopProof.getHeader().getJWK().computeThumbprint().toString()));
+
+        final DPoPAccessToken token = new DPoPAccessToken(claims.serialize(getDataSealer()));
+        request.addHeader("DPoP", dpopProof.serialize());
+
+        storeMetadata(storageService, clientId, "mockSecret", scope);
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_DPOP_PROOF_CODE);
+    }
+
+    @SuppressWarnings("null")
+    @Test
+    public void testSuccessOnlySubjectWithDPoP() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
+        final ECKey dpopProofKey = defaultDPoPProofKey();
+        final AccessTokenClaimsSet claims =
+                buildDPoPAccessTokenClaimsSet(dpopProofKey.computeThumbprint().toString());
+
+        final DPoPAccessToken token = new DPoPAccessToken(claims.serialize(getDataSealer()));
+        final SignedJWT dpopProof = buildDPoPProof(dpopProofKey, JWSAlgorithm.ES256, "POST",
+                "http://localhost/idp/profile/oidc/userinfo", token);
+        request.addHeader("DPoP", dpopProof.serialize());
+
         storeMetadata(storageService, clientId, "mockSecret", scope);
         request.addHeader("Authorization", getTokenHeaderValue(token));
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -339,7 +376,7 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
 
     @SuppressWarnings("null")
     @Test
-    public void testSuccessOnlySubjectWithDPoPJWTNoAudience() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+    public void testFailWithJWTDPoP_noAth() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
         ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
         final SignedJWT dpopProof = buildDPoPProof("POST", "http://localhost/idp/profile/oidc/userinfo");
         final AccessTokenClaimsSet claims =
@@ -348,6 +385,42 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
         final DPoPAccessToken token = buildJWTDPoPToken(claims, signingKey.getPrivateKey(), "RS256");
         request.addHeader("DPoP", dpopProof.serialize());
 
+        storeMetadata(storageService, clientId, "mockSecret", scope);
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_DPOP_PROOF_CODE);
+    }
+
+    @SuppressWarnings("null")
+    @Test
+    public void testFailWithJWTDPoP_nonMatchingAth() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
+        final SignedJWT dpopProof = buildDPoPProof("POST", "http://localhost/idp/profile/oidc/userinfo", new DPoPAccessToken("mock"));
+        final AccessTokenClaimsSet claims =
+                buildDPoPAccessTokenClaimsSet((dpopProof.getHeader().getJWK().computeThumbprint().toString()));
+
+        final DPoPAccessToken token = buildJWTDPoPToken(claims, signingKey.getPrivateKey(), "RS256");
+        request.addHeader("DPoP", dpopProof.serialize());
+
+        storeMetadata(storageService, clientId, "mockSecret", scope);
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, OAuth2Error.INVALID_DPOP_PROOF_CODE);
+    }
+
+    @SuppressWarnings("null")
+    @Test
+    public void testSuccessOnlySubjectWithDPoPJWTNoAudience() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException, com.nimbusds.oauth2.sdk.ParseException, JOSEException {
+        final ECKey dpopProofKey = defaultDPoPProofKey();
+        final AccessTokenClaimsSet claims =
+                buildDPoPAccessTokenClaimsSet(dpopProofKey.computeThumbprint().toString());
+
+        final DPoPAccessToken token = buildJWTDPoPToken(claims, signingKey.getPrivateKey(), "RS256");
+        final SignedJWT dpopProof = buildDPoPProof(dpopProofKey, JWSAlgorithm.ES256, "POST",
+                "http://localhost/idp/profile/oidc/userinfo", token);
+        request.addHeader("DPoP", dpopProof.serialize());
+
         storeMetadata(storageService, clientId, "mockSecret", scope);
         request.addHeader("Authorization", getTokenHeaderValue(token));
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunctionTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunctionTest.java
new file mode 100644
index 00000000..caa603d7
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DPoPAccessTokenHashFromRequestLookupFunctionTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed 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.logic;
+
+import java.util.function.Supplier;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.oauth2.sdk.dpop.DPoPUtils;
+import com.nimbusds.oauth2.sdk.token.DPoPAccessToken;
+
+import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.component.UninitializedComponentException;
+import net.shibboleth.shared.primitive.NonnullSupplier;
+
+/**
+ * Unit tests for {@link DPoPAccessTokenHashFromRequestLookupFunction}.
+ */
+public class DPoPAccessTokenHashFromRequestLookupFunctionTest {
+
+    DPoPAccessTokenHashFromRequestLookupFunction function;
+
+    @Test(expectedExceptions = ComponentInitializationException.class)
+    public void testNoSupplier() throws ComponentInitializationException {
+        function = new DPoPAccessTokenHashFromRequestLookupFunction();
+        function.setId("mockId");
+        function.initialize();
+    }
+
+    @Test(expectedExceptions = UninitializedComponentException.class)
+    public void testNotInitialized(){
+        function = new DPoPAccessTokenHashFromRequestLookupFunction();
+        function.setHttpServletRequestSupplier(new Supplier<>() {
+
+            @Override
+            public HttpServletRequest get() {
+                return null;
+            }
+            
+        });
+        function.apply(null);
+    }
+
+    @Test
+    public void testNoValues() {
+        function = initWithSupplier();
+        Assert.assertNull(function.apply(null));
+    }
+
+    @Test
+    public void testOneValue() throws JOSEException {
+        function = initWithSupplier("DPoP mock");
+        Assert.assertEquals(function.apply(null), DPoPUtils.computeSHA256(new DPoPAccessToken("mock")).toString());
+    }
+
+    @Test
+    public void testOneBearerValue() {
+        function = initWithSupplier("Bearer mock");
+        Assert.assertNull(function.apply(null));
+    }
+
+    @Test
+    public void testMultioleValues() throws JOSEException {
+        function = initWithSupplier("Bearer mock1", "DPoP mock2");
+        Assert.assertEquals(function.apply(null), DPoPUtils.computeSHA256(new DPoPAccessToken("mock2")).toString());
+    }
+
+    protected DPoPAccessTokenHashFromRequestLookupFunction initWithSupplier(final String... values) {
+        final NonnullSupplier<HttpServletRequest> supplier = new NonnullSupplier<>() {
+
+            @Override
+            public HttpServletRequest get() {
+                final MockHttpServletRequest httpRequest = new MockHttpServletRequest();
+                for (final String value : values) {
+                    assert value != null;
+                    httpRequest.addHeader("Authorization", value);
+                }
+                return httpRequest;
+            }
+            
+        };
+        function = new DPoPAccessTokenHashFromRequestLookupFunction();
+        function.setHttpServletRequestSupplier(supplier);
+        function.setId("mockId");
+        try {
+            function.initialize();
+        } catch (ComponentInitializationException e) {
+            Assert.fail();
+        }
+        return function;
+    }
+}

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


More information about the commits mailing list