diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java index ffc5d59cbaf..94787f70a00 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClient.java @@ -103,7 +103,7 @@ public String getAccountLinkingURL( byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); final String hash = Base64.getUrlEncoder().encodeToString(check); - return UriBuilder.fromUri(oidcInfo.getAuthServerURL()) + return UriBuilder.fromUri(oidcInfo.getAuthServerPublicURL()) .path("/realms/{realm}/broker/{provider}/link") .queryParam("nonce", nonce) .queryParam("hash", hash) diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfo.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfo.java index ce2c6adc89b..9cafae6e67d 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfo.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfo.java @@ -22,6 +22,7 @@ public class OIDCInfo { private final String jwksPublicUri; private final String jwksUri; private final String authServerURL; + private final String authServerPublicURL; public OIDCInfo( String tokenPublicEndpoint, @@ -30,7 +31,8 @@ public OIDCInfo( String userInfoEndpoint, String jwksPublicUri, String jwksUri, - String authServerURL) { + String authServerURL, + String authServerPublicURL) { this.tokenPublicEndpoint = tokenPublicEndpoint; this.endSessionPublicEndpoint = endSessionPublicEndpoint; this.userInfoPublicEndpoint = userInfoPublicEndpoint; @@ -39,6 +41,7 @@ public OIDCInfo( this.jwksUri = jwksUri; this.authServerURL = authServerURL; + this.authServerPublicURL = authServerPublicURL; } /** @return public url to retrieve token */ @@ -84,4 +87,9 @@ public String getJwksUri() { public String getAuthServerURL() { return authServerURL; } + + /** @return public OIDC auth endpoint url. */ + public String getAuthServerPublicURL() { + return authServerPublicURL; + } } diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProvider.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProvider.java index f0ccf5a8259..e511766c46d 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProvider.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/main/java/org/eclipse/che/multiuser/keycloak/server/OIDCInfoProvider.java @@ -92,7 +92,8 @@ public OIDCInfo get() { userInfoEndpoint, jwksPublicUri, jwksUri, - serverAuthUrl); + serverAuthUrl, + serverURL); } catch (IOException e) { throw new RuntimeException( "Exception while retrieving OpenId configuration from endpoint: " + wellKnownEndpoint, e); diff --git a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java index 28fd9f58d9b..665655fd36e 100644 --- a/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java +++ b/multiuser/keycloak/che-multiuser-keycloak-server/src/test/java/org/eclipse/che/multiuser/keycloak/server/KeycloakServiceClientTest.java @@ -13,13 +13,17 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.AUTH_SERVER_URL_INTERNAL_SETTING; import static org.eclipse.che.multiuser.keycloak.shared.KeycloakConstants.REALM_SETTING; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import com.jayway.restassured.RestAssured; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; import io.jsonwebtoken.JwtParser; import java.util.HashMap; import java.util.Map; @@ -55,12 +59,19 @@ public class KeycloakServiceClientTest { @Mock private KeycloakSettings keycloakSettings; @Mock private JwtParser jwtParser; @Mock private OIDCInfo oidcInfo; + @Mock private Jws jws; + @Mock private Claims claims; private KeycloakServiceClient keycloakServiceClient; @SuppressWarnings("unused") private KeycloakService keycloakService; + private static final String token = "token123"; + private static final String clientId = "some-client-id"; + private static final String someSessionState = "some-state"; + private static final String scope = "test_scope"; + @SuppressWarnings("unused") private final LocalApiExceptionMapper exceptionMapper = new LocalApiExceptionMapper(); @@ -68,22 +79,43 @@ public class KeycloakServiceClientTest { public void setUp() throws Exception { when(oidcInfo.getAuthServerURL()) .thenReturn(RestAssured.baseURI + ":" + RestAssured.port + RestAssured.basePath); + when(oidcInfo.getAuthServerPublicURL()).thenReturn("https://keycloak-che"); + when(jwtParser.parseClaimsJws(token)).thenReturn(jws); + when(jws.getBody()).thenReturn(claims); + when(claims.get(anyString(), eq(String.class))) + .thenAnswer( + invocationOnMock -> { + String arg = (String) invocationOnMock.getArguments()[0]; + if (arg.equals("azp")) { + return clientId; + } + if (arg.equals("session_state")) { + return someSessionState; + } + return null; + }); keycloakServiceClient = new KeycloakServiceClient(keycloakSettings, oidcInfo, jwtParser); - Map conf = new HashMap<>(); Map confInternal = new HashMap<>(); - confInternal.put( - AUTH_SERVER_URL_INTERNAL_SETTING, - RestAssured.baseURI + ":" + RestAssured.port + RestAssured.basePath); - conf.put(REALM_SETTING, "che"); + confInternal.put(REALM_SETTING, "che"); when(keycloakSettings.get()).thenReturn(confInternal); - when(keycloakSettings.get()).thenReturn(conf); + } + + @Test + public void shouldReturnPublicAccountLinkingURL() throws Exception { + keycloakService = new KeycloakService(token, scope, token, null); + keycloakServiceClient.getIdentityProviderToken("github"); + + String accountLinkURL = + keycloakServiceClient.getAccountLinkingURL( + token, "github", "https://some-redirect-link/auth/realms/che/broker/github/endpoint"); + assertTrue( + accountLinkURL.matches( + "https://keycloak-che/realms/che/broker/github/link\\?nonce=([0-9a-z-]*)&hash=([0-9A-Za-z-_%]*)&client_id=some-client-id&redirect_uri=https://some-redirect-link/auth/realms/che/broker/github/endpoint")); } @Test public void shouldReturnToken() throws Exception { - String token = "token123"; - String scope = "test_scope"; String tokenType = "test_type"; keycloakService = new KeycloakService(token, scope, tokenType, null); KeycloakTokenResponse response = keycloakServiceClient.getIdentityProviderToken("github");