Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: P4PU-329 save access token #43

Merged
merged 4 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
37 changes: 37 additions & 0 deletions src/main/java/it/gov/pagopa/arc/dto/IamUserInfoDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package it.gov.pagopa.arc.dto;

import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

@Getter @Setter
@AllArgsConstructor
@RequiredArgsConstructor
public class IamUserInfoDTO {


private String userId;
private String fiscalCode;
private String familyName;
private String name;
private String email;
private String issuer;

public static IamUserInfoDTO map2IamUserInfoDTO(Map<String, Object> attributes) {
return new IamUserInfoDTO(
getStringFromMap(attributes, "sub"),
getStringFromMap(attributes, "fiscalNumber"),
getStringFromMap(attributes, "familyName"),
getStringFromMap(attributes, "name"),
getStringFromMap(attributes, "email"),
getStringFromMap(attributes, "iss")
);
}

private static String getStringFromMap(Map<String, Object> map, String key) {
return map.containsKey(key) ? map.get(key).toString() : null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import it.gov.pagopa.arc.config.JWTConfiguration;
import it.gov.pagopa.arc.dto.IamUserInfoDTO;
import it.gov.pagopa.arc.model.generated.TokenResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

Expand All @@ -16,21 +18,27 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess

private final AccessTokenBuilderService accessTokenBuilderService;
private final ObjectMapper objectMapper;
private final TokenStoreService tokenStoreService;
private final JWTConfiguration jwtConfiguration;

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

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
OAuth2AuthenticationToken oauth2Token = (OAuth2AuthenticationToken) authentication;

TokenResponse accessToken = new TokenResponse(accessTokenBuilderService.build(),jwtConfiguration.getTokenType(),jwtConfiguration.getAccessToken().getExpireIn(),null,null);
tokenStoreService.save(accessToken.getAccessToken(), IamUserInfoDTO.map2IamUserInfoDTO(oauth2Token.getPrincipal().getAttributes()));
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write( objectMapper.writeValueAsString(accessToken) );
response.getWriter().flush();
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/it/gov/pagopa/arc/service/TokenStoreService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package it.gov.pagopa.arc.service;

import it.gov.pagopa.arc.dto.IamUserInfoDTO;


public interface TokenStoreService {

void save(String accessToken, IamUserInfoDTO userInfo);

IamUserInfoDTO getUserInfo(String accessToken);

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

import it.gov.pagopa.arc.dto.IamUserInfoDTO;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;

@Service
public class TokenStoreServiceImpl implements TokenStoreService{

private Map<String, IamUserInfoDTO> tokens = new ConcurrentHashMap<>();

@Override
public void save(String accessToken, IamUserInfoDTO idTokenClaims) {
tokens.put(accessToken,idTokenClaims);
}

@Override
public IamUserInfoDTO getUserInfo(String accessToken) {
return tokens.getOrDefault(accessToken, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider the use of Optional as return param

}

}
48 changes: 48 additions & 0 deletions src/test/java/it/gov/pagopa/arc/dto/IamUserInfoDTOTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package it.gov.pagopa.arc.dto;

import static org.junit.jupiter.api.Assertions.*;

import java.util.Map;
import org.junit.jupiter.api.Test;

class IamUserInfoDTOTest {

@Test
public void testMap2IamUserInfoDTO() {
Map<String, Object> attributes = Map.of(
"sub", "123456",
"fiscalNumber", "789012",
"familyName", "Polo",
"name", "Marco",
"email", "marco.polo@example.com",
"iss", "issuer"
);

IamUserInfoDTO userInfo = IamUserInfoDTO.map2IamUserInfoDTO(attributes);

assertEquals("123456", userInfo.getUserId());
assertEquals("789012", userInfo.getFiscalCode());
assertEquals("Polo", userInfo.getFamilyName());
assertEquals("Marco", userInfo.getName());
assertEquals("marco.polo@example.com", userInfo.getEmail());
assertEquals("issuer", userInfo.getIssuer());
}

@Test
public void testMap2IamUserInfoDTOWithMissingAttributes() {
Map<String, Object> attributes = Map.of(
"sub", "123456"
);

IamUserInfoDTO userInfo = IamUserInfoDTO.map2IamUserInfoDTO(attributes);

assertEquals("123456", userInfo.getUserId());
assertNull(userInfo.getFiscalCode());
assertNull(userInfo.getFamilyName());
assertNull(userInfo.getName());
assertNull(userInfo.getEmail());
assertNull(userInfo.getIssuer());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,68 @@
import it.gov.pagopa.arc.config.JWTSampleConfiguration;
import it.gov.pagopa.arc.model.generated.TokenResponse;
import java.io.IOException;
import java.time.Instant;
import java.util.Map;
import java.util.function.Consumer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.Authentication;

import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
@ExtendWith(MockitoExtension.class)
public class CustomAuthenticationSuccessHandlerTest {

@Mock
private AccessTokenBuilderService accessTokenBuilderService;

@Mock
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

@Mock
oleksiybozhykntt marked this conversation as resolved.
Show resolved Hide resolved
private Authentication authentication;
private TokenStoreService tokenStoreService;

@BeforeEach
void setUp(){
tokenStoreService = new TokenStoreServiceImpl();
JWTConfiguration jwtConfiguration = JWTSampleConfiguration.getCorrectConfiguration();
accessTokenBuilderService = new AccessTokenBuilderService(jwtConfiguration);
customAuthenticationSuccessHandler = new CustomAuthenticationSuccessHandler(accessTokenBuilderService,new ObjectMapper(),jwtConfiguration);
customAuthenticationSuccessHandler = new CustomAuthenticationSuccessHandler(new AccessTokenBuilderService(jwtConfiguration),new ObjectMapper(),jwtConfiguration,tokenStoreService);
}
@Test
void givenAuthenticationRequestThenInResponseGetCustomTokenResponse() throws IOException {
String sample_id_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik1hcmNvIiwiaWF0IjoxNTE2MjM5MDIyLCJmaXNjYWxOdW1iZXIiOiI3ODkwMTIiLCJmYW1pbHlOYW1lIjoiUG9sbyIsImVtYWlsIjoibWFyY28ucG9sb0BleGFtcGxlLmNvbSIsImlzcyI6Imlzc3VlciJ9.AErwXpbHrT_0WvN86QuQ0nvnZndVxt8jnmiD1lfj1_A";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sonar points out the naming of sample_id_token as issue. Try with camelCase

Consumer<Map<String, Object>> attributesConsumer = attributes -> {
attributes.putAll(Map.of(
"sub", "123456",
"fiscalNumber", "789012",
"familyName", "Polo",
"name", "Marco",
"email", "marco.polo@example.com",
"iss", "issuer"
));
};
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plusSeconds(3600);

OidcIdToken idToken = OidcIdToken.withTokenValue(sample_id_token)
.issuedAt(issuedAt)
.expiresAt(expiresAt)
.claims(attributesConsumer)
.build();
OAuth2User principal = new DefaultOidcUser(null,idToken);
OAuth2AuthenticationToken oAuth2AuthenticationToken = new OAuth2AuthenticationToken(principal,null,"test-client");

MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest();
customAuthenticationSuccessHandler.onAuthenticationSuccess(request,response,authentication);

customAuthenticationSuccessHandler.onAuthenticationSuccess(request,response,oAuth2AuthenticationToken);

assertEquals(response.getHeader("Content-Type"),"application/json");

TokenResponse token = new ObjectMapper().readValue(response.getContentAsString(),TokenResponse.class);
assertNotNull(token.getAccessToken());
assertNotNull(tokenStoreService.getUserInfo(token.getAccessToken()));
assertNotNull(token.getTokenType());
assertNotNull(token.getExpiresIn());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package it.gov.pagopa.arc.service;

import static org.junit.jupiter.api.Assertions.*;

import it.gov.pagopa.arc.dto.IamUserInfoDTO;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;

class TokenStoreServiceImplTest {

@Mock
TokenStoreServiceImpl tokenStoreService;

@BeforeEach
void setUp(){
tokenStoreService = new TokenStoreServiceImpl();
}
@Test
void givenAccessTokenAndUserInfoThenSaveAndRetrieveTheSameData() {
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
Map<String, Object> attributes = Map.of(
"sub", "123456",
"fiscalNumber", "789012",
"familyName", "Polo",
"name", "Marco",
"email", "marco.polo@example.com",
"iss", "issuer"
);
IamUserInfoDTO userInfo = IamUserInfoDTO.map2IamUserInfoDTO(attributes);
tokenStoreService.save(token,userInfo);

assertNotNull(tokenStoreService.getUserInfo(token));

assertEquals(attributes.get("sub"),tokenStoreService.getUserInfo(token).getUserId());
assertEquals(attributes.get("fiscalNumber"),tokenStoreService.getUserInfo(token).getFiscalCode());
assertEquals(attributes.get("familyName"),tokenStoreService.getUserInfo(token).getFamilyName());
assertEquals(attributes.get("name"),tokenStoreService.getUserInfo(token).getName());
assertEquals(attributes.get("email"),tokenStoreService.getUserInfo(token).getEmail());
assertEquals(attributes.get("iss"),tokenStoreService.getUserInfo(token).getIssuer());
}

}