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
5 changes: 5 additions & 0 deletions src/main/java/com/descope/model/auth/AuthenticationInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ public class AuthenticationInfo {
private Token refreshToken;
private UserResponse user;
private Boolean firstSeen;
private IDPResponse idpResponse;

public AuthenticationInfo(Token token, Token refreshToken, UserResponse user, Boolean firstSeen) {
this(token, refreshToken, user, firstSeen, null);
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/descope/model/auth/IDPResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.descope.model.auth;

import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class IDPResponse {
private List<String> idpGroups;
private Map<String, Object> idpSAMLAttributes;
private Map<String, Object> idpOIDCClaims;
Comment thread
dorsha marked this conversation as resolved.
}
8 changes: 8 additions & 0 deletions src/main/java/com/descope/model/jwt/response/JWTResponse.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.descope.model.jwt.response;

import com.descope.model.auth.IDPResponse;
import com.descope.model.user.response.UserResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
Expand All @@ -17,4 +18,11 @@ public class JWTResponse {
private Integer cookieExpiration;
private UserResponse user;
private Boolean firstSeen;
private IDPResponse idpResponse;
Comment thread
dorsha marked this conversation as resolved.

public JWTResponse(String sessionJwt, String refreshJwt, String cookieDomain, String cookiePath,
Integer cookieMaxAge, Integer cookieExpiration, UserResponse user, Boolean firstSeen) {
this(sessionJwt, refreshJwt, cookieDomain, cookiePath, cookieMaxAge, cookieExpiration, user,
firstSeen, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public AuthenticationInfo validateAndRefreshSessionWithTokensAuthenticationInfo(
} else if (StringUtils.isNotBlank(sessionToken)) {
try {
Token refresh = validateAndCreateToken(refreshToken);
return new AuthenticationInfo(validateSessionWithToken(sessionToken), refresh, null, null);
return new AuthenticationInfo(validateSessionWithToken(sessionToken), refresh, null, null, null);
} catch (Exception e) {
if (StringUtils.isNotBlank(refreshToken)) {
return refreshSessionWithTokenAuthenticationInfo(refreshToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ AuthenticationInfo getAuthenticationInfo(JWTResponse jwtResponse) {
refreshToken = validateAndCreateToken(jwtResponse.getRefreshJwt());
}
return new AuthenticationInfo(
sessionToken, refreshToken, jwtResponse.getUser(), jwtResponse.getFirstSeen());
sessionToken, refreshToken, jwtResponse.getUser(), jwtResponse.getFirstSeen(),
jwtResponse.getIdpResponse());
}

@SuppressWarnings("unchecked")
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/descope/sdk/mgmt/impl/JwtServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ private AuthenticationInfo validateAndCreateAuthInfo(JWTResponse jwtResponse) th
}
Token sessionToken = validateAndCreateToken(jwtResponse.getSessionJwt());
Token refreshToken = validateAndCreateToken(jwtResponse.getRefreshJwt());
return new AuthenticationInfo(sessionToken, refreshToken, jwtResponse.getUser(), jwtResponse.getFirstSeen());
return new AuthenticationInfo(sessionToken, refreshToken, jwtResponse.getUser(), jwtResponse.getFirstSeen(),
jwtResponse.getIdpResponse());
}

private URI composeUpdateJwtUri() {
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/com/descope/sdk/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ public class TestUtils {
1234567,
1234567890,
MOCK_USER_RESPONSE,
true);
true,
null);
public static final Map<String, Object> TENANTS_AUTHZ = mapOf("permissions", Arrays.asList("tp1", "tp2"), "roles",
Arrays.asList("tr1", "tr2"));
public static final Token MOCK_TOKEN = Token.builder()
Expand Down
61 changes: 61 additions & 0 deletions src/test/java/com/descope/sdk/auth/impl/OAuthServiceImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import static org.mockito.Mockito.mockStatic;

import com.descope.model.auth.AuthenticationInfo;
import com.descope.model.auth.IDPResponse;
import com.descope.model.auth.OAuthResponse;
import com.descope.model.client.Client;
import com.descope.model.jwt.Token;
import com.descope.model.jwt.response.JWTResponse;
import com.descope.model.jwt.response.SigningKeysResponse;
import com.descope.model.magiclink.LoginOptions;
import com.descope.model.user.response.UserResponse;
Expand Down Expand Up @@ -111,6 +113,65 @@ void testExchangeToken() {
Assertions.assertThat(user.getLoginIds()).isNotEmpty();
}

@Test
void testExchangeTokenWithoutIDPResponse() {
JWTResponse jwtResponseNoIdp = new JWTResponse(
"someSessionJwt", "someRefreshJwt", "", "/", 1234567, 1234567890,
MOCK_JWT_RESPONSE.getUser(), true);

ApiProxy apiProxy = mock(ApiProxy.class);
doReturn(jwtResponseNoIdp).when(apiProxy).post(any(), any(), any());
doReturn(new SigningKeysResponse(Arrays.asList(MOCK_SIGNING_KEY))).when(apiProxy).get(any(),
eq(SigningKeysResponse.class));

AuthenticationInfo authenticationInfo;
try (MockedStatic<ApiProxyBuilder> mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) {
mockedApiProxyBuilder.when(() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy);
try (MockedStatic<JwtUtils> mockedJwtUtils = mockStatic(JwtUtils.class)) {
mockedJwtUtils.when(() -> JwtUtils.getToken(anyString(), any())).thenReturn(MOCK_TOKEN);
authenticationInfo = oauthService.exchangeToken("somecode");
}
}

Assertions.assertThat(authenticationInfo).isNotNull();
Assertions.assertThat(authenticationInfo.getUser()).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse()).isNull();
}

@Test
void testExchangeTokenWithIDPResponse() {
IDPResponse idpResponse = new IDPResponse(
Arrays.asList("users"),
null,
mapOf("email_verified", true, "locale", "en-US"));
JWTResponse jwtResponseWithIdp = new JWTResponse(
"someSessionJwt", "someRefreshJwt", "", "/", 1234567, 1234567890,
MOCK_JWT_RESPONSE.getUser(), true, idpResponse);

ApiProxy apiProxy = mock(ApiProxy.class);
doReturn(jwtResponseWithIdp).when(apiProxy).post(any(), any(), any());
doReturn(new SigningKeysResponse(Arrays.asList(MOCK_SIGNING_KEY))).when(apiProxy).get(any(),
eq(SigningKeysResponse.class));

AuthenticationInfo authenticationInfo;
try (MockedStatic<ApiProxyBuilder> mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) {
mockedApiProxyBuilder.when(() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy);
try (MockedStatic<JwtUtils> mockedJwtUtils = mockStatic(JwtUtils.class)) {
mockedJwtUtils.when(() -> JwtUtils.getToken(anyString(), any())).thenReturn(MOCK_TOKEN);
authenticationInfo = oauthService.exchangeToken("somecode");
}
}

Assertions.assertThat(authenticationInfo).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse()).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpGroups())
.isEqualTo(Arrays.asList("users"));
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpSAMLAttributes()).isNull();
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpOIDCClaims())
.containsEntry("email_verified", true)
.containsEntry("locale", "en-US");
}

void testExampleRequireBrowser() throws Exception {
System.out.println(oauthService.start(OAUTH_PROVIDER_GOOGLE, "https://localhost/kuku", null));
String encodedCode = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static com.descope.sdk.TestUtils.MOCK_TOKEN;
import static com.descope.sdk.TestUtils.MOCK_URL;
import static com.descope.sdk.TestUtils.PROJECT_ID;
import static com.descope.utils.CollectionUtils.mapOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
Expand All @@ -13,9 +14,11 @@
import static org.mockito.Mockito.mockStatic;

import com.descope.model.auth.AuthenticationInfo;
import com.descope.model.auth.IDPResponse;
import com.descope.model.auth.SAMLResponse;
import com.descope.model.client.Client;
import com.descope.model.jwt.Token;
import com.descope.model.jwt.response.JWTResponse;
import com.descope.model.jwt.response.SigningKeysResponse;
import com.descope.model.magiclink.LoginOptions;
import com.descope.model.user.response.UserResponse;
Expand Down Expand Up @@ -88,4 +91,65 @@ void testExchangeToken() {
Assertions.assertThat(user.getUserId()).isNotBlank();
Assertions.assertThat(user.getLoginIds()).isNotEmpty();
}

@Test
void testExchangeTokenWithoutIDPResponse() {
JWTResponse jwtResponseNoIdp = new JWTResponse(
"someSessionJwt", "someRefreshJwt", "", "/", 1234567, 1234567890,
MOCK_JWT_RESPONSE.getUser(), true);

ApiProxy apiProxy = mock(ApiProxy.class);
doReturn(jwtResponseNoIdp).when(apiProxy).post(any(), any(), any());
doReturn(new SigningKeysResponse(Arrays.asList(MOCK_SIGNING_KEY)))
.when(apiProxy).get(any(), eq(SigningKeysResponse.class));

AuthenticationInfo authenticationInfo;
try (MockedStatic<ApiProxyBuilder> mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) {
mockedApiProxyBuilder.when(
() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy);
try (MockedStatic<JwtUtils> mockedJwtUtils = mockStatic(JwtUtils.class)) {
mockedJwtUtils.when(() -> JwtUtils.getToken(anyString(), any())).thenReturn(MOCK_TOKEN);
authenticationInfo = samlService.exchangeToken("somecode");
}
}

Assertions.assertThat(authenticationInfo).isNotNull();
Assertions.assertThat(authenticationInfo.getUser()).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse()).isNull();
}

@Test
void testExchangeTokenWithIDPResponse() {
IDPResponse idpResponse = new IDPResponse(
Arrays.asList("engineering", "devops"),
mapOf("department", "engineering", "title", "Staff Engineer"),
null);
JWTResponse jwtResponseWithIdp = new JWTResponse(
"someSessionJwt", "someRefreshJwt", "", "/", 1234567, 1234567890,
MOCK_JWT_RESPONSE.getUser(), true, idpResponse);

ApiProxy apiProxy = mock(ApiProxy.class);
doReturn(jwtResponseWithIdp).when(apiProxy).post(any(), any(), any());
doReturn(new SigningKeysResponse(Arrays.asList(MOCK_SIGNING_KEY)))
.when(apiProxy).get(any(), eq(SigningKeysResponse.class));

AuthenticationInfo authenticationInfo;
try (MockedStatic<ApiProxyBuilder> mockedApiProxyBuilder = mockStatic(ApiProxyBuilder.class)) {
mockedApiProxyBuilder.when(
() -> ApiProxyBuilder.buildProxy(any(), any())).thenReturn(apiProxy);
try (MockedStatic<JwtUtils> mockedJwtUtils = mockStatic(JwtUtils.class)) {
mockedJwtUtils.when(() -> JwtUtils.getToken(anyString(), any())).thenReturn(MOCK_TOKEN);
authenticationInfo = samlService.exchangeToken("somecode");
}
}

Assertions.assertThat(authenticationInfo).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse()).isNotNull();
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpGroups())
.isEqualTo(Arrays.asList("engineering", "devops"));
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpSAMLAttributes())
.containsEntry("department", "engineering")
.containsEntry("title", "Staff Engineer");
Assertions.assertThat(authenticationInfo.getIdpResponse().getIdpOIDCClaims()).isNull();
}
}
Loading