[java-plugin-shibd-oidc] branch main updated: Finish scope parameter lookup strategy

Phil Smart philip.smart at jisc.ac.uk
Tue Oct 14 16:13:14 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=83403341640e9cba13a4d9fbecc0d8db394bbaa7

The following commit(s) were added to refs/heads/main by this push:
     new 8340334  Finish scope parameter lookup strategy
8340334 is described below

commit 83403341640e9cba13a4d9fbecc0d8db394bbaa7
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue Oct 14 17:13:12 2025 +0100

    Finish scope parameter lookup strategy
    
     - Scope take from DDF, if disallowed or not present, then rpConfig.
---
 .../sp/oidc/profile/impl/ScopeLookupStrategy.java  |  53 +++++++--
 .../oidc/profile/impl/ScopeLookupStrategyTest.java | 128 +++++++++++++++++++++
 2 files changed, 170 insertions(+), 11 deletions(-)

diff --git a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java
index e24a78a..1cdf217 100644
--- a/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java
+++ b/sp-oidc-impl/src/main/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategy.java
@@ -14,35 +14,66 @@
 
 package net.shibboleth.sp.oidc.profile.impl;
 
+import java.util.Arrays;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nonnull;
+
 import org.opensaml.messaging.context.MessageContext;
+import org.slf4j.Logger;
 
+import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.oidc.profile.OIDCInitiatorConstants;
 
 /**
- *
+ * A strategy function that extracts Scope from the inbound {@link MessageContext} and returns them as a set of 
+ * {@link String}s. Takes them from the inbound {@link DDF} object if they exist, if they do not exist or they were 
+ * disallowed by the Hub configuration they are taken from the relying party configuration.
  */
 public class ScopeLookupStrategy extends AbstractAgentAndRelyingPartyContextLookupFunction<Set<String>>{
+    
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ForceAuthnParameterLookupStrategy.class);
 
     /** {@inheritDoc} */
     @Override
     public Set<String> apply(final MessageContext messageContext) {
+        
         final DDF input = getDDF(messageContext, DDFDirection.INPUT);
-        if (input == null) {
-            return null;
-        }
-        final String scopeFromDDF = input.getmember(OIDCInitiatorConstants.SCOPE).string();
-        if (StringSupport.trimOrNull(scopeFromDDF) == null) {
-            return null;
+        
+        Set<String> scopes = CollectionSupport.emptySet(); 
+        
+        if (input != null) {
+            final String scopeFromDDF = input.getmember(OIDCInitiatorConstants.SCOPE).string();
+            if (StringSupport.trimOrNull(scopeFromDDF) != null) {                
+                assert scopeFromDDF != null;
+                scopes = Arrays.stream(scopeFromDDF.split("\\s+")).filter(s -> !s.isEmpty())
+                        .collect(Collectors.toUnmodifiableSet());
+            }
         }
-        assert scopeFromDDF != null;
-        return StringSupport.stringToList(scopeFromDDF,"\\s+").stream().filter(s -> !s.isEmpty())
-                .collect(Collectors.toUnmodifiableSet());
+        
+        if (!scopes.isEmpty() && isFeatureDisallowed(OIDCAuthorizationConfiguration.FEATURE_SCOPE, messageContext)) {
+            log.warn("Agent disallowed from overriding scope");
+            scopes = CollectionSupport.emptySet();
+        } 
 
+        if (scopes.isEmpty()) {
+            final OIDCAuthenticationRelyingPartyProfileConfiguration rpConfig =
+                    getOIDCRelyingPartyProfileConfiguration(messageContext);
+            if (rpConfig != null) {
+                final Set<String> scopesFromConfig = rpConfig.getScopes(PRC_LOOKUP.apply(messageContext));
+                if (scopesFromConfig != null && !scopesFromConfig.isEmpty()) {
+                    scopes = scopesFromConfig;
+                }
+            }
+        }       
+        return scopes;
     }
 
-}
+}
\ No newline at end of file
diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategyTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategyTest.java
new file mode 100644
index 0000000..2922baf
--- /dev/null
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/impl/ScopeLookupStrategyTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.Set;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.FunctionSupport;
+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 ScopeLookupStrategy}.
+ */
+public class ScopeLookupStrategyTest extends AbstractAuthenticationLookupStrategyTest {
+    
+    /** The strategy to test.*/
+    private ScopeLookupStrategy strategy;
+
+    /** The DDF to store input parameters.*/
+    private DDF ddf;
+
+    @Override
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        super.setUp();
+        strategy = new ScopeLookupStrategy();
+
+        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 testDDFScope() {
+        ddf.addmember(OIDCInitiatorConstants.SCOPE).string("email profile");
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 2);
+        assertTrue(scopes.contains("email"));
+        assertTrue(scopes.contains("profile"));
+    }
+    
+    @Test
+    public void testRPConfigScope() {
+        rpConfig.setScopes(Set.of("email", "profile"));
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 2);
+        assertTrue(scopes.contains("email"));
+        assertTrue(scopes.contains("profile"));
+    }
+    @Test
+    public void testRPConfigScope_Empty() {
+        rpConfig.setScopes(Set.of(""));
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 0);
+    }
+    
+    @Test
+    public void testRPConfigScope_Null() {
+        rpConfig.setScopesLookupStrategy(FunctionSupport.constant(null));
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 0);
+    }
+    
+    @Test
+    public void testDDFScope_Dissallowed() {
+        ddf.addmember(OIDCInitiatorConstants.SCOPE).string("email profile");
+        rpConfig.setDisallowedFeatures(OIDCAuthorizationConfiguration.FEATURE_SCOPE);
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 1);
+        // if not from agent, the hub (rp config) always adds openid
+        assertTrue(scopes.contains("openid"));
+    }
+
+    @Test
+    public void testDDFScope_Dissallowed_AddFromRPConfig() {
+        ddf.addmember(OIDCInitiatorConstants.SCOPE).string("email profile");
+        rpConfig.setDisallowedFeatures(OIDCAuthorizationConfiguration.FEATURE_SCOPE);
+        rpConfig.setScopes(Set.of("email", "profile"));
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(), 2);
+        assertTrue(scopes.contains("email"));
+        assertTrue(scopes.contains("profile"));
+    }
+    
+    @Test
+    public void testDDFScope_NothingInDDF_NothingInConfig() {
+        final Set<String> scopes = strategy.apply(mc);
+        assertNotNull(scopes);
+        assertEquals(scopes.size(),1);
+        // if not from agent, the hub (rp config) always adds openid
+        assertTrue(scopes.contains("openid"));
+    }
+    
+
+}

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


More information about the commits mailing list