Skip to content

Commit 4254b34

Browse files
maximthomasvharseko
authored andcommitted
Using arbitrary OIDC requested claims values in id_token and user_info is allowed
1 parent ccf0375 commit 4254b34

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

openam-oauth2/src/test/java/org/forgerock/openam/openidconnect/OidcClaimsExtensionTest.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* information: "Portions copyright [year] [name of copyright owner]".
1313
*
1414
* Copyright 2015-2016 ForgeRock AS.
15+
* Portions copyright 2025 3A Systems LLC.
1516
*/
1617

1718
package org.forgerock.openam.openidconnect;
@@ -71,6 +72,10 @@ public void setupScript() throws Exception {
7172
@BeforeMethod
7273
public void setup() throws Exception {
7374
this.logger = mock(Debug.class);
75+
doAnswer(invocationOnMock -> {
76+
System.out.println(invocationOnMock.getArguments()[0]);
77+
return null;
78+
}).when(logger).warning(anyString());
7479
this.ssoToken = mock(SSOToken.class);
7580
this.identity = mock(AMIdentity.class);
7681
this.accessToken = new StatefulAccessToken(json(object()), OAuth2Constants.Token.OAUTH_ACCESS_TOKEN, "id");
@@ -106,18 +111,20 @@ public void testProfileScope() throws Exception {
106111
public void testRequestedClaims() throws Exception {
107112
// Given
108113
Map<String, Set<String>> requestedClaims = new HashMap<String, Set<String>>();
109-
requestedClaims.put("given_name", asSet("fred"));
114+
requestedClaims.put("given_name", asSet("joe", "fred"));
110115
requestedClaims.put("family_name", asSet("flintstone"));
116+
111117
Bindings variables = testBindings(asSet("profile"), requestedClaims);
112118
when(identity.getAttribute("cn")).thenReturn(asSet("Joe Bloggs"));
119+
when(identity.getAttribute("sn")).thenReturn(asSet("bloggs"));
120+
when(identity.getAttribute("givenname")).thenReturn(asSet("joe"));
113121

114122
// When
115123
UserInfoClaims result = scriptEvaluator.evaluateScript(script, variables);
116124

117125
// Then
118126
assertThat(result.getValues()).containsOnly(
119-
entry("given_name", "fred"),
120-
entry("family_name", "flintstone"),
127+
entry("given_name", "joe"),
121128
entry("name", "Joe Bloggs"));
122129

123130
assertThat(result.getCompositeScopes()).containsOnlyKeys("profile");
@@ -128,7 +135,7 @@ public void testRequestedClaims() throws Exception {
128135
verify(identity).getAttribute("cn");
129136
verify(identity).getAttribute("preferredlocale");
130137
verify(identity).getAttribute("preferredtimezone");
131-
verifyNoMoreInteractions(identity);
138+
verify(identity).getAttribute("sn");
132139
}
133140

134141
@Test
@@ -139,6 +146,9 @@ public void testRequestedClaimsNoScope() throws Exception {
139146
requestedClaims.put("family_name", asSet("flintstone"));
140147
Bindings variables = testBindings(asSet("openid"), requestedClaims);
141148

149+
when(identity.getAttribute("sn")).thenReturn(asSet("flintstone"));
150+
when(identity.getAttribute("givenname")).thenReturn(asSet("fred"));
151+
142152
// When
143153
UserInfoClaims result = scriptEvaluator.evaluateScript(script, variables);
144154

openam-oauth2/src/test/resources/oidc-claims-extension.groovy

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* information: "Portions copyright [year] [name of copyright owner]".
1313
*
1414
* Copyright 2014-2016 ForgeRock AS.
15+
* Portions copyright 2025 3A Systems LLC.
1516
*/
1617
import com.iplanet.sso.SSOException
1718
import com.sun.identity.idm.IdRepoException
@@ -52,12 +53,16 @@ def fromSet = { claim, attr ->
5253
}
5354

5455
attributeRetriever = { attribute, claim, identity, requested ->
56+
def attr = fromSet(claim, identity.getAttribute(attribute))
5557
if (requested == null || requested.isEmpty()) {
56-
fromSet(claim, identity.getAttribute(attribute))
57-
} else if (requested.size() == 1) {
58-
requested.iterator().next()
58+
attr
5959
} else {
60-
throw new RuntimeException("No selection logic for $claim defined. Values: $requested")
60+
if (requested.contains(attr)) {
61+
attr
62+
} else {
63+
logger.warning("OpenAMScopeValidator.getUserInfo(): $claim attribute=$attr does not match the requested value=$requested");
64+
null
65+
}
6166
}
6267
}
6368

@@ -106,7 +111,7 @@ def computedClaims = scopes.findAll { s -> !"openid".equals(s) && scopeClaimsMap
106111
map << scopeClaims.findAll { c -> !requestedClaims.containsKey(c) }.collectEntries([:]) { claim -> computeClaim(claim, null) }
107112
}.findAll { map -> map.value != null } << requestedClaims.collectEntries([:]) { claim, requestedValue ->
108113
computeClaim(claim, requestedValue)
109-
}
114+
}.findAll { map -> map.value != null }
110115

111116
def compositeScopes = scopeClaimsMap.findAll { scope ->
112117
scopes.contains(scope.key)

openam-scripting/src/main/groovy/oidc-claims-extension.groovy

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* information: "Portions copyright [year] [name of copyright owner]".
1313
*
1414
* Copyright 2014-2016 ForgeRock AS.
15+
* Portions copyright 2025 3A Systems LLC.
1516
*/
1617
import com.iplanet.sso.SSOException
1718
import com.sun.identity.idm.IdRepoException
@@ -52,12 +53,16 @@ def fromSet = { claim, attr ->
5253
}
5354

5455
attributeRetriever = { attribute, claim, identity, requested ->
56+
def attr = fromSet(claim, identity.getAttribute(attribute))
5557
if (requested == null || requested.isEmpty()) {
56-
fromSet(claim, identity.getAttribute(attribute))
57-
} else if (requested.size() == 1) {
58-
requested.iterator().next()
58+
attr
5959
} else {
60-
throw new RuntimeException("No selection logic for $claim defined. Values: $requested")
60+
if (requested.contains(attr)) {
61+
attr
62+
} else {
63+
logger.warning("OpenAMScopeValidator.getUserInfo(): $claim attribute=$attr does not match the requested value=$requested");
64+
null
65+
}
6166
}
6267
}
6368

@@ -106,7 +111,7 @@ def computedClaims = scopes.findAll { s -> !"openid".equals(s) && scopeClaimsMap
106111
map << scopeClaims.findAll { c -> !requestedClaims.containsKey(c) }.collectEntries([:]) { claim -> computeClaim(claim, null) }
107112
}.findAll { map -> map.value != null } << requestedClaims.collectEntries([:]) { claim, requestedValue ->
108113
computeClaim(claim, requestedValue)
109-
}
114+
}.findAll { map -> map.value != null }
110115

111116
def compositeScopes = scopeClaimsMap.findAll { scope ->
112117
scopes.contains(scope.key)

0 commit comments

Comments
 (0)