Skip to content

Commit b4a3b0e

Browse files
feat: Temporary: Use email as fallback principal id when user_uuid is missing. (#1065)
1 parent 12d3794 commit b4a3b0e

File tree

4 files changed

+51
-4
lines changed

4 files changed

+51
-4
lines changed

cloudplatform/security/src/main/java/com/sap/cloud/sdk/cloudplatform/security/principal/OidcAuthTokenPrincipalExtractor.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
class OidcAuthTokenPrincipalExtractor implements PrincipalExtractor
1717
{
1818
private static final String JWT_USER_UUID_CLAIM = "user_uuid";
19+
private static final String JWT_EMAIL_CLAIM = "email";
1920

2021
@Override
2122
@Nonnull
@@ -43,11 +44,16 @@ private Try<String> tryGetPrincipalId( @Nonnull final DecodedJWT jwt )
4344
return Try.of(() -> {
4445
final Claim userUuidClaim = jwt.getClaim(JWT_USER_UUID_CLAIM);
4546

46-
if( userUuidClaim.isMissing() || userUuidClaim.isNull() ) {
47-
throw new PrincipalAccessException("The current JWT does not contain the IAS user uuid.");
47+
if( userUuidClaim != null && !userUuidClaim.isMissing() && !userUuidClaim.isNull() ) {
48+
return userUuidClaim.asString();
4849
}
4950

50-
return userUuidClaim.asString();
51+
final Claim emailClaim = jwt.getClaim(JWT_EMAIL_CLAIM);
52+
if( emailClaim != null && !emailClaim.isMissing() && !emailClaim.isNull() ) {
53+
return emailClaim.asString();
54+
}
55+
56+
throw new PrincipalAccessException("The current JWT does not contain the IAS user uuid or an email.");
5157
});
5258
}
5359
}

cloudplatform/security/src/test/java/com/sap/cloud/sdk/cloudplatform/security/AuthTokenDecoderIasTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,35 @@ void testCaseInsensitiveBearer()
202202
assertThat(jwt).isNotNull();
203203
assertThat(jwt.getClaim("user_uuid").asString()).isEqualTo("5a21dfa1-fd90-45ff-a5d3-d1cfa446d25a");
204204
}
205+
206+
@Test
207+
void testDecodeSucceedsWithEmailOnly( @Nonnull final WireMockRuntimeInfo wm )
208+
{
209+
final Token tokenOnlyEmail =
210+
JwtGenerator
211+
.getInstance(Service.IAS, "2aba8ab2-edc3-4666-b2ed-90b2b47e60e3")
212+
.withHeaderParameter(TokenHeader.KEY_ID, "testKey")
213+
.withClaimValue("iss", wm.getHttpBaseUrl())
214+
.withClaimValues("aud", "1668e3ce-e2b8-4d27-a05b-3db47e7a4152", "2aba8ab2-edc3-4666-b2ed-90b2b47e60e3")
215+
.withClaimValue("sub", "sub-only-email")
216+
// intentionally omit user_uuid
217+
.withClaimValue("email", "[email protected]")
218+
.withExpiration(OffsetDateTime.now().plusDays(1).toInstant())
219+
.withPrivateKey(RSA_KEYS.getPrivate())
220+
.createToken();
221+
222+
final String tokenValue = tokenOnlyEmail.getTokenValue();
223+
224+
final RequestHeaderContainer headers =
225+
DefaultRequestHeaderContainer
226+
.fromSingleValueMap(Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Bearer " + tokenValue));
227+
228+
final AuthToken authToken = new AuthTokenDecoderDefault().decode(headers).getOrNull();
229+
230+
assertThat(authToken).isNotNull();
231+
232+
final DecodedJWT jwt = authToken.getJwt();
233+
assertThat(jwt).isNotNull();
234+
assertThat(jwt.getClaim("email").asString()).isEqualTo("[email protected]");
235+
}
205236
}

cloudplatform/security/src/test/java/com/sap/cloud/sdk/cloudplatform/security/principal/OidcAuthTokenPrincipalExtractorTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ void testReadPrincipal()
5656
assertThat(principal.getPrincipalId()).isEqualTo("principal id");
5757
}
5858

59+
@Test
60+
void testReadPrincipalFromEmailFallback()
61+
{
62+
mockAuthTokenFacade(JWT.create().withClaim("email", "[email protected]"));
63+
64+
final Principal principal = new OidcAuthTokenPrincipalExtractor().tryGetCurrentPrincipal().get();
65+
66+
assertThat(principal.getPrincipalId()).isEqualTo("[email protected]");
67+
}
68+
5969
private void mockAuthTokenFacadeWithMissingAuthToken()
6070
{
6171
AuthTokenAccessor.setAuthTokenFacade(() -> Try.failure(new AuthTokenAccessException("Auth token not mocked.")));

release_notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
### ✨ New Functionality
1616

17-
-
17+
- Temporary: Use `email` as fallback principal id when `user_uuid` is missing. Will switch to using `sub` once IAS exposes `idtype` (tracked in [SCICAI-1323](https://jira.tools.sap/browse/SCICAI-1323)).
1818

1919
### 📈 Improvements
2020

0 commit comments

Comments
 (0)