Skip to content

Commit

Permalink
add http headers to OAuth2ServiceException constructor and provide ge…
Browse files Browse the repository at this point in the history
…tter (#1255)

---------

Co-authored-by: Manuel Fink <[email protected]>
  • Loading branch information
liga-oz and finkmanAtSap authored Aug 11, 2023
1 parent 70a6499 commit 003db33
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -71,9 +72,8 @@ protected OAuth2TokenResponse requestAccessToken(URI tokenEndpointUri, HttpHeade
try {
return executeRequest(httpPost);
} catch (IOException | URISyntaxException e) {
if (e instanceof OAuth2ServiceException)
throw (OAuth2ServiceException) e;

if (e instanceof OAuth2ServiceException oAuth2Exception)
throw oAuth2Exception;
throw new OAuth2ServiceException("Unexpected error retrieving JWT token: " + e.getMessage());
}
}
Expand All @@ -95,6 +95,7 @@ private OAuth2TokenResponse executeRequest(HttpPost httpPost) throws IOException
throw OAuth2ServiceException.builder("Error retrieving JWT token")
.withStatusCode(statusCode)
.withUri(requestUri)
.withHeaders(Arrays.toString(response.getAllHeaders()))
.withResponseBody(body)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import java.io.IOException;
import java.io.Serial;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -20,6 +23,7 @@ public class OAuth2ServiceException extends IOException {
@Serial
private static final long serialVersionUID = 1L;
private Integer httpStatusCode = 0;
private final List<String> headers = new ArrayList<>();

public OAuth2ServiceException(String message) {
super(message);
Expand All @@ -37,7 +41,23 @@ public OAuth2ServiceException(String message, Integer httpStatusCode) {
super(message);
this.httpStatusCode = httpStatusCode != null ? httpStatusCode : 0;
}


/**
* Creates an exception.
*
* @param message
* the error message
* @param httpStatusCode
* the status code of the HTTP service request
* @param headers
* the headers of the HTTP service request
*/

OAuth2ServiceException(String message, Integer httpStatusCode, List<String> headers) {
this(message, httpStatusCode);
this.headers.addAll(headers);
}

/**
* Returns the HTTP status code of the failed OAuth2 service request or
* {@code 0} e.g. in case the service wasn't called at all.
Expand All @@ -48,6 +68,14 @@ public Integer getHttpStatusCode() {
return httpStatusCode;
}

/**
* Returns the HTTP headers of the failed OAuth2 service request
* @return list of HTTP headers
*/
public List<String> getHeaders() {
return this.headers;
}

/**
* Creates an exception.
*
Expand All @@ -63,7 +91,8 @@ public static class Builder {
private Integer httpStatusCode;
private URI serverUri;
private String responseBody;
private String headers;
private final List<String> headers = new ArrayList<>();
private String headersString;

public Builder(String message) {
this.message = message;
Expand Down Expand Up @@ -92,21 +121,21 @@ public Builder withResponseBody(String responseBody) {
}

public Builder withHeaders(String... headers) {
this.headers = "[";
for (String header : headers) {
this.headers += header;
}
this.headers += "]";
List<String> headerList = Arrays.stream(headers).filter(Objects::nonNull).toList();

this.headers.addAll(headerList);
this.headersString = headerList.stream().collect(Collectors.joining(", ", "[", "]"));

return this;
}

public OAuth2ServiceException build() {
String message = Stream
String m = Stream
.of(this.message, createUriMessage(), createStatusCodeMessage(), createResponseBodyMessage(),
createHeaderMessage())
.filter(Objects::nonNull)
.collect(Collectors.joining(". "));
return new OAuth2ServiceException(message, httpStatusCode);
return new OAuth2ServiceException(m, httpStatusCode, headers);
}

private String createResponseBodyMessage() {
Expand All @@ -122,7 +151,7 @@ private String createUriMessage() {
}

private String createHeaderMessage() {
return headers == null ? null : "Headers " + headers;
return headersString == null ? null : "Headers " + headersString;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

import javax.annotation.Nonnull;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
Expand Down Expand Up @@ -70,12 +72,12 @@ protected OAuth2TokenResponse requestAccessToken(URI tokenEndpointUri, HttpHeade
String warningMsg = String.format(
"Error retrieving JWT token. Received status code %s. Call to XSUAA was not successful: %s",
ex.getStatusCode(), ex.getResponseBodyAsString());
throw new OAuth2ServiceException(warningMsg);
throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(), getHeaders(ex.getResponseHeaders()));
} catch (HttpServerErrorException ex) {
String warningMsg = String.format("Server error while obtaining access token from XSUAA (%s): %s",
ex.getStatusCode(), ex.getResponseBodyAsString());
LOGGER.error(warningMsg, ex);
throw new OAuth2ServiceException(warningMsg);
throw new OAuth2ServiceException(warningMsg, ex.getStatusCode().value(), getHeaders(ex.getResponseHeaders()));
} catch (ResourceAccessException ex) {
String warningMsg = String.format(
"RestClient isn't configured properly - Error while obtaining access token from XSUAA (%s): %s",
Expand All @@ -95,15 +97,21 @@ protected OAuth2TokenResponse requestAccessToken(URI tokenEndpointUri, HttpHeade
return new OAuth2TokenResponse(accessToken, expiresIn, refreshToken, tokenType);
}

private static List<String> getHeaders(org.springframework.http.HttpHeaders ex) {
if (ex != null){
return ex.toSingleValueMap().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).toList();
}
return Collections.emptyList();
}

/**
* Creates a copy of the given map or an new empty map of type MultiValueMap.
* Creates a copy of the given map or a new empty map of type MultiValueMap.
*
* @return a new @link{MultiValueMap} that contains all entries of the optional
* map.
*/
private MultiValueMap<String, String> copyIntoForm(Map<String, String> parameters) {
@SuppressWarnings("unchecked")
MultiValueMap<String, String> formData = new LinkedMultiValueMap();
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
if (parameters != null) {
parameters.forEach(formData::add);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.sap.cloud.security.xsuaa.client;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.util.List;

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

class OAuth2ServiceExceptionTest {
public static final String SERVICE_EXCEPTION = "Service Exception";
private static List<String> headers;
private static OAuth2ServiceException builtWithHeaders;
private static OAuth2ServiceException createdWithHeaders;

@BeforeAll
static void setup() {
headers = List.of("header1=value1", "header2=value2");
builtWithHeaders = OAuth2ServiceException.builder(SERVICE_EXCEPTION).withHeaders(headers.toArray(String[]::new)).withStatusCode(400).build();
createdWithHeaders = new OAuth2ServiceException(SERVICE_EXCEPTION, 400, headers);
}

@Test
void testWithHeaders() {
assertIterableEquals(headers, builtWithHeaders.getHeaders());
assertTrue(builtWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
assertTrue(builtWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
assertEquals(400, builtWithHeaders.getHttpStatusCode());

assertIterableEquals(headers, createdWithHeaders.getHeaders());
assertTrue(createdWithHeaders.getMessage().contains(SERVICE_EXCEPTION));
assertFalse(createdWithHeaders.getMessage().contains("[header1=value1, header2=value2]"));
assertEquals(400, createdWithHeaders.getHttpStatusCode());
}
}

0 comments on commit 003db33

Please sign in to comment.