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

chore: fix sonar issues #3789

Merged
merged 8 commits into from
Sep 23, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.tomcat.util.codec.binary.Base64;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
Expand All @@ -29,6 +29,7 @@
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand Down Expand Up @@ -146,9 +147,9 @@ public FailedAuthenticationHandler failedAuthenticationHandler() {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(requests -> requests.anyRequest().authenticated())
.apply(new CustomSecurityFilters())
.and().build();
.authorizeHttpRequests(requests -> requests.anyRequest().authenticated())
.with(new CustomSecurityFilters(), Customizer.withDefaults())
.build();
}

@Bean
Expand All @@ -161,7 +162,7 @@ public SafMethodSecurityExpressionRoot safMethodSecurityExpressionRoot(

private class CustomSecurityFilters extends AbstractHttpConfigurer<CustomSecurityFilters, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
public void configure(HttpSecurity http) {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);

http.addFilterBefore(new BasicContentFilter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ public class ValidateAPIController {
}
))
})
public ResponseEntity<String> checkConformance(@Parameter(in = ParameterIn.PATH, required = true, description = "Service ID of the service to check") @PathVariable String serviceId,
@Parameter(hidden = true) @CookieValue(value = "apimlAuthenticationToken", defaultValue = "dummy") String authenticationToken) {
public ResponseEntity<String> checkConformance(@Parameter(in = ParameterIn.PATH, required = true, description = "Service ID of the service to check") @PathVariable String serviceId) {
ConformanceProblemsContainer foundNonConformanceIssues = new ConformanceProblemsContainer(serviceId);
foundNonConformanceIssues.add(CONFORMANCE_PROBLEMS, validateServiceIdFormat(serviceId));
if (!foundNonConformanceIssues.isEmpty())
Expand All @@ -121,7 +120,7 @@ public ResponseEntity<String> checkConformance(@Parameter(in = ParameterIn.PATH,
checkMetadataCanBeRetrieved(metadata);
Optional<String> swaggerUrl = verificationOnboardService.findSwaggerUrl(metadata);

validateSwaggerDocument(serviceId, foundNonConformanceIssues, metadata, swaggerUrl, authenticationToken);
validateSwaggerDocument(serviceId, foundNonConformanceIssues, metadata, swaggerUrl);
} catch (ValidationException e) {
switch (e.getKey()) {
case WRONG_SERVICE_ID_KEY:
Expand All @@ -142,7 +141,7 @@ public ResponseEntity<String> checkConformance(@Parameter(in = ParameterIn.PATH,
return new ResponseEntity<>("{\"message\":\"Service " + serviceId + " fulfills all checked conformance criteria\"}", HttpStatus.OK);
}

private void validateSwaggerDocument(String serviceId, ConformanceProblemsContainer foundNonConformanceIssues, Map<String, String> metadata, Optional<String> swaggerUrl, String token) throws ValidationException {
private void validateSwaggerDocument(String serviceId, ConformanceProblemsContainer foundNonConformanceIssues, Map<String, String> metadata, Optional<String> swaggerUrl) throws ValidationException {
if (swaggerUrl.isEmpty()) {
throw new ValidationException("Could not find Swagger Url", NON_CONFORMANT_KEY);
}
Expand All @@ -160,7 +159,7 @@ private void validateSwaggerDocument(String serviceId, ConformanceProblemsContai

Set<Endpoint> allEndpoints = swaggerParser.getAllEndpoints();
if (!allEndpoints.isEmpty())
foundNonConformanceIssues.add(CONFORMANCE_PROBLEMS, verificationOnboardService.testEndpointsByCalling(allEndpoints, token));
foundNonConformanceIssues.add(CONFORMANCE_PROBLEMS, verificationOnboardService.testEndpointsByCalling(allEndpoints));

foundNonConformanceIssues.add(CONFORMANCE_PROBLEMS, VerificationOnboardService.getProblemsWithEndpointUrls(swaggerParser));
}
Expand Down Expand Up @@ -206,11 +205,11 @@ private void validateSwaggerDocument(String serviceId, ConformanceProblemsContai
}
))
})
public ResponseEntity<String> checkValidateLegacy(@RequestBody String serviceId, @Parameter(hidden = true) @CookieValue(value = "apimlAuthenticationToken", defaultValue = "dummy") String authenticationToken) {
public ResponseEntity<String> checkValidateLegacy(@RequestBody String serviceId) {
if (serviceId.startsWith("serviceID")) {
serviceId = serviceId.replace("serviceID=", "");
}
return checkConformance(serviceId, authenticationToken);
return checkConformance(serviceId);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,15 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.zowe.apiml.constants.EurekaMetadataDefinition;
import org.zowe.apiml.product.constants.CoreService;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;

/**
* Service class that offers methods for checking onboarding information and also checks availability metadata from
Expand Down Expand Up @@ -102,54 +89,24 @@ public String getSwagger(String swaggerUrl) {
* Checks if endpoints can be called and return documented responses
*
* @param endpoints endpoints to check
* @param passedAuthenticationToken Token used to call endpoints that support SSO
* @return List of problems
*/
public List<String> testEndpointsByCalling(Set<Endpoint> endpoints, String passedAuthenticationToken) {
ArrayList<String> result = new ArrayList<>(checkEndpointsNoSSO(endpoints));
richard-salac marked this conversation as resolved.
Show resolved Hide resolved
try {
result.addAll(checkEndpointsWithSSO(endpoints, passedAuthenticationToken));
} catch (ValidationException e) {
result.add(e.getMessage());
}

return result;
public List<String> testEndpointsByCalling(Set<Endpoint> endpoints) {
return checkEndpoints(endpoints);
}

private List<String> checkEndpointsWithSSO(Set<Endpoint> endpoints, String passedAuthenticationToken) {
private List<String> checkEndpoints(Set<Endpoint> endpoints) {
ArrayList<String> result = new ArrayList<>();

String ssoCookie = getAuthenticationCookie(passedAuthenticationToken);

HttpHeaders headersSSO = new HttpHeaders();
richard-salac marked this conversation as resolved.
Show resolved Hide resolved
headersSSO.setContentType(MediaType.APPLICATION_JSON);
headersSSO.add("Cookie", "apimlAuthenticationToken=" + ssoCookie);
HttpEntity<String> requestSSO = new HttpEntity<>(headersSSO);

for (Endpoint endpoint : endpoints) {
for (HttpMethod method : endpoint.getHttpMethods()) {
checkEndpoint(endpoint, result, method, requestSSO, true);
checkEndpoint(endpoint, result, method);
}
}
return result;
}

private List<String> checkEndpointsNoSSO(Set<Endpoint> endpoints) {
ArrayList<String> result = new ArrayList<>();

HttpHeaders headersNoSSO = new HttpHeaders();
headersNoSSO.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestNoSSO = new HttpEntity<>(headersNoSSO);

for (Endpoint endpoint : endpoints) {
for (HttpMethod method : endpoint.getHttpMethods()) {
checkEndpoint(endpoint, result, method, requestNoSSO, false);
}
}
return result;
}

private void checkEndpoint(Endpoint endpoint, ArrayList<String> result, HttpMethod method, HttpEntity<String> request, boolean attemptWithSSO) {
private void checkEndpoint(Endpoint endpoint, ArrayList<String> result, HttpMethod method) {
if (method == HttpMethod.DELETE) {
return;
}
Expand All @@ -159,14 +116,16 @@ private void checkEndpoint(Endpoint endpoint, ArrayList<String> result, HttpMeth
// Example: transforms https://localhost:10010/discoverableclient/api/v1/pets/{id} to https://localhost:10010/discoverableclient/api/v1/pets/dummy
String url = urlFromSwagger.replaceAll("\\{[^{}]*}", "dummy");

ResponseEntity<String> responseWithSSO = getResponse(request, method, url);
result.addAll(fromResponseReturnFoundProblems(responseWithSSO, endpoint, method, attemptWithSSO));
ResponseEntity<String> responseWithSSO = getResponse(method, url);
result.addAll(fromResponseReturnFoundProblems(responseWithSSO, endpoint, method));
}

private ResponseEntity<String> getResponse(HttpEntity<String> request, HttpMethod method, String url) {
private ResponseEntity<String> getResponse(HttpMethod method, String url) {
ResponseEntity<String> response;
try {
response = restTemplate.exchange(url, method, request, String.class);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
response = restTemplate.exchange(url, method, new HttpEntity<>(headers), String.class);
} catch (HttpClientErrorException | HttpServerErrorException e) {
response = ResponseEntity.status(e.getStatusCode())
.headers(e.getResponseHeaders())
Expand All @@ -177,7 +136,7 @@ private ResponseEntity<String> getResponse(HttpEntity<String> request, HttpMetho
return response;
}

private List<String> fromResponseReturnFoundProblems(ResponseEntity<String> response, Endpoint currentEndpoint, HttpMethod method, boolean attemptWithSSO) {
private List<String> fromResponseReturnFoundProblems(ResponseEntity<String> response, Endpoint currentEndpoint, HttpMethod method) {
ArrayList<String> result = new ArrayList<>();

String responseBody = response.getBody();
Expand All @@ -186,8 +145,8 @@ private List<String> fromResponseReturnFoundProblems(ResponseEntity<String> resp
result.add("Documented endpoint at " + currentEndpoint.getUrl() + " could not be located, attempting to call it through gateway gives the ZWEAM104E error");
}

if (attemptWithSSO && responseBody != null && (response.getStatusCode() == HttpStatus.FORBIDDEN || response.getStatusCode() == HttpStatus.UNAUTHORIZED)) {
result.add(method + " request to documented endpoint at " + currentEndpoint.getUrl() + " responded with status code " + response.getStatusCode().value() + ", despite being called with the SSO authorization");
richard-salac marked this conversation as resolved.
Show resolved Hide resolved
if (responseBody != null && (response.getStatusCode() == HttpStatus.FORBIDDEN || response.getStatusCode() == HttpStatus.UNAUTHORIZED)) {
result.add(method + " request to documented endpoint at " + currentEndpoint.getUrl() + " responded with status code " + response.getStatusCode().value());
}

if (!currentEndpoint.isResponseCodeForMethodDocumented(String.valueOf(response.getStatusCode().value()), method)) {
Expand All @@ -201,33 +160,6 @@ public static List<String> getProblemsWithEndpointUrls(AbstractSwaggerValidator
return swaggerParser.getProblemsWithEndpointUrls();
}

private String getAuthenticationCookie(String passedAuthenticationToken) {
richard-salac marked this conversation as resolved.
Show resolved Hide resolved
String errorMsg = "Error retrieving ZAAS connection details";
// FIXME This keeps the current behaviour
if (passedAuthenticationToken.equals("dummy")) {
URI uri = discoveryClient.getServices().stream()
.filter(service -> CoreService.ZAAS.getServiceId().equalsIgnoreCase(service))
.flatMap(service -> discoveryClient.getInstances(service).stream())
.findFirst()
.map(ServiceInstance::getUri)
.orElseThrow(() -> new ValidationException(errorMsg, ValidateAPIController.NO_METADATA_KEY));

String zaasAuthValidateUri = String.format("%s://%s:%d%s", uri.getScheme() == null ? "https" : uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath() + "/zaas/validate/auth");
try {
restTemplate.exchange(zaasAuthValidateUri, HttpMethod.GET, null, String.class);
} catch (HttpClientErrorException.Conflict e) {
throw new ValidationException(e.getResponseBodyAsString(), ValidateAPIController.NON_CONFORMANT_KEY);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Error getting authentication support", e);
}
throw new ValidationException("Error validating the authentication support", ValidateAPIController.NO_METADATA_KEY);
}

}
return passedAuthenticationToken;
}

public static boolean supportsSSO(Map<String, String> metadata) {
if (metadata.containsKey(EurekaMetadataDefinition.AUTHENTICATION_SSO)) {
return metadata.get(EurekaMetadataDefinition.AUTHENTICATION_SSO).equals("true");
Expand Down
Loading
Loading