[java-plugin-shibd-oidc] branch main updated: Add ui_locales handler
Phil Smart
philip.smart at jisc.ac.uk
Wed Oct 15 10:56:08 UTC 2025
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-plugin-shibd-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd-oidc.git;a=commit;h=556b6d93a3baf71fced8cc1b81db31bb3e75f08d
The following commit(s) were added to refs/heads/main by this push:
new 556b6d9 Add ui_locales handler
556b6d9 is described below
commit 556b6d93a3baf71fced8cc1b81db31bb3e75f08d
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Oct 15 11:56:05 2025 +0100
Add ui_locales handler
- takes them only from the input DDF
---
.../sp/oidc/profile/OIDCInitiatorConstants.java | 3 +
.../idp/flows/sp/initiator/oidc/oidc-beans.xml | 6 ++
.../sp/oidc/flows/OIDCAuthenticationFlowTest.java | 27 +++++++-
.../sp/oidc/profile/impl/BuildRequestObject.java | 8 +++
.../oidc/profile/impl/UiLocalesLookupStrategy.java | 52 +++++++++++++++
.../profile/request/impl/AddUiLocalesHandler.java | 67 +++++++++++++++++++
.../profile/impl/UiLocalesLookupStrategyTest.java | 77 ++++++++++++++++++++++
7 files changed, 239 insertions(+), 1 deletion(-)
diff --git a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
index 033e0fb..167f8cc 100644
--- a/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
+++ b/sp-oidc-api/src/main/java/net/shibboleth/sp/oidc/profile/OIDCInitiatorConstants.java
@@ -48,6 +48,9 @@ public final class OIDCInitiatorConstants {
/** Resource parameter */
@Nonnull @NotEmpty public static final String RESOURCE = "resource";
+
+ /** ui_locales parameter */
+ @Nonnull @NotEmpty public static final String UI_LOCALES = "ui_locales";
/** authnContextClassRef input parameter. */
@Nonnull @NotEmpty public static final String AUTHN_CONTEXT_CLASS_REF = AuthnContextClassRef.DEFAULT_ELEMENT_LOCAL_NAME;
diff --git a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
index 04fa62e..7a5bf47 100644
--- a/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
+++ b/sp-oidc-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/oidc/oidc-beans.xml
@@ -181,6 +181,12 @@
<bean class="net.shibboleth.sp.oidc.profile.impl.ResourceLookupStrategy" scope="prototype"/>
</property>
</bean>
+ <bean id="AddUiLocales" scope="prototype"
+ class="net.shibboleth.sp.oidc.profile.request.impl.AddUiLocalesHandler">
+ <property name="parameterValueLookupStrategy">
+ <bean class="net.shibboleth.sp.oidc.profile.impl.UiLocalesLookupStrategy" scope="prototype"/>
+ </property>
+ </bean>
</list>
</property>
</bean>
diff --git a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
index ad0a9a4..2974835 100644
--- a/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
+++ b/sp-oidc-conf-impl/src/test/java/net/shibboleth/sp/oidc/flows/OIDCAuthenticationFlowTest.java
@@ -52,7 +52,8 @@ import net.shibboleth.sp.profile.SPConstants;
import net.shibboleth.sp.profile.impl.IssueCorrelationCookie;
/**
- * TODO these tests work using a signed request object atm, but the asserts need to work on url params as well
+ * TODO these tests work using a signed request object atm, we need to formalise that being set, and
+ * test using without the request object.
*/
@ContextConfiguration(
locations = {
@@ -255,6 +256,30 @@ public class OIDCAuthenticationFlowTest extends AbstractSPFlowTest {
assertValueForParameterFromRequestObject(req, "scope", "openid email profile");
}
+ /**
+ * Basic flow test with ui_locales.
+ *
+ * @throws Exception on error
+ */
+ @Test
+ public void testUiLocalesFromAgent() throws Exception {
+ setDefaultAuth();
+
+ final DDF input = new DDF(null).structure();
+ input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();
+ input.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+ input.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL);
+ input.addmember(OIDCInitiatorConstants.UI_LOCALES).string("fr-CA fr en");
+ setApplicationRequest("test-oidc-application", input);
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertFlowExecutionResult(result, FLOW_ID);
+ assertFlowExecutionOutcome(result.getOutcome());
+
+ final AuthenticationRequest req = validateOutputMessage(result);
+ assertValueForParameterFromRequestObject(req, "ui_locales", "fr-CA fr en");
+ }
+
/**
* Basic flow test with display.
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildRequestObject.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildRequestObject.java
index 5fc353b..4d70d92 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildRequestObject.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/BuildRequestObject.java
@@ -18,6 +18,7 @@ import java.time.Duration;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -31,6 +32,7 @@ import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
import org.slf4j.Logger;
import com.nimbusds.jwt.JWT;
+import com.nimbusds.langtag.LangTag;
import com.nimbusds.oauth2.sdk.ResponseMode;
import com.nimbusds.oauth2.sdk.id.Audience;
import com.nimbusds.oauth2.sdk.id.Issuer;
@@ -266,6 +268,12 @@ public class BuildRequestObject extends AbstractProfileAction {
setClaimIfPresent(requestObjectClaims, "login_hint", authnRequest.getLoginHint());
setClaimIfPresent(requestObjectClaims, "prompt", authnRequest.getPrompt());
setClaimIfPresent(requestObjectClaims, "display", authnRequest.getDisplay());
+
+ if (!authnRequest.getUiLocales().isEmpty()) {
+ final String locales = authnRequest.getUiLocales().stream().map(LangTag::toString).filter(s -> !s.isEmpty())
+ .collect(Collectors.joining(" "));
+ setClaimIfPresent(requestObjectClaims, "ui_locales", locales);
+ }
if (authnRequest.providerSupportsClaimsParameter()) {
// Build the ACRs if set before adding the 'claims' claim
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategy.java
new file mode 100644
index 0000000..1bf60b9
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategy.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sp.oidc.profile.impl;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.opensaml.messaging.context.MessageContext;
+
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+
+/**
+ * A strategy function that extracts ui_locales from the inbound {@link MessageContext} and returns them as a List of
+ * {@link String}s. Taking them from the inbound {@link DDF} object if they exist.
+ */
+public class UiLocalesLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<List<String>>{
+
+ /** {@inheritDoc} */
+ @Override
+ public List<String> apply(final MessageContext messageContext) {
+
+ final DDF input = getDDF(messageContext, DDFDirection.INPUT);
+
+ List<String> uiLocales = CollectionSupport.emptyList();
+
+ if (input != null) {
+ final String uiLocalesFromDDF = input.getmember(OIDCInitiatorConstants.UI_LOCALES).string();
+ if (StringSupport.trimOrNull(uiLocalesFromDDF) != null) {
+ assert uiLocalesFromDDF != null;
+ uiLocales = Arrays.stream(uiLocalesFromDDF.split("\\s+")).filter(s -> !s.isEmpty())
+ .toList();
+ }
+ }
+ return uiLocales;
+ }
+
+}
diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddUiLocalesHandler.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddUiLocalesHandler.java
new file mode 100644
index 0000000..b804e99
--- /dev/null
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/request/impl/AddUiLocalesHandler.java
@@ -0,0 +1,67 @@
+/*
+ * 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.sp.oidc.profile.request.impl;
+
+import java.util.List;
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.slf4j.Logger;
+
+import com.nimbusds.langtag.LangTag;
+import com.nimbusds.langtag.LangTagException;
+
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.oidc.profile.impl.AbstractAuthenticationRequestParameterValueMessageHandler;
+
+/**
+ * A message handler that sets the 'ui_locales' parameter on the authentication request.
+ */
+public class AddUiLocalesHandler extends AbstractAuthenticationRequestParameterValueMessageHandler<List<String>> {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(AddUiLocalesHandler.class);
+
+ /** Constructor.*/
+ public AddUiLocalesHandler() {
+ super((Class)List.class);
+ }
+
+ @Override
+ protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+
+ final List<String> locales = getParameterValue(messageContext);
+ if (locales != null && !locales.isEmpty()) {
+ if (log.isTraceEnabled()) {
+ log.trace("{} Setting 'ui_locales={}'", getLogPrefix(), locales);
+ }
+ final List<LangTag> uiLocals = locales.stream().map(tag -> {
+ try {
+ return LangTag.parse(tag);
+ } catch (final LangTagException e) {
+ log.warn("Can not parse language tag '{}'", tag);
+ }
+ return null;
+ }).filter(Objects::nonNull).toList();
+
+ getAuthenticationRequest().setUiLocales(uiLocals);
+ }
+ }
+
+}
diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategyTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategyTest.java
new file mode 100644
index 0000000..46c742e
--- /dev/null
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/UiLocalesLookupStrategyTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.sp.oidc.profile.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
+import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
+import net.shibboleth.sp.profile.InitiatorConstants;
+import net.shibboleth.sp.profile.SPConstants;
+
+/**
+ * Tests for {@link UiLocalesLookupStrategyTest}
+ */
+public class UiLocalesLookupStrategyTest extends AbstractAuthenticationLookupStrategyTest {
+
+ /** The strategy to test.*/
+ private UiLocalesLookupStrategy strategy;
+
+ /** The DDF to store input parameters.*/
+ private DDF ddf;
+
+ @Override
+ @BeforeMethod
+ public void setUp() throws ComponentInitializationException {
+ super.setUp();
+ strategy = new UiLocalesLookupStrategy();
+
+ ddf = new DDF(null).structure();
+ ddf.addmember(RemotedHttpServletRequest.STRUCTURE_NAME).structure();
+ ddf.addmember(InitiatorConstants.RESPONSE_URL).string(RESPONSE_URL);
+ ddf.addmember(SPConstants.TARGET).unsafe_string(RESOURCE_URL);
+ addDDFToAgentRequestContext(ddf);
+ }
+
+ @Test
+ public void testThreeLocales() {
+ ddf.addmember(OIDCInitiatorConstants.UI_LOCALES).string("fr-CA fr en");
+ final List<String> result = strategy.apply(mc);
+ assertNotNull(result);
+ assert result != null;
+ assertEquals(result.size(), 3);
+ assertTrue(result.contains("fr-CA"));
+ assertTrue(result.contains("fr"));
+ assertTrue(result.contains("en"));
+ }
+
+ @Test
+ public void testNoLocales() {
+ final List<String> result = strategy.apply(mc);
+ assertNotNull(result);
+ assert result != null;
+ assertEquals(result.size(), 0);
+ }
+
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list