Test with MockMvc in Java / Spring Boot - header "Authorization" - java

How can i test an endpoint with authorization header with a user context?
mockMvc.perform(post("/endpoint")
.content(objectMapper.writeValueAsString(request))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", authorizationToken(APP_AUTHORIZATION)))
.andDo(print()).andExpect(status().is2xxSuccessful());
I tried to do this, but it didn't work.
private String buildToken(#Nonnull ApiClient.JwtData data) throws JsonProcessingException {
final var token = JWT.create()
.withSubject(data.getUserId())
.withIssuedAt(new Date())
.withClaim("name", data.getUsername())
.withClaim("fullname", data.getUserFullName())
.withClaim("userid", data.getUserId())
.withClaim("locale", Objects.requireNonNullElse(data.getLocale(), DEFAULT_LOCALE));
final var authsMap = new HashMap<String, String[]>();
token.withClaim("authorities", objectMapper.writeValueAsString(authsMap));
return token.sign(Algorithm.HMAC256(SECRET));
}
protected String authorizationToken(String... authorities) throws JsonProcessingException {
final var jwtData = new ApiClient.JwtData("USER_ID", "USER_NAME", "USER_FULLNAME"
, "locale", "USER_AUTHORITIES", "US-EN", authorities);
return buildToken(jwtData);
}

Related

Srping WebClient - Does not send token (camel-case issue "access_token" -> "accessToken")

My Spring WebClient is not sending Bearer Token, I found that it is because Spring is getting the token from "access_token" but the external server is sending "accessToken". TokenResponse.class:
public static TokenResponse parse(final JSONObject jsonObject)
throws ParseException{
if (jsonObject.containsKey("access_token"))
return AccessTokenResponse.parse(jsonObject);
else
return TokenErrorResponse.parse(jsonObject);
}
How can I force Spring to parse this token?
My config:
#Bean
public ReactiveClientRegistrationRepository clientRegistrations(
#Value("${rest.security.clientId}") final String clientId,
#Value("${rest.security.clientSecret}") final String clientSecret,
#Value("${rest.endpoint}") final String baseUrl) {
final var clientRegistration = ClientRegistration
.withRegistrationId(CLIENT_REGISTRATION_ID)
.tokenUri(baseUrl+ "/token")
.clientId(clientId)
.clientSecret(clientSecret)
.authorizationGrantType(CLIENT_CREDENTIALS)
.build();
return new InMemoryReactiveClientRegistrationRepository(clientRegistration);
}

RestTemplate Junit: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null

I have a spring boot application that makes an API hit of other internal projects using the rest template which works fine and I am writing unit test cases for it but test case if failing due to Unexpected exception thrown: java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
Service
#Service
#Slf4j
public class DynamoDBServiceImpl implements DynamoDBService {
private final RestTemplate restTemplate;
private final HttpHeaders httpHeaders;
private final String jwtHeader;
private final String apiKeyHeader;
private final String dynamodbSysApiKey;
private final String fetchAdminGroupUrl;
public DynamoDBServiceImpl(
RestTemplate restTemplate,
HttpHeaders httpHeaders,
#Value("${header-name.jwt}") String jwtHeader,
#Value("${header-name.api-key}") String apiKeyHeader,
#Value("${dynamodb-sys-api-key}") String dynamodbSysApiKey,
#Value("${dynamodb-fetch-admin-group-url}") String fetchAdminGroupUrl) {
this.restTemplate = restTemplate;
this.httpHeaders = httpHeaders;
this.jwtHeader = jwtHeader;
this.apiKeyHeader = apiKeyHeader;
this.dynamodbSysApiKey = dynamodbSysApiKey;
this.fetchAdminGroupUrl = fetchAdminGroupUrl;
}
#Override
public List<AdminGroupDTO> getAllAdminGroups() {
log.debug("Request to get admin group details with url : {}", fetchAdminGroupUrl);
httpHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setBearerAuth(CommonUtils.getHeaderFromCurrentHttpRequest(jwtHeader));
httpHeaders.set(apiKeyHeader, dynamodbSysApiKey);
HttpEntity<AdminGroupDTO> request = new HttpEntity<>(httpHeaders);
ResponseEntity<List<AdminGroupDTO>> response =
restTemplate.exchange(fetchAdminGroupUrl, HttpMethod.GET, request, new ParameterizedTypeReference<List<AdminGroupDTO>>() {});
return response.getBody();
}
}
Test
#SpringBootTest(classes = Application.class)
public class DynamoDBServiceTest {
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final HttpHeaders httpHeaders = new HttpHeaders();
private final DynamoDBServiceImpl dynamoDBService =
new DynamoDBServiceImpl(
restTemplate, httpHeaders, "Authorization" , "Api-Key", "fake", "https://fake.com");
#Test
void testGetAllAdminGroups() {
List<AdminGroupDTO> adminGroupDTOList = new ArrayList<>();
AdminGroupDTO adminGroupDTO = new AdminGroupDTO();
adminGroupDTO.setAdminGroupId(1L);
adminGroupDTO.setAdminGroupName("fake");
adminGroupDTO.setCountryName("fake");
adminGroupDTOList.add(adminGroupDTO);
ResponseEntity<List<AdminGroupDTO>> responseEntity = new ResponseEntity<>(adminGroupDTOList, HttpStatus.OK);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
assertDoesNotThrow(dynamoDBService::getAllAdminGroups);
}
}
Replace this line of code :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
With this :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.eq(new ParameterizedTypeReference<List<AdminGroupDTO>>() {}))
)
.thenReturn(responseEntity);
And excepption should dissapear.
For futher details you can check this post.

How to get Access Token from Keycloak over SpringBoot?

I'm trying to get an Access Token from Keycloak over SpringBoot and did try the following example. But the KeycloakAuthenticationToken token is null.
Does someone know another approach to get an Access Token?
#GetMapping("/token")
public String getToken(HttpServletRequest request) throws IOException {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) request.getUserPrincipal();
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) token.getAccount().getKeycloakSecurityContext();
KeycloakSecurityContext context = token.getAccount().getKeycloakSecurityContext();
String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(session.getToken());
String idTokenPretty = JsonSerialization.writeValueAsPrettyString(session.getIdToken());
RefreshToken refreshToken;
try {
refreshToken = new JWSInput(session.getRefreshToken()).readJsonContent(RefreshToken.class);
} catch (JWSInputException e) {
throw new IOException(e);
}
String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
return refreshTokenPretty;
}
Seems like I can get a token like this with ('org.keycloak:keycloak-admin-client'):
Keycloak keycloak = KeycloakBuilder.builder() //
.serverUrl(serverUrl) //
.realm(realm) //
.grantType(OAuth2Constants.PASSWORD) //
.clientId(clientId) //
.clientSecret(clientSecret) //
.username(userName) //
.password(password) //
.build();
AccessTokenResponse tok = keycloak.tokenManager().getAccessToken();
If someone knows a more elegant way, I would appreciate if you let me know :)
Thanks in advance!
Try the following:
HttpEntity<MultiValueMap<String, String>> request =
new TokenRequest.Builder(clientID, OAuth2Constants.PASSWORD)
.add("username", userName)
.add("password", password)
.build();
ResponseEntity<String> response = restTemplate.postForEntity( postUrl, request , String.class );
return response.getBody();
and the helper class:
public class TokenRequest {
public static class Builder{
MultiValueMap<String, String> data;
public Builder(String clientID, String grant_type){
data = new LinkedMultiValueMap<>();
data.put("client_id", Collections.singletonList(clientID));
data.put("grant_type", Collections.singletonList(grant_type));
}
public Builder add(String key, String value){
data.put(key, Collections.singletonList(value));
return this;
}
public HttpEntity<MultiValueMap<String, String>> build(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return new HttpEntity<>(data, headers);
}
}
private TokenRequest(){
}
}
Try this:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
KeycloakAuthenticationToken keycloakAuthenticationToken = (KeycloakAuthenticationToken) request.getUserPrincipal();
KeycloakPrincipal<KeycloakSecurityContext> principal = (KeycloakPrincipal) keycloakAuthenticationToken.getPrincipal();
String token = principal.getKeycloakSecurityContext().getIdTokenString();

spring cloud gateway predicates test cases

I have implemented the predicate factory(spring cloud gateway) to validate the headers and I want to add the test cases for that
public Predicate<ServerWebExchange> apply(Config config ) {
return (ServerWebExchange t) -> {
List<String> Header = t.getRequest().getHeaders().get("abcd");
#business logic
return true;
};
}
I want to include the test cases for the predicate factory above.
I tried the test case as below
#Before
public void prepareStubs() {
stubFor(any(urlPathEqualTo("/abcd")).willReturn(aResponse().withBody("ABCD")));
}
#Test
public void testGatewayRouting() throws JsonMappingException, JsonProcessingException {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer eyJraWQiOiIiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9");
HttpEntity<?> entity = new HttpEntity<>(headers);
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(createURLWithPort("/abcd"));
ResponseEntity<String> response = restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity,
String.class);
assertEquals(200, response.getStatusCodeValue());
assertEquals("ABCD", response.getBody());
}

How to fix sender_id_mismatch using fcm notification

I am working on a java server which is sending Firebase Cloud Messaging notification to devices using OAUTH 2.0 authentication.
According to guide (https://firebase.google.com/docs/cloud-messaging/auth-server?authuser=0) I have generated key from an account service with editor role, but I keep getting 403 SENDER_ID_MISMATCH error.
Any suggestion?
public class FcmManager {
private static final String DEVICE_NOTIFICATION_URL = "https://fcm.googleapis.com/v1/projects/myprojectid/messages:send";
private static final String JSON_STR_DEVICE_NOTIFICATION = "{\"message\":{\"token\" : " +"\"%s\"" + ",\"notification\" : " +
"{\"body\" : \"%s\",\"title\" : \"%s\"}}}";
public static boolean sendNotificationDevice(DeviceNotification deviceNotification, String msgTitle,
String msgBody) throws Exception{
String accessToken = getAccessToken();
System.out.println(msgBody);
String jsonStr = String.format(JSON_STR_DEVICE_NOTIFICATION, deviceNotification.getToken()
,msgBody,msgTitle);
System.out.println(jsonStr);
F.Promise<String> response = WS.url(DEVICE_NOTIFICATION_URL)
.setContentType("application/json").setHeader("Authorization","Bearer " +
accessToken).post(jsonStr).map(
new F.Function<WS.Response, String>() {
public String apply(WS.Response response) {
String result = response.getBody();
System.out.println(result);
return result;
}
}
);
return true;
}
private static String getAccessToken() throws IOException {
GoogleCredential googleCredential = GoogleCredential
.fromStream(new FileInputStream("mygeneratedkeyfromaccountservice.json"))
.createScoped(Arrays.asList("https://www.googleapis.com/auth/firebase.messaging"));
googleCredential.refreshToken();
return googleCredential.getAccessToken();
}
}

Categories