Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ void thenValidateReturns200(String validToken) {
.body(requestBody)
.when()
.post(VALIDATE_ENDPOINT)
.then().statusCode(HttpStatus.SC_NO_CONTENT);
.then().statusCode(HttpStatus.SC_OK);
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Map;

/**
*
*/
Expand All @@ -21,5 +23,6 @@
public class ZaasOidcValidationResult {

private boolean isValid = false;
private Map<String, Object> claims;

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.net.HttpCookie;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -166,12 +167,20 @@ private ClassicHttpRequest validateOidcToken(String oidcToken) throws JsonProces

private ZaasOidcValidationResult extractZaasOidcValidate(SimpleHttpResponse response) throws IOException, ZaasClientException {
int statusCode = response.getCode();

if (statusCode == 200) {
var body = response.getStringBody();
var mapper = new ObjectMapper();
Comment thread
taban03 marked this conversation as resolved.
Outdated
var claims = mapper.readValue(body, Map.class);
return new ZaasOidcValidationResult(true, claims);
}

if (statusCode == 204) {
Comment thread
taban03 marked this conversation as resolved.
return new ZaasOidcValidationResult(true);
return new ZaasOidcValidationResult(true, null);
}

if (statusCode == 401) {
return new ZaasOidcValidationResult(false);
return new ZaasOidcValidationResult(false, null);
} else {
throw new ZaasClientException(ZaasClientErrorCodes.GENERIC_EXCEPTION, response.getStringBody());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.hc.core5.http.io.entity.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

Expand All @@ -44,15 +45,15 @@ public class SimpleHttpResponse {
private final Map<String, List<Header>> headers;

public SimpleHttpResponse(int code, byte[] byteBody) {
this(code, byteBody, null, Map.of());
this(code, byteBody, new String(byteBody), Map.of());
}

public SimpleHttpResponse(int code, String stringBody) {
this(code, null, stringBody, Map.of());
this(code, stringBody == null ? null : stringBody.getBytes(StandardCharsets.UTF_8), stringBody, Map.of());
}

public SimpleHttpResponse(int code, String stringBody, Map<String, List<Header>> headers) {
this(code, null, stringBody, headers);
this(code, stringBody == null ? null : stringBody.getBytes(StandardCharsets.UTF_8), stringBody, headers);
}

public SimpleHttpResponse(int code) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import static org.zowe.apiml.zaasclient.exception.ZaasClientErrorCodes.*;
Expand Down Expand Up @@ -234,7 +231,7 @@ void createConfigProperties() {
@Test
void givenValidOidcToken_whenValidate_thenSuccess() throws ZaasClientException {
var token = "validOidcToken";
var successResult = new ZaasOidcValidationResult(true);
var successResult = new ZaasOidcValidationResult(true, null);
when(tokens.validateOidc(token)).thenReturn(successResult);
assertSame(successResult, underTest.validateOidc(token));
}
Expand All @@ -252,7 +249,7 @@ void givenValidOidc_whenValidateException_thenRethrown() throws ZaasClientExcept
@Test
void givenInvalidOidc_whenValidate_thenFalse() throws ZaasClientException {
var token = "invalidOidc";
var failResult = new ZaasOidcValidationResult(false);
var failResult = new ZaasOidcValidationResult(false, null);
when(tokens.validateOidc(token)).thenReturn(failResult);
assertSame(failResult, underTest.validateOidc(token));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,9 @@

import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.zowe.apiml.zaasclient.exception.ZaasClientErrorCodes.GENERIC_EXCEPTION;
import static org.zowe.apiml.zaasclient.exception.ZaasClientErrorCodes.TOKEN_NOT_PROVIDED;

Expand Down Expand Up @@ -226,11 +219,30 @@ void givenEmptyOidcToken_whenValidate_thenException() {
}

@Test
void givenValidToken_whenValidate_thenSuccess() throws ZaasClientException {
void givenValidToken_whenValidateBefore3_6_0_thenSuccess() throws ZaasClientException {
var token = "validOidcToken";
mockHttpClientResponse(204);
var validationResult = zaasJwtService.validateOidc(token);
assertTrue(validationResult.isValid());
assertNull(validationResult.getClaims());
}

@Test
void givenValidToken_whenValidateOn3_6_0_orLaterVersion_thenSuccess() throws ZaasClientException {
var token = "validOidcToken";
mockHttpClientResponse(200, """
{
"sub": "user",
"anotherClaim": "x",
"exp": 5
}
""");
var validationResult = zaasJwtService.validateOidc(token);
assertTrue(validationResult.isValid());
assertNotNull(validationResult.getClaims());
assertEquals("user", validationResult.getClaims().get("sub"));
assertEquals("x", validationResult.getClaims().get("anotherClaim"));
assertEquals(5, validationResult.getClaims().get("exp"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,13 @@
import org.springframework.lang.Nullable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.zowe.apiml.message.api.ApiMessageView;
import org.zowe.apiml.message.core.MessageService;
import org.zowe.apiml.security.common.token.AccessTokenProvider;
import org.zowe.apiml.security.common.token.OIDCProvider;
import org.zowe.apiml.security.common.token.TokenNotValidException;
import org.zowe.apiml.security.common.util.JwtUtils;
import org.zowe.apiml.zaas.security.service.AuthenticationService;
import org.zowe.apiml.zaas.security.service.JwtSecurity;
import org.zowe.apiml.zaas.security.service.token.OIDCTokenProvider;
Expand All @@ -66,9 +60,7 @@
import java.util.List;
import java.util.Map;

import static org.apache.http.HttpStatus.SC_NO_CONTENT;
import static org.apache.http.HttpStatus.SC_OK;
import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
import static org.apache.http.HttpStatus.*;

/**
* Controller offer method to control security. It can contain method for user and also method for calling services
Expand Down Expand Up @@ -464,7 +456,7 @@ private List<JsonWebKey> getCurrentKey() {
return currentKey.getJsonWebKeys();
}

@PostMapping(path = OIDC_TOKEN_VALIDATE)
@PostMapping(path = OIDC_TOKEN_VALIDATE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Validate OIDC token",
tags = {"OIDC"},
operationId = "validateOIDCToken",
Expand All @@ -481,13 +473,14 @@ private List<JsonWebKey> getCurrentKey() {
@ApiResponse(responseCode = "204", description = "Valid token"),
@ApiResponse(responseCode = "401", description = "Invalid token or OIDC provider is not defined")
})
public ResponseEntity<Void> validateOIDCToken(@RequestBody ValidateRequestModel validateRequestModel) {
public ResponseEntity<Object> validateOIDCToken(@RequestBody ValidateRequestModel validateRequestModel) {
log.debug("Validating OIDC token using provider {}", oidcProvider);
String token = validateRequestModel.getToken();
if (oidcProvider != null && oidcProvider.isValid(token)) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
return new ResponseEntity<>(JwtUtils.getJwtClaims(token).getClaims(), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
final ApiMessageView message = messageService.createMessage("org.zowe.apiml.common.unauthorized").mapToView();
return new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,12 @@
import java.util.List;
import java.util.Optional;

import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.apache.http.HttpStatus.SC_NOT_FOUND;
import static org.apache.http.HttpStatus.SC_NO_CONTENT;
import static org.apache.http.HttpStatus.SC_OK;
import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
import static org.apache.http.HttpStatus.*;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@ExtendWith(SpringExtension.class)
class AuthControllerTest {
Expand Down Expand Up @@ -416,28 +403,39 @@ void thenRemoveRulesAndTokens() throws Exception {
@Nested
class GivenValidateOIDCTokenRequest {

private static final String TOKEN = "token";

@Nested
class WhenValidateToken {

private static final String TOKEN = "ewogICJ0eXAiOiAiSldUIiwKICAibm9uY2UiOiAiYVZhbHVlVG9CZVZlcmlmaWVkIiwKICAiYWxnIjogIlJTMjU2IiwKICAia2lkIjogIlNlQ1JldEtleSIKfQ.ewogICJhdWQiOiAiMDAwMDAwMDMtMDAwMC0wMDAwLWMwMDAtMDAwMDAwMDAwMDAwIiwKICAiaXNzIjogImh0dHBzOi8vb2lkYy5wcm92aWRlci5vcmcvYXBwIiwKICAiaWF0IjogMTcyMjUxNDEyOSwKICAibmJmIjogMTcyMjUxNDEyOSwKICAiZXhwIjogODcyMjUxODEyNSwKICAic3ViIjogIm9pZGMudXNlcm5hbWUiCn0.c29tZVNpZ25lZEhhc2hDb2Rl";

private String getBody() throws JSONException {
return new JSONObject()
.put("token", TOKEN)
.toString();
}

@Test
void validateOIDCToken() throws Exception {
when(oidcProvider.isValid(TOKEN)).thenReturn(true);
mockMvc.perform(post("/zaas/api/v1/auth/oidc-token/validate")
.contentType(MediaType.APPLICATION_JSON)
.content(body.toString()))
.andExpect(status().is(SC_NO_CONTENT));
.content(getBody()))
.andExpect(status().is(SC_OK))
.andExpect(jsonPath("sub", is("oidc.username")))
.andExpect(jsonPath("iss", is("https://oidc.provider.org/app")));
}

@Test
void return401() throws Exception {
when(oidcProvider.isValid(TOKEN)).thenReturn(false);
mockMvc.perform(post("/zaas/api/v1/auth/oidc-token/validate")
.contentType(MediaType.APPLICATION_JSON)
.content(body.toString()))
.content(getBody()))
.andExpect(status().is(SC_UNAUTHORIZED));
}

}

}

@Nested
Expand Down
Loading