Skip to content
Snippets Groups Projects
Commit 80c3d567 authored by Mathieu.Vonlanthen's avatar Mathieu.Vonlanthen
Browse files

refactor(LoginITService): introduce LoginResult record

parent 4da427d9
No related branches found
No related tags found
No related merge requests found
......@@ -8,11 +8,14 @@ import static ch.unige.solidify.auth.AuthConstants.UNIQUE_ID_HEADER;
import static ch.unige.solidify.auth.AuthTestConstants.AUTHORIZE_ENDPOINT;
import static ch.unige.solidify.auth.AuthTestConstants.CLIENT_BACKEND_ID;
import static ch.unige.solidify.auth.AuthTestConstants.CLIENT_BACKEND_SECRET;
import static ch.unige.solidify.auth.AuthTestConstants.CLIENT_PORTAL_ID;
import static ch.unige.solidify.auth.AuthTestConstants.CLIENT_PORTAL_MFA_ID;
import static ch.unige.solidify.auth.AuthTestConstants.IS_MFA;
import static ch.unige.solidify.auth.AuthTestConstants.IS_NOT_MFA;
import static ch.unige.solidify.auth.AuthTestConstants.LOGIN_URL;
import static ch.unige.solidify.auth.AuthTestConstants.MFA_LOGIN_URL;
import static ch.unige.solidify.auth.AuthTestConstants.NOT_EXISTING_URL;
import static ch.unige.solidify.auth.AuthTestConstants.TEST_USER_UNIQUE_ID;
import static ch.unige.solidify.auth.AuthTestConstants.TOKEN_ENDPOINT;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
......@@ -97,7 +100,7 @@ class AuthenticationIT {
assertTrue(jSessionId.isPresent());
// Login
final ResponseEntity<String> loginResponse = this.loginITService.login(jSessionId.get(), IS_NOT_MFA);
final ResponseEntity<String> loginResponse = this.loginITService.login(jSessionId.get(), IS_NOT_MFA).loginEndpointResponse();
assertEquals(HttpStatus.FOUND, loginResponse.getStatusCode());
// Second attempt to call /oauth2/authorize with correct jSessionId and code challenge
......@@ -127,7 +130,7 @@ class AuthenticationIT {
@Test
void unauthorizedIfExpiredToken() {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
this.loginITService.waitTokenExpiration();
final ResponseEntity<String> response = this.userIT.useUserInfoEndpoint(token);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode(), "Expected 401 OK but got " + response.getStatusCode());
......@@ -136,7 +139,7 @@ class AuthenticationIT {
@Test
void unauthorizedIfForgedRootToken() throws ParseException {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
final String forgedToken = this.forgeToken((SignedJWT) JWTParser.parse(token), true, false);
final ResponseEntity<String> response = this.userIT.useUserInfoEndpoint(forgedToken);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode(), "Expected 401 OK but got " + response.getStatusCode());
......@@ -145,7 +148,7 @@ class AuthenticationIT {
@Test
void unauthorizedIfForgedBackInTimeToken() throws ParseException {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA);
final String token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
final String forgedToken = this.forgeToken((SignedJWT) JWTParser.parse(token), false, true);
final ResponseEntity<String> response = this.userIT.useUserInfoEndpoint(forgedToken);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode(), "Expected 401 OK but got " + response.getStatusCode());
......@@ -175,7 +178,7 @@ class AuthenticationIT {
assertTrue(jSessionId.isPresent());
// Simulate manipulated 302 redirect to not-MFA login
final ResponseEntity<String> loginResponse = this.loginITService.login(jSessionId.get(), IS_NOT_MFA);
final ResponseEntity<String> loginResponse = this.loginITService.login(jSessionId.get(), IS_NOT_MFA).loginEndpointResponse();
assertEquals(HttpStatus.FOUND, loginResponse.getStatusCode());
assertNotNull(loginResponse.getHeaders().getLocation());
assertEquals(LOGIN_URL, loginResponse.getHeaders().getLocation().toString());
......@@ -211,8 +214,10 @@ class AuthenticationIT {
@ParameterizedTest
@ValueSource(booleans = { false, true })
void loginPageTest(boolean isMfa) {
final String clientId = isMfa ? CLIENT_PORTAL_MFA_ID : CLIENT_PORTAL_ID;
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(isMfa);
assertNotNull(this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), isMfa));
final String accessToken = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
this.loginITService.verifyToken(accessToken, TEST_USER_UNIQUE_ID, clientId, ApplicationRole.USER, isMfa);
}
@Test
......
......@@ -33,6 +33,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
......@@ -63,6 +64,7 @@ class ParallelsCallWithRenewedAccessTokenIT {
this.loginITService = new LoginITService(clientITService);
}
@Disabled("WIP")
@Test
void parallelCallsWithAccessTokenCheckedDirectly() throws InterruptedException {
this.results = new HashMap<>();
......
......@@ -40,7 +40,7 @@ class UserIT {
@Test
void useUserInfoEndpointTest() {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA);
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
final ResponseEntity<String> response = this.useUserInfoEndpoint(oAuth2Token);
assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode(), "Expected 403 OK but got " + response.getStatusCode());
}
......@@ -57,7 +57,7 @@ class UserIT {
@Test
void useLoginInfosEndpointTest() {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA); final ResponseEntity<String> response = restClient.get()
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse()); final ResponseEntity<String> response = restClient.get()
.uri(USER_ENDPOINT + USER_LOGIN_INFOS_ENDPOINT, TEST_USER_EXTERNAL_UID)
.headers(headers -> headers.setBearerAuth(oAuth2Token))
.retrieve()
......@@ -69,7 +69,7 @@ class UserIT {
@Test
void useChangeRoleEndpointTest() {
final LoginITService.LoginResult loginResult = this.loginITService.getLoginResult(IS_NOT_MFA);
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse(), IS_NOT_MFA);
final String oAuth2Token = this.loginITService.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse());
final ResponseEntity<String> response = restClient.post()
.uri(USER_ENDPOINT + USER_CHANGE_ROLE_ENDPOINT, TEST_USER_EXTERNAL_UID)
.headers(headers -> headers.setBearerAuth(oAuth2Token))
......
......@@ -83,7 +83,8 @@ public class LoginITService {
assertTrue(jSessionId.isPresent());
// Simulate 302 redirect to log in Shibboleth pre-authentication
final ResponseEntity<String> loginResponse = this.login(jSessionId.get(), isMfa);
final LoginResult loginResult = this.login(jSessionId.get(), isMfa);
final ResponseEntity<String> loginResponse = loginResult.loginEndpointResponse();
assertEquals(HttpStatus.FOUND, loginResponse.getStatusCode());
// Second attempt to call /oauth2/authorize with credentials
......@@ -94,12 +95,12 @@ public class LoginITService {
assertEquals(HttpStatus.OK, tokenEndpointResponse.getStatusCode());
assertNull(tokenEndpointResponse.getHeaders().getFirst(HttpHeaders.SET_COOKIE));
assertNotNull(tokenEndpointResponse.getBody());
return new LoginResult(tokenEndpointResponse, jSessionId.get());
return new LoginResult(loginResult.loginEndpointResponse, tokenEndpointResponse, loginResult.jSessionId(), loginResult.randomUserId);
}
public void getSecondAuthorizationCodeWithSameJSessionIdAfterTokenExpiration() {
final LoginResult loginResult = this.getLoginResult(IS_NOT_MFA);
final String token1 = this.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse, IS_NOT_MFA);
final String token1 = this.getTokenFromTokenEndpointResponse(loginResult.tokenEndpointResponse);
this.waitTokenExpiration();
......@@ -112,7 +113,7 @@ public class LoginITService {
// Exchange authorization code for an OAuth2 access token
final ResponseEntity<String> tokenEndpointResponse2 = this.getTokenEndpointResponse(authorizationCode2, pkceCodeExchange.codeVerifier,
IS_NOT_MFA);
final String token2 = this.getTokenFromTokenEndpointResponse(tokenEndpointResponse2, IS_NOT_MFA);
final String token2 = this.getTokenFromTokenEndpointResponse(tokenEndpointResponse2);
assertNotNull(token2);
assertNotEquals(token1, token2);
}
......@@ -157,8 +158,7 @@ public class LoginITService {
.toEntity(String.class);
}
public String getTokenFromTokenEndpointResponse(ResponseEntity<String> tokenEndpointResponse, boolean isMfa) {
final String clientId = isMfa ? CLIENT_PORTAL_MFA_ID : CLIENT_PORTAL_ID;
public String getTokenFromTokenEndpointResponse(ResponseEntity<String> tokenEndpointResponse) {
final ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = null;
try {
......@@ -166,9 +166,7 @@ public class LoginITService {
} catch (JsonProcessingException e) {
fail(e.getMessage());
}
final String accessToken = jsonNode.get("access_token").asText();
this.verifyToken(accessToken, TEST_USER_UNIQUE_ID, clientId, ApplicationRole.USER, isMfa);
return accessToken;
return jsonNode.get("access_token").asText();
}
public Optional<String> getJSessionId(ResponseEntity<String> response) {
......@@ -227,12 +225,21 @@ public class LoginITService {
}
public ResponseEntity<String> login(String jSessionId, boolean isMfa) {
final int randomId = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
return this.useLoginUrl(TEST_USER_UNIQUE_ID + randomId, TEST_USER_MAIL + randomId, TEST_USER_SURNAME + randomId,
public LoginResult login(String jSessionId, boolean isMfa) {
return this.login(jSessionId, isMfa, false);
}
public LoginResult login(String jSessionId, boolean isMfa, boolean randomUser) {
String randomId = "";
if (randomUser) {
randomId = Integer.toString(ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
}
final ResponseEntity<String> loginEndpointResponse = this.useLoginUrl(TEST_USER_UNIQUE_ID + randomId, TEST_USER_MAIL + randomId, TEST_USER_SURNAME + randomId,
TEST_USER_GIVEN_NAME + randomId, TEST_USER_HOME_ORG, jSessionId, isMfa);
return new LoginResult(loginEndpointResponse, null, jSessionId, randomId);
}
public void verifyToken(String accessToken, String jwtSubject, String jwtAudience, ApplicationRole applicationRole, boolean isMfa) {
final String[] chunks = accessToken.split("\\.");
final Base64.Decoder decoder = Base64.getUrlDecoder();
......@@ -281,6 +288,10 @@ public class LoginITService {
}
}
public record LoginResult(ResponseEntity<String> tokenEndpointResponse, String jSessionId) {}
public record PkceCodeExchange(String codeVerifier, String codeChallenge) {}
public record LoginResult(ResponseEntity<String> loginEndpointResponse,
ResponseEntity<String> tokenEndpointResponse,
String jSessionId,
String randomUserId) {}
public record PkceCodeExchange(String codeVerifier,
String codeChallenge) {}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment