Skip to content

Commit

Permalink
[P4PU-332] fixed token builder service, fixed token builder service t…
Browse files Browse the repository at this point in the history
…est, fixed CustomAuthenticationSuccessHandlerTest class
  • Loading branch information
oleksiybozhykntt committed Jul 30, 2024
1 parent 090eed5 commit 54232b8
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public class JWTConfiguration {

private String audience;
private String tokenType;
private AccessToken accessToken;

@Getter @Setter @AllArgsConstructor @NoArgsConstructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
)
.successHandler(customAuthenticationSuccessHandler)
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.anyRequest().permitAll());
return http.build();
Expand Down
38 changes: 0 additions & 38 deletions src/main/java/it/gov/pagopa/arc/dto/IamUserInfoDTO.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import it.gov.pagopa.arc.config.JWTConfiguration;
import it.gov.pagopa.arc.model.generated.TokenResponse;
import it.gov.pagopa.arc.utils.CertUtils;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
Expand All @@ -17,6 +16,7 @@
@Service
public class AccessTokenBuilderService {

private final JWTConfiguration jwtConfiguration;
private final String allowedAudience;
private final int expireIn;
private final RSAPublicKey rsaPublicKey;
Expand All @@ -27,7 +27,7 @@ public AccessTokenBuilderService(
) {
this.allowedAudience = jwtConfiguration.getAudience();
this.expireIn = jwtConfiguration.getAccessToken().getExpireIn();

this.jwtConfiguration = jwtConfiguration;
try {
rsaPrivateKey = CertUtils.pemKey2PrivateKey(jwtConfiguration.getAccessToken().getPrivateKey());
rsaPublicKey = CertUtils.pemPub2PublicKey(jwtConfiguration.getAccessToken().getPublicKey());
Expand All @@ -36,17 +36,15 @@ public AccessTokenBuilderService(
}
}

public TokenResponse build(){
public String build(){
Algorithm algorithm = Algorithm.RSA512(rsaPublicKey, rsaPrivateKey);
String tokenType = "bearer";
String token = JWT.create()
.withClaim("typ", tokenType)
return JWT.create()
.withClaim("typ",jwtConfiguration.getTokenType() )
.withIssuer(allowedAudience)
.withJWTId(UUID.randomUUID().toString())
.withIssuedAt(Instant.now())
.withExpiresAt(Instant.now().plusSeconds(expireIn))
.sign(algorithm);
return new TokenResponse(token, tokenType, expireIn,null,null);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package it.gov.pagopa.arc.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import it.gov.pagopa.arc.config.JWTConfiguration;
import it.gov.pagopa.arc.model.generated.TokenResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand All @@ -16,17 +17,21 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess
AccessTokenBuilderService accessTokenBuilderService;
ObjectMapper objectMapper;

JWTConfiguration jwtConfiguration;

CustomAuthenticationSuccessHandler(
AccessTokenBuilderService accessTokenBuilderService,
ObjectMapper objectMapper){
ObjectMapper objectMapper,
JWTConfiguration jwtConfiguration){
this.accessTokenBuilderService = accessTokenBuilderService;
this.objectMapper = objectMapper;
this.jwtConfiguration = jwtConfiguration;
}

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
TokenResponse accessToken = accessTokenBuilderService.build();
TokenResponse accessToken = new TokenResponse(accessTokenBuilderService.build(),jwtConfiguration.getTokenType(),jwtConfiguration.getAccessToken().getExpireIn(),null,null);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write( objectMapper.writeValueAsString(accessToken) );
response.getWriter().flush();
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ spring:

jwt:
audience: "\${JWT_TOKEN_AUDIENCE:application-audience}"
tokenType: "\${JWT_TOKEN_TYPE:Bearer}"
access-token:
expire-in: "\${JWT_TOKEN_EXPIRATION_SECONDS:3600}"
private-key: "\${JWT_TOKEN_PRIVATE_KEY:}"
Expand Down
47 changes: 0 additions & 47 deletions src/test/java/it/gov/pagopa/arc/dto/IamUserInfoDTOTest.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,28 @@ class AccessTokenBuilderServiceTest {

@BeforeEach
void init(){
JWTConfiguration jwtConfiguration = new JWTConfiguration("APPLICATION_AUDIENCE",new AccessToken(EXPIRE_IN,PRIVATE_KEY,PUBLIC_KEY));
JWTConfiguration jwtConfiguration = new JWTConfiguration("APPLICATION_AUDIENCE","Bearer",new AccessToken(EXPIRE_IN,PRIVATE_KEY,PUBLIC_KEY));
accessTokenBuilderService = new AccessTokenBuilderService(jwtConfiguration);
}

@Test
void testException(){
JWTConfiguration jwtConfiguration = new JWTConfiguration("APPLICATION_AUDIENCE",new AccessToken(EXPIRE_IN,PRIVATE_KEY,INVALID_PUBLIC_KEY));
void givenInvalidKeyThenThrowException(){
JWTConfiguration jwtConfiguration = new JWTConfiguration("APPLICATION_AUDIENCE","Bearer",new AccessToken(EXPIRE_IN,PRIVATE_KEY,INVALID_PUBLIC_KEY));
assertThrows(IllegalStateException.class,()-> new AccessTokenBuilderService(jwtConfiguration) );
}

@Test
void test(){
void givenCorrectAccessTokenThenVerifyHeaderAndBodyForRequiredFields(){
// When
TokenResponse result = accessTokenBuilderService.build();
String token = accessTokenBuilderService.build();

// Then
Assertions.assertEquals("bearer", result.getTokenType());
Assertions.assertEquals(EXPIRE_IN, result.getExpiresIn());

DecodedJWT decodedAccessToken = JWT.decode(result.getAccessToken());
DecodedJWT decodedAccessToken = JWT.decode(token);
String decodedHeader = new String(Base64.getDecoder().decode(decodedAccessToken.getHeader()));
String decodedPayload = new String(Base64.getDecoder().decode(decodedAccessToken.getPayload()));

Assertions.assertEquals("{\"alg\":\"RS512\",\"typ\":\"JWT\"}", decodedHeader);
Assertions.assertEquals(EXPIRE_IN, (decodedAccessToken.getExpiresAtAsInstant().toEpochMilli() - decodedAccessToken.getIssuedAtAsInstant().toEpochMilli()) / 1_000);
Assertions.assertTrue(Pattern.compile("\\{\"typ\":\"bearer\",\"iss\":\"APPLICATION_AUDIENCE\",\"jti\":\"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\",\"iat\":[0-9]+,\"exp\":[0-9]+}").matcher(decodedPayload).matches(), "Payload not matches requested pattern: " + decodedPayload);
Assertions.assertTrue(Pattern.compile("\\{\"typ\":\"Bearer\",\"iss\":\"APPLICATION_AUDIENCE\",\"jti\":\"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\",\"iat\":[0-9]+,\"exp\":[0-9]+}").matcher(decodedPayload).matches(), "Payload not matches requested pattern: " + decodedPayload);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.gov.pagopa.arc.config.JWTConfiguration;
import it.gov.pagopa.arc.config.JWTConfiguration.AccessToken;
import it.gov.pagopa.arc.model.generated.TokenResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.Authentication;

public class CustomAuthenticationSuccessHandlerTest {
Expand All @@ -26,56 +34,71 @@ public class CustomAuthenticationSuccessHandlerTest {
private AccessTokenBuilderService accessTokenBuilderService;

@Mock
private ObjectMapper objectMapper;

@InjectMocks
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

@Mock
private HttpServletRequest request;

@Mock
private HttpServletResponse response;
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

@Mock
private Authentication authentication;

@Mock
private TokenResponse tokenResponse;

private StringWriter responseWriter;

@Test
public void testConstructorInjection() {
AccessTokenBuilderService accessTokenBuilderService = Mockito.mock(AccessTokenBuilderService.class);
ObjectMapper objectMapper = Mockito.mock(ObjectMapper.class);

CustomAuthenticationSuccessHandler handler = new CustomAuthenticationSuccessHandler(accessTokenBuilderService, objectMapper);

assertNotNull(handler);
assertNotNull(handler.accessTokenBuilderService);
assertNotNull(handler.objectMapper);
}
public static final int EXPIRE_IN = 3600;

private static final String PRIVATE_KEY= """
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA2ovm/rd3g69dq9PisinQ6mWy8ZttT8D+GKXCsHZycsGnN7b7
4TPyYy+4+h+9cgJeizp8RDRrufHjiBrqi/2reOk/rD7ZHbpfQvHK8MYfgIVdtTxY
MX/GGdOrX6/5TV2b8e2aCG6GmxF0UuEvxY9oTmcZUxnIeDtl/ixz4DQ754eS363q
WfEA92opW+jcYzr07sbQtR86e+Z/s/CUeX6W1PHNvBqdlAgp2ecr/1DOLq1D9hEA
NBPSwbt+FM6FNe4vLphi7GTwiB0yaAuy+jE8odND6HPvvvmgbK1/2qTHn/HJjWUm
11LUC73BszR32BKbdEEhxPQnnwswVekWzPi1IwIDAQABAoIBAFH4aWKeY8hTjTm2
lm+muYJBNNXkKyLfyy5pddWEB7c9JUADdQPp3P8Q1juSjhbmBpoIDLX0R3eN336c
Qd7R/W+zZLtxMzQwRCyyziBy3zvwSc6BXL7sItxrBPs14LcA5k3ehYimE/yzlkLD
zYw3FrNZfikqIYPfG4kzGR892D4lbSMTTzXgBtPEyM3TmBTDwbJ5hk6xMx9AwGec
mwz8izWNFhgc3LxrI4KnMZz6dikhScCThTHL58ZdgSdMHPjTK+Xhh7pnwFF5D3bt
H5jVsuqDX107mo/TeKyovt2H6xQMleVfjWUW6JJUxEoRtPSYBg0ogtbK337k8AoG
BqldO6ECgYEA6oXwrG+lAEe/wLwgLqT2kpjPiK8JHw0MzfzljHI0H9Sh7/ga5yrK
WZyMEm2JlhyGSXdMzm4CCeNsP4fJVVo1uZiYGZkl0wOlPSsd6DkXfLfC4qiyU2qm
Vk0BgiQRKwoWrFv2mPl9/AJWRSbrCk4223K2yWzieYgwyfY4nJ5h8BECgYEA7o9p
QYbzNhrDMyObawNz4UwR3zhMzmmnopGHn8XO9OmARDDM1CGci37TJUYK9tajjFIz
H0YwLcL/6/cu8kxs35hXBdmZgYv+jmT8zekMNp37kqjm4u+Ac8UnleCUqufdEpIY
Uvnak08C9XZtPkYvVJlQ8KyotXRsXvLYo5i5hfMCgYA/NPAjmUdwJuZATLOjvqQR
6ItufDZKHxtHXRSE4La5qXYnlceya+7zbeS2hr0hLvjmTffuXum/voKLMM6LaW+3
YLAFnif6ki3zqW47C0AQRfqJWgwNvV2tPr3cVFooLmTj+TkiC4Pv6rVTl+Sa92+D
f4xSBz2WoaT8mZayZ2Ff8QKBgDHtacYBDF3CdB/7z8cxzcrVNNhW3BxHGIJ5mrzh
lVLEm8epvvSWpEC9pksiwaCvg0MW4QQmmGa7bPxhmz2yqQaSx4O96tamCfybPh2K
LLgxkDk9iDTukx+nn4VKn1K1fBsq4FRdXlV+L8xXoL1ryvQVsk7sk9KGLzgf8x8q
E4npAoGABrR0F9hWlqGaENoXujNEN7LTzsVWXRD490dn0oawVYPzpuX0l2vCjNp/
veDYA00ElNOLz9WdkniU7BuTf9+9oWZCDXbJvK7HvidxVv0owbx02CxDL+UV98kr
XtIA8ZH/XPiyad0JjP4wDTgygKzmYdXgmVjO9/NcOA2jpvyugdw=
-----END RSA PRIVATE KEY-----
""";

private static final String PUBLIC_KEY= """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ovm/rd3g69dq9PisinQ
6mWy8ZttT8D+GKXCsHZycsGnN7b74TPyYy+4+h+9cgJeizp8RDRrufHjiBrqi/2r
eOk/rD7ZHbpfQvHK8MYfgIVdtTxYMX/GGdOrX6/5TV2b8e2aCG6GmxF0UuEvxY9o
TmcZUxnIeDtl/ixz4DQ754eS363qWfEA92opW+jcYzr07sbQtR86e+Z/s/CUeX6W
1PHNvBqdlAgp2ecr/1DOLq1D9hEANBPSwbt+FM6FNe4vLphi7GTwiB0yaAuy+jE8
odND6HPvvvmgbK1/2qTHn/HJjWUm11LUC73BszR32BKbdEEhxPQnnwswVekWzPi1
IwIDAQAB
-----END PUBLIC KEY-----
""";

@BeforeEach
public void setUp() throws Exception {
MockitoAnnotations.openMocks(this);
responseWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(responseWriter);

when(response.getWriter()).thenReturn(printWriter);
when(accessTokenBuilderService.build()).thenReturn(tokenResponse);
when(objectMapper.writeValueAsString(any())).thenReturn("accessTokenResponse");
void setUp(){
JWTConfiguration jwtConfiguration = new JWTConfiguration("APPLICATION_AUDIENCE","Bearer",new AccessToken(EXPIRE_IN,PRIVATE_KEY,PUBLIC_KEY));
accessTokenBuilderService = new AccessTokenBuilderService(jwtConfiguration);
customAuthenticationSuccessHandler = new CustomAuthenticationSuccessHandler(accessTokenBuilderService,new ObjectMapper(),jwtConfiguration);
}

@Test
public void testOnAuthenticationSuccess() throws Exception {
customAuthenticationSuccessHandler.onAuthenticationSuccess(request, response, authentication);

verify(accessTokenBuilderService).build();
verify(objectMapper).writeValueAsString(tokenResponse);
verify(response).setContentType(MediaType.APPLICATION_JSON_VALUE);
assertEquals("accessTokenResponse", responseWriter.toString().trim());
void givenAuthenticationRequestThenInResponseGetCustomTokenResponse() throws IOException {
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest();
customAuthenticationSuccessHandler.onAuthenticationSuccess(request,response,authentication);
assertEquals(response.getHeader("Content-Type"),"application/json");
TokenResponse token = customAuthenticationSuccessHandler.objectMapper.readValue(response.getContentAsString(),TokenResponse.class);
assertNotNull(token.getAccessToken());
assertNotNull(token.getTokenType());
assertNotNull(token.getExpiresIn());
}

}

0 comments on commit 54232b8

Please sign in to comment.