Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
class OidcAuthTokenPrincipalExtractor implements PrincipalExtractor
{
private static final String JWT_USER_UUID_CLAIM = "user_uuid";
private static final String JWT_EMAIL_CLAIM = "email";

@Override
@Nonnull
Expand Down Expand Up @@ -43,11 +44,16 @@ private Try<String> tryGetPrincipalId( @Nonnull final DecodedJWT jwt )
return Try.of(() -> {
final Claim userUuidClaim = jwt.getClaim(JWT_USER_UUID_CLAIM);

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

return userUuidClaim.asString();
final Claim emailClaim = jwt.getClaim(JWT_EMAIL_CLAIM);
if( emailClaim != null && !emailClaim.isMissing() && !emailClaim.isNull() ) {
return emailClaim.asString();
}

throw new PrincipalAccessException("The current JWT does not contain the IAS user uuid or an email.");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,35 @@ void testCaseInsensitiveBearer()
assertThat(jwt).isNotNull();
assertThat(jwt.getClaim("user_uuid").asString()).isEqualTo("5a21dfa1-fd90-45ff-a5d3-d1cfa446d25a");
}

@Test
void testDecodeSucceedsWithEmailOnly( @Nonnull final WireMockRuntimeInfo wm )
{
final Token tokenOnlyEmail =
JwtGenerator
.getInstance(Service.IAS, "2aba8ab2-edc3-4666-b2ed-90b2b47e60e3")
.withHeaderParameter(TokenHeader.KEY_ID, "testKey")
.withClaimValue("iss", wm.getHttpBaseUrl())
.withClaimValues("aud", "1668e3ce-e2b8-4d27-a05b-3db47e7a4152", "2aba8ab2-edc3-4666-b2ed-90b2b47e60e3")
.withClaimValue("sub", "sub-only-email")
// intentionally omit user_uuid
.withClaimValue("email", "[email protected]")
.withExpiration(OffsetDateTime.now().plusDays(1).toInstant())
.withPrivateKey(RSA_KEYS.getPrivate())
.createToken();

final String tokenValue = tokenOnlyEmail.getTokenValue();

final RequestHeaderContainer headers =
DefaultRequestHeaderContainer
.fromSingleValueMap(Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Bearer " + tokenValue));

final AuthToken authToken = new AuthTokenDecoderDefault().decode(headers).getOrNull();

assertThat(authToken).isNotNull();

final DecodedJWT jwt = authToken.getJwt();
assertThat(jwt).isNotNull();
assertThat(jwt.getClaim("email").asString()).isEqualTo("[email protected]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ void testReadPrincipal()
assertThat(principal.getPrincipalId()).isEqualTo("principal id");
}

@Test
void testReadPrincipalFromEmailFallback()
{
mockAuthTokenFacade(JWT.create().withClaim("email", "[email protected]"));

final Principal principal = new OidcAuthTokenPrincipalExtractor().tryGetCurrentPrincipal().get();

assertThat(principal.getPrincipalId()).isEqualTo("[email protected]");
}

private void mockAuthTokenFacadeWithMissingAuthToken()
{
AuthTokenAccessor.setAuthTokenFacade(() -> Try.failure(new AuthTokenAccessException("Auth token not mocked.")));
Expand Down
2 changes: 1 addition & 1 deletion release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

### ✨ New Functionality

-
- 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)).

### 📈 Improvements

Expand Down