diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/multiuser.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/multiuser.properties index e7735cab73..8fd51dd327 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/multiuser.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/multiuser.properties @@ -110,6 +110,10 @@ che.oidc.allowed_clock_skew_sec=3 # `name` in Dex installations. che.oidc.username_claim=NULL +# Email claim to be used when parsing JWT token +# if not defined the fallback value is 'email'. +che.oidc.email_claim=NULL + # Base URL of an alternate OIDC provider that provides # a discovery endpoint as detailed in the following specification # link:https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[Obtaining OpenID Provider Configuration Information] diff --git a/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/OIDCInfoProvider.java b/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/OIDCInfoProvider.java index cb15930715..c85f141813 100644 --- a/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/OIDCInfoProvider.java +++ b/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/OIDCInfoProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -43,6 +43,7 @@ public class OIDCInfoProvider implements Provider { OIDC_SETTING_PREFIX + "auth_internal_server_url"; public static final String OIDC_PROVIDER_SETTING = OIDC_SETTING_PREFIX + "oidc_provider"; public static final String OIDC_USERNAME_CLAIM_SETTING = OIDC_SETTING_PREFIX + "username_claim"; + public static final String OIDC_EMAIL_CLAIM_SETTING = OIDC_SETTING_PREFIX + "email_claim"; public static final String OIDC_ALLOWED_CLOCK_SKEW_SEC = OIDC_SETTING_PREFIX + "allowed_clock_skew_sec"; diff --git a/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilter.java b/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilter.java index 256011ec9b..edffe04dc8 100644 --- a/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilter.java +++ b/multiuser/oidc/src/main/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -12,6 +12,7 @@ package org.eclipse.che.multiuser.oidc.filter; import static com.google.common.base.Strings.isNullOrEmpty; +import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_EMAIL_CLAIM_SETTING; import static org.eclipse.che.multiuser.oidc.OIDCInfoProvider.OIDC_USERNAME_CLAIM_SETTING; import io.jsonwebtoken.Claims; @@ -40,7 +41,8 @@ import org.eclipse.che.multiuser.api.permission.server.PermissionChecker; * *

It also makes sure that User is present in Che database. If not, it will create the User from * JWT token claims. The username claim is configured with {@link - * org.eclipse.che.multiuser.oidc.OIDCInfoProvider#OIDC_USERNAME_CLAIM_SETTING}. + * org.eclipse.che.multiuser.oidc.OIDCInfoProvider#OIDC_USERNAME_CLAIM_SETTING}. The email claim is + * configured with {@link org.eclipse.che.multiuser.oidc.OIDCInfoProvider#OIDC_EMAIL_CLAIM_SETTING}. */ @Singleton public class OidcTokenInitializationFilter @@ -48,11 +50,13 @@ public class OidcTokenInitializationFilter private static final String EMAIL_CLAIM = "email"; private static final String NAME_CLAIM = "name"; protected static final String DEFAULT_USERNAME_CLAIM = NAME_CLAIM; + protected static final String DEFAULT_EMAIL_CLAIM = EMAIL_CLAIM; private final JwtParser jwtParser; private final PermissionChecker permissionChecker; private final UserManager userManager; private final String usernameClaim; + private final String emailClaim; @Inject public OidcTokenInitializationFilter( @@ -61,12 +65,14 @@ public class OidcTokenInitializationFilter SessionStore sessionStore, RequestTokenExtractor tokenExtractor, UserManager userManager, - @Nullable @Named(OIDC_USERNAME_CLAIM_SETTING) String usernameClaim) { + @Nullable @Named(OIDC_USERNAME_CLAIM_SETTING) String usernameClaim, + @Nullable @Named(OIDC_EMAIL_CLAIM_SETTING) String emailClaim) { super(sessionStore, tokenExtractor); this.permissionChecker = permissionChecker; this.jwtParser = jwtParser; this.userManager = userManager; this.usernameClaim = isNullOrEmpty(usernameClaim) ? DEFAULT_USERNAME_CLAIM : usernameClaim; + this.emailClaim = isNullOrEmpty(emailClaim) ? DEFAULT_EMAIL_CLAIM : emailClaim; } @Override @@ -86,7 +92,7 @@ public class OidcTokenInitializationFilter User user = userManager.getOrCreateUser( claims.getSubject(), - claims.get(EMAIL_CLAIM, String.class), + claims.get(emailClaim, String.class), claims.get(usernameClaim, String.class)); return new AuthorizedSubject( new SubjectImpl(user.getName(), user.getId(), token, false), permissionChecker); diff --git a/multiuser/oidc/src/test/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilterTest.java b/multiuser/oidc/src/test/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilterTest.java index 57f5fd76a5..870ecb6511 100644 --- a/multiuser/oidc/src/test/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilterTest.java +++ b/multiuser/oidc/src/test/java/org/eclipse/che/multiuser/oidc/filter/OidcTokenInitializationFilterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -11,6 +11,7 @@ */ package org.eclipse.che.multiuser.oidc.filter; +import static org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter.DEFAULT_EMAIL_CLAIM; import static org.eclipse.che.multiuser.oidc.filter.OidcTokenInitializationFilter.DEFAULT_USERNAME_CLAIM; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -46,6 +47,7 @@ public class OidcTokenInitializationFilterTest { @Mock private RequestTokenExtractor tokenExtractor; @Mock private UserManager userManager; private final String usernameClaim = "blabolClaim"; + private final String emailClaim = "pafturClaim"; private final String TEST_USERNAME = "jondoe"; private final String TEST_USER_EMAIL = "jon@doe"; private final String TEST_USERID = "jon1337"; @@ -66,11 +68,12 @@ public class OidcTokenInitializationFilterTest { sessionStore, tokenExtractor, userManager, - usernameClaim); + usernameClaim, + emailClaim); lenient().when(jwsClaims.getBody()).thenReturn(claims); lenient().when(claims.getSubject()).thenReturn(TEST_USERID); - lenient().when(claims.get("email", String.class)).thenReturn(TEST_USER_EMAIL); + lenient().when(claims.get(emailClaim, String.class)).thenReturn(TEST_USER_EMAIL); lenient().when(claims.get(usernameClaim, String.class)).thenReturn(TEST_USERNAME); } @@ -124,7 +127,8 @@ public class OidcTokenInitializationFilterTest { sessionStore, tokenExtractor, userManager, - customUsernameClaim); + customUsernameClaim, + emailClaim); User createdUser = mock(User.class); when(createdUser.getId()).thenReturn(TEST_USERID); when(createdUser.getName()).thenReturn(TEST_USERNAME); @@ -142,8 +146,42 @@ public class OidcTokenInitializationFilterTest { verify(claims, never()).get(usernameClaim, String.class); } + @Test(dataProvider = "emailClaims") + public void testDefaultEmailClaimWhenEmpty(String customEmailClaim) + throws ServerException, ConflictException { + tokenInitializationFilter = + new OidcTokenInitializationFilter( + permissionsChecker, + jwtParser, + sessionStore, + tokenExtractor, + userManager, + usernameClaim, + customEmailClaim); + User createdUser = mock(User.class); + when(createdUser.getId()).thenReturn(TEST_USERID); + when(createdUser.getName()).thenReturn(TEST_USERNAME); + when(userManager.getOrCreateUser(TEST_USERID, TEST_USER_EMAIL, TEST_USERNAME)) + .thenReturn(createdUser); + when(claims.get(DEFAULT_EMAIL_CLAIM, String.class)).thenReturn(TEST_USER_EMAIL); + + var subject = tokenInitializationFilter.extractSubject(TEST_TOKEN, jwsClaims); + + assertEquals(subject.getUserId(), TEST_USERID); + assertEquals(subject.getUserName(), TEST_USERNAME); + assertEquals(subject.getToken(), TEST_TOKEN); + verify(userManager).getOrCreateUser(TEST_USERID, TEST_USER_EMAIL, TEST_USERNAME); + verify(claims).get(DEFAULT_EMAIL_CLAIM, String.class); + verify(claims, never()).get(emailClaim, String.class); + } + @DataProvider public static Object[][] usernameClaims() { return new Object[][] {{""}, {null}}; } + + @DataProvider + public static Object[][] emailClaims() { + return new Object[][] {{""}, {null}}; + } }