[java-idp-oidc] branch dev/JOIDC-226 updated: JOIDC-226 - Autoconfigure CORS for public OIDC clients

Codeberg noreply at shibboleth.net
Thu Nov 20 14:14:31 UTC 2025


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

codeberg pushed a commit to branch dev/JOIDC-226
in repository java-idp-oidc.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-oidc/commit/67c465aa21c0a559f195ec394997e362b54c53ca

The following commit(s) were added to refs/heads/dev/JOIDC-226 by this push:
     new 67c465aa JOIDC-226 - Autoconfigure CORS for public OIDC clients
67c465aa is described below

commit 67c465aa21c0a559f195ec394997e362b54c53ca
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Nov 20 16:13:47 2025 +0200

    JOIDC-226 - Autoconfigure CORS for public OIDC clients
    
    https://shibboleth.atlassian.net/browse/JOIDC-226
    
    Initial implementation, WIP
    - Wired a new ValidateOriginHeader action into most of the API-flows: par, token, userinfo, introspection and revocation
      - The default validation (DefaultOriginHeaderValidationPredicate) is against the registered redirect URIs (some of them must start with origin-header + "/"
      - The action publishes InvalidOriginHeader event if the validation fails
        - The base action (AbstractBuildErrorResponseFromEvent) for endpoint-specific error messages supports mappedResponsesLookupStrategy to map the event into pre-defined response
        - Default implementation shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy can be overridden per flow
        - Default response is similar to Spring's "Invalid CORS request" -response
---
 .../impl/DefaultInvalidOriginErrorResponse.java    |  68 +++++++++++
 .../oauth2/profile/impl/ValidateOriginHeader.java  | 124 +++++++++++++++++++++
 .../impl/AbstractBuildErrorResponseFromEvent.java  |  32 ++++++
 .../DefaultOriginHeaderValidationPredicate.java    |  62 +++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  14 +++
 .../oauth2/introspection/introspection-beans.xml   |   1 +
 .../oauth2/introspection/introspection-flow.xml    |   1 +
 .../pushed-authorization-beans.xml                 |   1 +
 .../pushed-authorization-flow.xml                  |   1 +
 .../flows/oauth2/revocation/revocation-beans.xml   |   1 +
 .../flows/oauth2/revocation/revocation-flow.xml    |   1 +
 .../flows/oidc/abstract/oidc-abstract-beans.xml    |   4 +
 .../idp/flows/oidc/token/token-beans.xml           |   1 +
 .../shibboleth/idp/flows/oidc/token/token-flow.xml |   1 +
 .../idp/flows/oidc/userinfo/userinfo-beans.xml     |   1 +
 .../idp/flows/oidc/userinfo/userinfo-flow.xml      |   1 +
 .../oidc/op/profile/flow/AbstractOidcFlowTest.java |  12 +-
 .../op/profile/flow/IntrospectionFlowTest.java     |  40 +++++++
 .../op/profile/flow/PushedAuthorizeFlowTest.java   |  28 +++++
 .../oidc/op/profile/flow/RevocationFlowTest.java   |  33 ++++++
 .../plugin/oidc/op/profile/flow/TokenFlowTest.java |  34 ++++++
 .../plugin/oidc/op/profile/flow/UserInfoTest.java  |  27 +++++
 22 files changed, 487 insertions(+), 1 deletion(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/impl/DefaultInvalidOriginErrorResponse.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/impl/DefaultInvalidOriginErrorResponse.java
new file mode 100644
index 00000000..74e2c21c
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/messaging/impl/DefaultInvalidOriginErrorResponse.java
@@ -0,0 +1,68 @@
+/*
+ * 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.messaging.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import com.nimbusds.oauth2.sdk.Response;
+import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * A Nimbus {@link Response} implementation representing an error response related to invalid Origin-header in request.
+ */
+public class DefaultInvalidOriginErrorResponse implements Response {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(DefaultInvalidOriginErrorResponse.class);
+
+    /** The error message body contents. */
+    @Nullable private final String contents;
+
+    /**
+     * Constructor with default (null) body contents.
+     */
+    public DefaultInvalidOriginErrorResponse() {
+        this(null);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param body error message contents.
+     */
+    public DefaultInvalidOriginErrorResponse(@Nonnull @ParameterName(name = "body") final String body) {
+        contents = body;
+    }
+
+    /** {@inheritDoc} */
+    public boolean indicatesSuccess() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public HTTPResponse toHTTPResponse() {
+        final HTTPResponse response = new HTTPResponse(HTTPResponse.SC_FORBIDDEN);
+        if (contents != null) {
+            response.setContent(contents);
+        }
+        return response;
+    }
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateOriginHeader.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateOriginHeader.java
new file mode 100644
index 00000000..8a41359f
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/ValidateOriginHeader.java
@@ -0,0 +1,124 @@
+/*
+ * 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.oauth2.profile.impl;
+
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.logic.DefaultOriginHeaderValidationPredicate;
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Validates the possibly existing Origin-header via a configurable validator.
+ * 
+ * @since 4.4.0
+ */
+public class ValidateOriginHeader extends AbstractProfileAction {
+
+    /** Event identifier for invalid origin header. */
+    public static final String EVENT_ID_INVALID_ORIGIN_HEADER = "InvalidOriginHeader";
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ValidateOriginHeader.class);
+
+    /** Strategy used to locate the Origin -header value. */
+    @Nonnull private Function<ProfileRequestContext, String> originHeaderLookupStrategy;
+
+    /** Enforcer function for validating client ID against the configured policy. */
+    @Nonnull private Function<ProfileRequestContext, BiPredicate<ProfileRequestContext, String>>
+        originHeaderValidatorLookupStrategy;
+
+    /** The Origin -header value to be validated. */
+    @NonnullBeforeExec private String origin;
+
+    /** The validator for the Origin -header value. */
+    @NonnullBeforeExec private BiPredicate<ProfileRequestContext, String> originValidator;
+
+    /** Constructor. */
+    public ValidateOriginHeader() {
+        originHeaderLookupStrategy = prc -> getHttpServletRequest().getHeader("Origin");
+        originHeaderValidatorLookupStrategy = FunctionSupport.constant(new DefaultOriginHeaderValidationPredicate());
+    }
+
+    /**
+     * Set the strategy used to locate the Origin -header value.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setOriginHeaderLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+        checkSetterPreconditions();
+
+        originHeaderLookupStrategy =
+                Constraint.isNotNull(strategy, "OriginHeaderLookupStrategy cannot be null");
+    }
+
+    /**
+     * Set the strategy used to locate the validator for the Origin -header value.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setOriginHeaderValidatorLookupStrategy(
+            final Function<ProfileRequestContext, BiPredicate<ProfileRequestContext, String>> strategy) {
+        checkSetterPreconditions();
+
+        originHeaderValidatorLookupStrategy = Constraint.isNotNull(strategy,
+                "OriginHeaderValidatorLookupStrategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+
+        origin = StringSupport.trimOrNull(originHeaderLookupStrategy.apply(profileRequestContext));
+        if (origin == null) {
+            log.trace("{} No Origin-header resolved, nothing to do", getLogPrefix());
+            return false;
+        }
+
+        originValidator = originHeaderValidatorLookupStrategy.apply(profileRequestContext);
+        if (originValidator == null) {
+            log.error("{} No validator for the Origin-header resolved, nothing to do", getLogPrefix());
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        if (!originValidator.test(profileRequestContext, origin)) {
+            log.warn("{} Origin {} did not pass the validation", getLogPrefix(), origin);
+            ActionSupport.buildEvent(profileRequestContext, EVENT_ID_INVALID_ORIGIN_HEADER);
+            return;
+        }
+        log.debug("{} Successfully validated origin {}", getLogPrefix(), origin);
+    }
+
+}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractBuildErrorResponseFromEvent.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractBuildErrorResponseFromEvent.java
index db1a7d18..a0493b50 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractBuildErrorResponseFromEvent.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/AbstractBuildErrorResponseFromEvent.java
@@ -30,12 +30,14 @@ import org.slf4j.Logger;
 
 import com.nimbusds.oauth2.sdk.ErrorObject;
 import com.nimbusds.oauth2.sdk.ErrorResponse;
+import com.nimbusds.oauth2.sdk.Response;
 import com.nimbusds.oauth2.sdk.http.HTTPResponse;
 
 import net.shibboleth.idp.plugin.oidc.op.profile.EventIdToErrorObjectMapping;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 
 /**
@@ -63,6 +65,9 @@ public abstract class AbstractBuildErrorResponseFromEvent<T extends ErrorRespons
     @Nonnull
     private Function<ProfileRequestContext, EventContext> eventContextLookupStrategy;
 
+    /** Strategy function for locating the map of eventIds to pre-configured response messages. */
+    @Nonnull private Function<ProfileRequestContext, Map<String, Response>> mappedResponsesLookupStrategy;
+
     /** Map of eventIds to pre-configured error objects. */
     private Map<String, ErrorObject> mappedErrors;
 
@@ -82,6 +87,7 @@ public abstract class AbstractBuildErrorResponseFromEvent<T extends ErrorRespons
      */
     public AbstractBuildErrorResponseFromEvent(@Nullable final Collection<M> freeObjects) {
         eventContextLookupStrategy = new CurrentOrPreviousEventLookup();
+        mappedResponsesLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyMap());
         mappedErrors = new HashMap<>();
         defaultStatusCode = DEFAULT_HTTP_STATUS_CODE;
         defaultCode = DEFAULT_ERROR_CODE;
@@ -118,6 +124,21 @@ public abstract class AbstractBuildErrorResponseFromEvent<T extends ErrorRespons
         eventContextLookupStrategy = Constraint.isNotNull(strategy, "EventContext lookup strategy cannot be null");
     }
 
+    /**
+     * Set strategy function for locating the map of eventIds to pre-configured response messages.
+     * 
+     * @param strategy lookup strategy
+     * 
+     * @since 4.4.0
+     */
+    public void setMappedResponsesLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, Map<String, Response>> strategy) {
+        ifInitializedThrowUnmodifiabledComponentException();
+
+        mappedResponsesLookupStrategy =
+                Constraint.isNotNull(strategy, "MappedResponses lookup strategy cannot be null");
+    }
+
     /**
      * Set map of eventIds to pre-configured error objects.
      * 
@@ -167,6 +188,17 @@ public abstract class AbstractBuildErrorResponseFromEvent<T extends ErrorRespons
         final Object event = eventCtx.getEvent();
         assert event != null;
         final String eventValue = event.toString();
+        final Map<String, Response> mappedResponses = mappedResponsesLookupStrategy.apply(profileRequestContext);
+        if (mappedResponses != null && mappedResponses.containsKey(eventValue)) {
+            final Response mappedResponse = mappedResponses.get(eventValue);
+            if (mappedResponse == null) {
+                log.warn("{} Ignoring null response specified for event {}", getLogPrefix(), eventValue);
+            } else {
+                log.debug("{} Found mapped response message for event {}", getLogPrefix(), eventValue);
+                profileRequestContext.ensureOutboundMessageContext().setMessage(mappedResponse);
+                return;
+            }
+        }
         final ErrorObject error;
         if (mappedErrors.containsKey(eventValue)) {
             log.debug("{} Found mapped event for {}", getLogPrefix(), eventValue);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultOriginHeaderValidationPredicate.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultOriginHeaderValidationPredicate.java
new file mode 100644
index 00000000..b4f8ab8c
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultOriginHeaderValidationPredicate.java
@@ -0,0 +1,62 @@
+/*
+ * 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.net.URI;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultValidRedirectUrisLookupFunction;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Default validation strategy for the Origin -header. This checks if any of the valid URIs fetched via lookup strategy
+ * starts with the Origin-value given in the input parameters.
+ * 
+ * @since 4.4.0
+ */
+public class DefaultOriginHeaderValidationPredicate implements BiPredicate<ProfileRequestContext, String> {
+
+    /** Strategy used to obtain the redirect uris to compare request value to. */
+    @Nonnull private Function<ProfileRequestContext, Set<URI>> validRedirectURIsLookupStrategy;
+
+    /**
+     * Constructor.
+     */
+    public DefaultOriginHeaderValidationPredicate() {
+        validRedirectURIsLookupStrategy = new DefaultValidRedirectUrisLookupFunction();
+    }
+    
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext profileRequestContext, @Nullable final String origin) {
+        if (StringSupport.trimOrNull(origin) == null) {
+            return false;
+        }
+        return Optional.ofNullable(validRedirectURIsLookupStrategy.apply(profileRequestContext))
+                .map(set -> set.stream()
+                        .map(uri -> uri.toString())
+                        .map(uri -> uri.endsWith("/") ? uri : uri.concat("/"))
+                        .anyMatch(uri -> uri.startsWith(origin)))
+                .orElse(false);
+    }
+
+}
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index cd6daefd..b2b716b3 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -965,4 +965,18 @@
    <bean id="DefaultMetadataSkeleton" class="org.springframework.core.io.FileSystemResource" lazy-init="true"
        c:path="%{idp.oidc.discovery.template:%{idp.home}/static/openid-configuration.json}" />
 
+    <bean id="shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy" parent="shibboleth.Functions.Constant">
+        <constructor-arg name="target">
+            <util:map id="shibboleth.oidc.DefaultMappedErrorResponses" value-type="com.nimbusds.oauth2.sdk.Response">
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateOriginHeader.EVENT_ID_INVALID_ORIGIN_HEADER"/>
+                    </key>
+                    <bean class="net.shibboleth.idp.plugin.oidc.op.messaging.impl.DefaultInvalidOriginErrorResponse"
+                        c:body="Invalid CORS request"/>
+                </entry>
+            </util:map>
+        </constructor-arg>
+    </bean>
+
 </beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
index a6e3d194..fe0a39be 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-beans.xml
@@ -55,6 +55,7 @@
         class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildIntrospectionErrorResponseFromEvent"
         scope="prototype"
         p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:mappedResponsesLookupStrategy="#{getObject('shibboleth.oauth2.introspection.MappedErrorResponsesLookupStrategy') ?: getObject('shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy')}"
         p:mappedErrors="#{getObject('shibboleth.oauth2.introspection.MappedErrors') ?: getObject('shibboleth.oidc.DefaultApiMappedErrors')}">
         <property name="eventContextLookupStrategy">
             <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
index 3aa8e59f..51b7a528 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/introspection/introspection-flow.xml
@@ -27,6 +27,7 @@
 
     <action-state id="ResumeAfterAuthentication">
         <evaluate expression="ValidateClientIDAgainstPolicy" />
+        <evaluate expression="ValidateOriginHeader" />
         <evaluate expression="ProcessTokenForIntrospection" />
         <evaluate expression="'proceed'" />
         
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
index 702ca83c..f656229e 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-beans.xml
@@ -372,6 +372,7 @@
         class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildPushedAuthorizationErrorResponseFromEvent"
         scope="prototype"
         p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:mappedResponsesLookupStrategy="#{getObject('shibboleth.oauth2.par.MappedErrorResponsesLookupStrategy') ?: getObject('shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy')}"
         p:mappedErrors="#{getObject('shibboleth.oauth2.par.MappedErrors') ?: getObject('shibboleth.oidc.DefaultApiMappedErrors')}">
         <property name="eventContextLookupStrategy">
             <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
index 496a74a9..efff4f70 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/pushed-authorization/pushed-authorization-flow.xml
@@ -28,6 +28,7 @@
     <action-state id="ResumeAfterAuthentication">
         <evaluate expression="ValidatePushedAuthorizationClientIDMatch" />
         <evaluate expression="ValidateClientIDAgainstPolicy" />
+        <evaluate expression="ValidateOriginHeader" />
         <evaluate expression="ValidateAuthorizationRequestType" />
         <evaluate expression="InitializeOutboundMessageContext" />
         <evaluate expression="SetRequestObjectToResponseContext" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
index 4655bc34..2f556f82 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-beans.xml
@@ -67,6 +67,7 @@
         class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.BuildRevokeTokenErrorResponseFromEvent" 
         scope="prototype"
         p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:mappedResponsesLookupStrategy="#{getObject('shibboleth.oauth2.revocation.MappedErrorResponsesLookupStrategy') ?: getObject('shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy')}"
         p:mappedErrors="#{getObject('shibboleth.oauth2.revocation.MappedErrors') ?: getObject('shibboleth.oidc.DefaultApiMappedErrors')}">
         <property name="eventContextLookupStrategy">
             <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
index ad68687a..5a470d1e 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oauth2/revocation/revocation-flow.xml
@@ -29,6 +29,7 @@
 
     <action-state id="ResumeAfterAuthentication">
         <evaluate expression="ValidateClientIDAgainstPolicy" />
+        <evaluate expression="ValidateOriginHeader" />
         <evaluate expression="ProcessTokenForRevocation" />
         <evaluate expression="RevokeToken" />
         <evaluate expression="'proceed'" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
index aa8f2367..5805a4e6 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml
@@ -140,4 +140,8 @@
         c:type="#{ T(net.shibboleth.oidc.security.jose.context.SecurityParametersContext) }"
         c:createContext="true" />
 
+    <bean id="ValidateOriginHeader" class="net.shibboleth.idp.plugin.oidc.op.oauth2.profile.impl.ValidateOriginHeader"
+        scope="prototype"
+        p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
+
 </beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index ef14c177..5c0c4fd1 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
@@ -660,6 +660,7 @@
     <bean id="BuildErrorResponseFromEvent"
         class="net.shibboleth.idp.plugin.oidc.op.profile.impl.BuildTokenErrorResponseFromEvent" scope="prototype"
         p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:mappedResponsesLookupStrategy="#{getObject('shibboleth.oidc.token.MappedErrorResponsesLookupStrategy') ?: getObject('shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy')}"
         p:mappedErrors="#{getObject('shibboleth.oidc.token.MappedErrors') ?: getObject('shibboleth.oidc.DefaultApiMappedErrors')}">
         <property name="eventContextLookupStrategy">
             <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
index 9eb45d3f..8187342b 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-flow.xml
@@ -36,6 +36,7 @@
 
     <action-state id="ResumeAfterAuthentication">
         <evaluate expression="ValidateClientIDAgainstPolicy" />
+        <evaluate expression="ValidateOriginHeader" />
         <evaluate expression="ValidateGrantType" />
         <evaluate expression="'proceed'" />
         
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
index 61113570..60276ab1 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-beans.xml
@@ -228,6 +228,7 @@
     <bean id="BuildErrorResponseFromEvent"
         class="net.shibboleth.idp.plugin.oidc.op.userinfo.profile.impl.BuildUserInfoErrorResponseFromEvent" scope="prototype"
         p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier"
+        p:mappedResponsesLookupStrategy="#{getObject('shibboleth.oidc.userinfo.MappedErrorResponsesLookupStrategy') ?: getObject('shibboleth.oidc.DefaultMappedErrorResponsesLookupStrategy')}"
         p:mappedErrors="#{getObject('shibboleth.oidc.userinfo.MappedErrors') ?: getObject('shibboleth.oidc.DefaultOAuth2ProtectedApiMappedErrors')}"
         p:securityParametersContextLookupStrategy-ref="DPoPSecurityParametersContextProfileRequestContextLookup"
         p:algorithmCandidates="%{idp.oauth2.dpop.proofAlgorithms:RS256,RS384,RS512,PS256,PS384,PS512,ES256,ES384,ES512}"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-flow.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-flow.xml
index e7120437..9a744e36 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-flow.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/userinfo-flow.xml
@@ -48,6 +48,7 @@
 
     <action-state id="ResumeAfterDoDPoPProofValidation">
         <evaluate expression="ValidateClientIDAgainstPolicy" />
+        <evaluate expression="ValidateOriginHeader" />
         <evaluate expression="ValidateAccessToken" />
         <evaluate expression="ValidateScope" />
         <evaluate expression="SetRequestedClaimsToResponseContext" />
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 9177af6f..75f4232d 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
@@ -94,6 +94,9 @@ import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
 import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
 
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import net.shibboleth.idp.plugin.oidc.op.messaging.impl.DefaultInvalidOriginErrorResponse;
 import net.shibboleth.idp.plugin.oidc.op.token.support.AccessTokenClaimsSet;
 import net.shibboleth.idp.plugin.oidc.op.token.support.TokenClaimsSet;
 import net.shibboleth.idp.test.flows.AbstractFlowTest;
@@ -234,7 +237,14 @@ public abstract class AbstractOidcFlowTest extends AbstractFlowTest {
         Assert.assertNotNull(errorResponse.getErrorObject().getDescription());
         Assert.assertTrue(errorResponse.getErrorObject().getDescription().contains(errorDescription));
     }
-    
+
+    protected void assertInvalidOriginResponse(final FlowExecutionResult result) {
+        final Response response = parseResponse(result);
+        Assert.assertFalse(response.indicatesSuccess());
+        Assert.assertTrue(response instanceof DefaultInvalidOriginErrorResponse);
+        Assert.assertEquals(response.toHTTPResponse().getContent(), "Invalid CORS request");
+    }
+
     protected void setJsonRequest(final String method, final String body) {
         setRequest(method, body, "application/json");
     }
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
index 26a20286..209145c6 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/IntrospectionFlowTest.java
@@ -219,6 +219,46 @@ public class IntrospectionFlowTest extends AbstractOidcClientAuthenticationFlowT
         }
     }
 
+    @Test
+    public void testSuccess_validOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+            DataSealerException, ComponentInitializationException {
+        for (final String clientId : clientIds) {
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+            setBasicAuth(clientId, clientSecret);
+            request.addHeader("Origin", "https://example.org");
+            setHttpFormRequest("POST", Map.of(
+                    "token",
+                    buildToken(clientId, "sub", Scope.parse("openid")).toJSONObject().getAsString("access_token"),
+                    "token_type",
+                    "access_token"));
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+            final TokenIntrospectionSuccessResponse resp =
+                    parseSuccessResponse(result, TokenIntrospectionSuccessResponse.class);
+            Assert.assertTrue(resp.isActive());
+            assertBearerToken(resp);
+            Assert.assertEquals(resp.getClientID().getValue(), clientId);
+            Assert.assertEquals(resp.getScope(), Scope.parse("openid"));
+            Assert.assertNull(resp.getAudience());
+            Assert.assertEquals(resp.getUsername(), "jdoe");
+        }
+    }
+
+    @Test
+    public void testFails_invalidOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+            DataSealerException, ComponentInitializationException {
+        for (final String clientId : clientIds) {
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+            request.addHeader("Origin", "https://example.org:1234");
+            setBasicAuth(clientId, clientSecret);
+            setHttpFormRequest("POST", Map.of(
+                    "token",
+                    buildToken(clientId, "sub", Scope.parse("openid")).toJSONObject().getAsString("access_token"),
+                    "token_type",
+                    "access_token"));
+            assertInvalidOriginResponse(flowExecutor.launchExecution(FLOW_ID, null, externalContext));
+        }
+    }
+
     @Test
     public void testSuccessDPoP() throws IOException, NoSuchAlgorithmException, URISyntaxException, DataSealerException,
             ComponentInitializationException {
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
index f95b62af..2ec24d3c 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/PushedAuthorizeFlowTest.java
@@ -193,6 +193,34 @@ public class PushedAuthorizeFlowTest extends AbstractOidcClientAuthenticationFlo
         }
     }
 
+    @Test
+    public void testSuccess_validOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+            DataSealerException, ComponentInitializationException {
+        for (final String clientId : clientIds) {
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+            setBasicAuth(clientId, clientSecret);
+            request.addHeader("Origin", "https://example.org");
+            setHttpFormRequest("POST", createRequestParameters(clientId));
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+            assertSuccessResponse(result, clientId);
+            final PushedAuthorizationSuccessResponse response =
+                    parseSuccessResponse(result, PushedAuthorizationSuccessResponse.class);
+            verifyAuthorizeEndpoint(clientId, response.getRequestURI().toString());
+        }
+    }
+
+    @Test
+    public void testFails_invalidOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+            DataSealerException, ComponentInitializationException {
+        for (final String clientId : clientIds) {
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+            setBasicAuth(clientId, clientSecret);
+            request.addHeader("Origin", "https://example.org:1234");
+            setHttpFormRequest("POST", createRequestParameters(clientId));
+            assertInvalidOriginResponse(flowExecutor.launchExecution(FLOW_ID, null, externalContext));
+        }
+    }
+
     @Test
     public void testFailure_unregisteredScope() throws IOException, NoSuchAlgorithmException, URISyntaxException, DataSealerException,
             ComponentInitializationException {
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
index 4ad7fc55..e7fa12bf 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/RevocationFlowTest.java
@@ -142,6 +142,39 @@ public class RevocationFlowTest extends AbstractOidcClientAuthenticationFlowTest
         }
     }
 
+    @Test
+    public void testSuccess_validOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+        DataSealerException, ComponentInitializationException {
+        final String id = idGenerator.generateIdentifier();
+        final String rootId = idGenerator.generateIdentifier();
+        for (final String clientId : clientIds) {
+            setBasicAuth(clientId, clientSecret);
+            request.addHeader("Origin", "https://example.org");
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org/cb");
+            setHttpFormRequest("POST", Collections.singletonMap("token", super.buildToken(clientId, "sub", 
+                    Scope.parse("openid"), null, id, rootId).toJSONObject().getAsString("access_token")));
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+            parseSuccessResponse(result, OAuth2RevocationSuccessResponse.class);
+            Assert.assertFalse(revocationCache.isRevoked(RevocationCacheContexts.SINGLE_ACCESS_OR_REFRESH_TOKENS, id));
+            Assert.assertTrue(revocationCache.isRevoked(RevocationCacheContexts.AUTHORIZATION_CODE, rootId));
+        }
+    }
+
+    @Test
+    public void testFails_invalidOrigin() throws IOException, NoSuchAlgorithmException, URISyntaxException,
+        DataSealerException, ComponentInitializationException {
+        final String id = idGenerator.generateIdentifier();
+        final String rootId = idGenerator.generateIdentifier();
+        for (final String clientId : clientIds) {
+            setBasicAuth(clientId, clientSecret);
+            request.addHeader("Origin", "https://example.org:1234");
+            storeMetadata(storageService, clientId, clientSecret, scope, "https://example.org");
+            setHttpFormRequest("POST", Collections.singletonMap("token", super.buildToken(clientId, "sub", 
+                    Scope.parse("openid"), null, id, rootId).toJSONObject().getAsString("access_token")));
+            assertInvalidOriginResponse(flowExecutor.launchExecution(FLOW_ID, null, externalContext));
+        }
+    }
+
     @Test
     public void testSuccessWithPostAuthn() throws IOException, NoSuchAlgorithmException, URISyntaxException,
         DataSealerException, ComponentInitializationException {
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 a3cbd3cd..903bb3c2 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
@@ -278,6 +278,40 @@ public class TokenFlowTest extends AbstractOidcClientAuthenticationFlowTest {
         }
     }
 
+    @Test
+    public void testValidGrantAcceptedOrigin() throws Exception {
+        for (final String clientId : clientIds) {
+            request.addHeader("Origin", "https://example.org");
+            initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
+                    buildAuthorizationCode(clientId), clientId));
+            storeConsent(storageService, "jdoe", clientId, "mail");
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+            final OIDCTokenResponse response = parseSuccessResponse(result, OIDCTokenResponse.class);
+            Assert.assertNotNull(response.getTokens().getAccessToken());
+            Assert.assertNotNull(response.getTokens().getRefreshToken());
+            Assert.assertNotNull(response.getOIDCTokens().getIDToken());
+            Assert.assertNotNull(response.getOIDCTokens().getIDToken().getJWTClaimsSet().getClaim("at_hash"));
+            Assert.assertNull(getSidFromAccessToken(response.getTokens().getAccessToken()));
+            Assert.assertNull(getSidFromRefreshToken(response.getTokens().getRefreshToken()));
+            assertDecoratedRefreshToken(response.getTokens().getRefreshToken());
+            Assert.assertNull(getSidFromJWT(response.getOIDCTokens().getIDToken()));
+            assertDecoratedAccessToken(response.getTokens().getAccessToken());
+            assertDecoratedIdToken(response.getOIDCTokens().getIDToken());
+        }
+    }
+
+    @Test
+    public void testValidGrantInvalidOrigin() throws Exception {
+        for (final String clientId : clientIds) {
+            request.addHeader("Origin", "http://localhost:12345");
+            initializeGrantAndRequest(clientId, createRequestParameters(redirectUri, "authorization_code",
+                    buildAuthorizationCode(clientId), clientId));
+            storeConsent(storageService, "jdoe", clientId, "mail");
+            final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+            assertInvalidOriginResponse(flowExecutor.launchExecution(FLOW_ID, null, externalContext));
+        }
+    }
+
     @Test
     public void testValidWithUriResource() throws Exception {
         final Map<String, String> requestParameters = createRequestParameters(redirectUri, "authorization_code",
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 03b8fc1b..779cc69c 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
@@ -172,6 +172,33 @@ public class UserInfoTest extends AbstractOidcApiFlowTest {
         Assert.assertNull(response.getUserInfoJWT());
     }
 
+    @Test
+    public void testSuccess_validOrigin() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException {
+        final BearerAccessToken token = buildToken(clientId, subject, new Scope("openid"));
+        storeMetadata(storageService, clientId, "mockSecret", scope, "https://example.org/cb");
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        request.addHeader("Origin", "https://example.org");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        final UserInfoSuccessResponse response = parseSuccessResponse(result, UserInfoSuccessResponse.class);
+        Assert.assertEquals(response.getUserInfo().getSubject().getValue(), subject);
+        final UserInfo userInfo = response.getUserInfo();
+        Assert.assertNotNull(userInfo);
+        Assert.assertNull(userInfo.getEmailAddress());
+        Assert.assertNull(userInfo.getNickname());
+        Assert.assertNull(response.getUserInfoJWT());
+    }
+
+    @Test
+    public void testFails_invalidOrigin() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
+        ComponentInitializationException, IOException {
+        final BearerAccessToken token = buildToken(clientId, subject, new Scope("openid"));
+        storeMetadata(storageService, clientId, "mockSecret", scope, "https://example.org/cb");
+        request.addHeader("Origin", "https://example.org:1234");
+        request.addHeader("Authorization", getTokenHeaderValue(token));
+        assertInvalidOriginResponse(flowExecutor.launchExecution(FLOW_ID, null, externalContext));
+    }
+
     @Test
     public void testFailsWhenNoOpenidScopeRequested() throws URISyntaxException, NoSuchAlgorithmException, DataSealerException,
         ComponentInitializationException, IOException {

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


More information about the commits mailing list