Skip to content

Commit

Permalink
add http headers to OAuth2ServiceException (#1256)
Browse files Browse the repository at this point in the history
  • Loading branch information
liga-oz authored Aug 11, 2023
1 parent 05791c5 commit 011188f
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -108,6 +109,7 @@ private OAuth2TokenResponse executeRequest(HttpPost httpPost) throws OAuth2Servi
throw OAuth2ServiceException.builder("Error retrieving JWT token")
.withStatusCode(statusCode)
.withUri(httpPost.getURI())
.withHeaders(Arrays.toString(response.getAllHeaders()))
.withResponseBody(responseBodyAsString)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import java.io.IOException;
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 @@ -18,6 +21,7 @@ public class OAuth2ServiceException extends IOException {

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 @@ -41,9 +45,15 @@ public OAuth2ServiceException(String message, Integer httpStatusCode) {
*
* @param message
* the error message
* @param httpStatusCode
* the status code of the HTTP service request
* @param headers
* the headers of the HTTP service request
*/
public static Builder builder(String message) {
return new Builder(message);

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

/**
Expand All @@ -56,20 +66,39 @@ 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.
*
* @param message
* the error message
*/
public static Builder builder(String message) {
return new Builder(message);
}

public static class Builder {
private String message;
private final String message;
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;
}

/**
* Parameterizes the Exception with a HTTP status code.
*
* Parameterizes the Exception with an HTTP status code.
*
* @param httpStatusCode
* the http status code
* @return the builder
Expand All @@ -90,21 +119,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).collect(Collectors.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 @@ -120,7 +149,7 @@ private String createUriMessage() {
}

private String createHeaderMessage() {
return headers == null ? null : "Headers " + headers;
return headersString == null ? null : "Headers " + headersString;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

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

import static com.sap.cloud.security.xsuaa.Assertions.assertNotNull;
import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.*;
Expand Down Expand Up @@ -87,12 +90,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 @@ -112,15 +115,22 @@ 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()).collect(
Collectors.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,38 @@
package com.sap.cloud.security.xsuaa.client;

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

import java.util.ArrayList;
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 = new ArrayList<>();
headers.add("header1=value1");
headers.add("header2=value2");
builtWithHeaders = OAuth2ServiceException.builder(SERVICE_EXCEPTION).withHeaders(headers.toArray(new String[0])).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 011188f

Please sign in to comment.