Skip to content

Commit

Permalink
secureCodeBox#121 Use URI Instead of String
Browse files Browse the repository at this point in the history
This has theadvantage that URLs are validated in place and we can
normalize theresulting URL to remove double slashes from path.

Signed-off-by: Sven Strittmatter <[email protected]>
  • Loading branch information
Weltraumschaf committed Jul 3, 2024
1 parent eb975b1 commit 3309da3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
@ToString
@EqualsAndHashCode
public final class ClientConfig {
/**
* Path prefix for the Defectdojo REST API
*/
public static final String API_PREFIX = "/api/v2/";
/**
* Default for {@link #maxPageCountForGets}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.fasterxml.jackson.databind.cfg.CoercionAction;
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
import io.securecodebox.persistence.defectdojo.config.ClientConfig;
import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.exception.TooManyResponsesException;
import io.securecodebox.persistence.defectdojo.http.AuthHeaderFactory;
import io.securecodebox.persistence.defectdojo.http.Foo;
Expand All @@ -34,7 +33,6 @@
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
Expand All @@ -44,7 +42,6 @@
*/
@Slf4j
abstract class GenericDefectDojoService<T extends Model> implements DefectDojoService<T> {
private static final String API_PREFIX = "/api/v2/";
private static final long DEFECT_DOJO_OBJET_LIMIT = 100L;
protected ClientConfig clientConfig;

Expand Down Expand Up @@ -81,7 +78,7 @@ public final T get(long id) {
final var restTemplate = this.getRestTemplate();
final HttpEntity<String> payload = new HttpEntity<>(getDefectDojoAuthorizationHeaders());

final var url = createBaseUrl() + id;
final var url = createBaseUrl().resolve(String.valueOf(id));
log.debug("Requesting URL: {}", url);
final ResponseEntity<T> response = restTemplate.exchange(
url,
Expand Down Expand Up @@ -151,20 +148,22 @@ public final void delete(long id) {
final var restTemplate = this.getRestTemplate();
final HttpEntity<String> payload = new HttpEntity<>(getDefectDojoAuthorizationHeaders());

restTemplate.exchange(createBaseUrl() + id + "/", HttpMethod.DELETE, payload, String.class);
final var url = createBaseUrl().resolve(id + "/");
restTemplate.exchange(url, HttpMethod.DELETE, payload, String.class);
}

@Override
public final T update(@NonNull T object, long id) {
final var restTemplate = this.getRestTemplate();
final HttpEntity<T> payload = new HttpEntity<>(object, getDefectDojoAuthorizationHeaders());
final ResponseEntity<T> response = restTemplate.exchange(createBaseUrl() + id + "/", HttpMethod.PUT, payload, getModelClass());
final var url = createBaseUrl().resolve(id + "/");
final ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.PUT, payload, getModelClass());

return response.getBody();
}

/**
* Get the URL path for the REST endpoint relative to {@link #API_PREFIX}
* Get the URL path for the REST endpoint relative to {@link ClientConfig#API_PREFIX}
*
* @return not {@code null}, not empty
*/
Expand All @@ -185,8 +184,13 @@ public final T update(@NonNull T object, long id) {
*/
protected abstract PaginatedResult<T> deserializeList(@NonNull String response);

private String createBaseUrl() {
return this.clientConfig.getUrl() + API_PREFIX + getUrlPath() + "/";
final URI createBaseUrl() {
final var buffer = clientConfig.getUrl() +
ClientConfig.API_PREFIX +
getUrlPath() +
'/';

return URI.create(buffer).normalize();
}

/**
Expand Down Expand Up @@ -226,13 +230,9 @@ protected PaginatedResult<T> internalSearch(Map<String, Object> queryParams, lon

final var url = createBaseUrl();
final UriComponentsBuilder builder;
try {
builder = UriComponentsBuilder
.fromUri(new URI(url))
.queryParams(multiValueMap);
} catch (URISyntaxException e) {
throw new PersistenceException("Bad URL given: " + url, e);
}
builder = UriComponentsBuilder
.fromUri(url)
.queryParams(multiValueMap);

final ResponseEntity<String> responseString = restTemplate.exchange(
builder.build(mutableQueryParams),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.securecodebox.persistence.defectdojo.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import io.securecodebox.persistence.defectdojo.exception.PersistenceException;
import io.securecodebox.persistence.defectdojo.model.Model;
import io.securecodebox.persistence.defectdojo.model.PaginatedResult;
import lombok.NonNull;
import org.junit.jupiter.api.Test;

import java.net.URI;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

/**
* Tests for {@link GenericDefectDojoService}
*/
final class GenericDefectDojoServiceTest extends WireMockBaseTestCase {
private static final class TestModel implements Model {
@Override
public boolean equalsQueryString(@NonNull Map<String, Object> queryParams) {
// Stub this to false because we do not test this method here.
return false;
}
}
private final GenericDefectDojoService<TestModel> sut =new GenericDefectDojoService<>(conf()) {

@Override
protected String getUrlPath() {
return "snafu";
}

@Override
protected Class<TestModel> getModelClass() {
return TestModel.class;
}

@Override
protected PaginatedResult<TestModel> deserializeList(@NonNull String response) {
try {
return this.objectMapper.readValue(response, new TypeReference<>() {
});
} catch (JsonProcessingException e) {
throw new PersistenceException("Can't process JSON response!", e);
}
}
};

@Test
void createBaseUrl() {
assertThat(sut.createBaseUrl(), is(URI.create("http://localhost:8888/api/v2/snafu/")));
}
}

0 comments on commit 3309da3

Please sign in to comment.