Java Auth and auth lib changes

This commit is contained in:
Meena Peri 2023-09-29 17:37:57 -05:00
parent 39dd71cdb6
commit fcf32fdff6
19 changed files with 241 additions and 862 deletions

View File

@ -38,39 +38,6 @@ com.squareup.okhttp.Request signedRequest = new LWAAuthorizationSigner(lwaAuthor
.sign(request);
```
## AWSSigV4Signer
Signs a request with [AWS Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)
using the provided AWS developer account credentials.
*Example*
```
com.squareup.okhttp.Request request = new Request.Builder()
.url(...)
...
.build();
AWSAuthenticationCredentials awsAuthenticationCredentials = AWSAuthenticationCredentials.builder()
.accessKeyId("...")
.secretKey("...")
.region("...")
.build();
com.squareup.okhttp.Request signedRequest = new AWSSigV4Signer(awsAuthenticationCredentials)
.sign(request);
/*Signs request using IAM role credentials.
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider = AWSAuthenticationCredentialsProvider.builder()
.roleArn("...")
.roleSessionName("...")
.build();
com.squareup.okhttp.Request signedRequest = new
AWSSigV4Signer(awsAuthenticationCredentialsProvider.getCredentials())
.sign(request);
```
## LWAAccessTokenCache
Interface to implement cache for access token that is returned in LWAClient and reuse the access token until time to live.
@ -79,7 +46,6 @@ Interface to set and get rateLimit configurations that are used with RateLimiter
*Example*
```
com.squareup.okhttp.Request request = new Request.Builder()
.url(...)
...
@ -89,8 +55,22 @@ com.squareup.okhttp.Request request = new Request.Builder()
.rateLimitPermit(...)
.waitTimeOutInMilliSeconds(...)
.build();
```
## Exception
This package returns a custom LWAException when there is an error returned during LWA authorization. LWAException provides additional details like errorCode and errorDescription to help fix the issue.
*Example*
```
catch (LWAException e) {
System.err.println("LWA Exception when calling Selling partner API");
System.err.println(e.getErrorCode());
System.err.println(e.getErrorMessage());
e.printStackTrace();
}
```
## Version
Selling Partner API Authentication/Authorization Library version 2.0.
## Resources
This package features Mustache templates designed for use with [swagger codegen](https://swagger.io/tools/swagger-codegen/).

View File

@ -6,7 +6,7 @@
<groupId>com.amazon.sellingpartnerapi</groupId>
<artifactId>sellingpartnerapi-aa-java</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<version>2.0</version>
<build>
<plugins>
<plugin>

View File

@ -0,0 +1,3 @@
{
"artifactVersion": "2.0"
}

View File

@ -51,10 +51,10 @@ import {{invokerPackage}}.auth.HttpBasicAuth;
import {{invokerPackage}}.auth.ApiKeyAuth;
import {{invokerPackage}}.auth.OAuth;
import com.amazon.SellingPartnerAPIAA.AWSSigV4Signer;
import com.amazon.SellingPartnerAPIAA.LWAAuthorizationSigner;
import com.google.common.util.concurrent.RateLimiter;
import com.amazon.SellingPartnerAPIAA.RateLimitConfiguration;
import com.amazon.SellingPartnerAPIAA.LWAException;
public class ApiClient {
@ -79,7 +79,6 @@ public class ApiClient {
private HttpLoggingInterceptor loggingInterceptor;
private LWAAuthorizationSigner lwaAuthorizationSigner;
private AWSSigV4Signer awsSigV4Signer;
private RateLimiter rateLimiter;
private RateLimitConfiguration rateLimitConfiguration;
@ -496,17 +495,6 @@ public class ApiClient {
this.lwaAuthorizationSigner = lwaAuthorizationSigner;
return this;
}
/**
* Sets the AWSSigV4Signer
*
* @param awsSigV4Signer AWSSigV4Signer instance
* @return Api client
*/
public ApiClient setAWSSigV4Signer(AWSSigV4Signer awsSigV4Signer) {
this.awsSigV4Signer = awsSigV4Signer;
return this;
}
/**
* Sets the RateLimiter
@ -985,8 +973,9 @@ public class ApiClient {
* @param progressRequestListener Progress request listener
* @return The HTTP call
* @throws ApiException If fail to serialize the request body object
* @throws LWAException If calls to fetch LWA access token fails
*/
public Call buildCall(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
public Call buildCall(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException, LWAException {
Request request = buildRequest(path, method, queryParams, collectionQueryParams, body, headerParams, formParams, authNames, progressRequestListener);
return httpClient.newCall(request);
@ -1006,8 +995,9 @@ public class ApiClient {
* @param progressRequestListener Progress request listener
* @return The HTTP request
* @throws ApiException If fail to serialize the request body object
* @throws LWAException If calls to fetch LWA access token fails
*/
public Request buildRequest(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
public Request buildRequest(String path, String method, List<Pair> queryParams, List<Pair> collectionQueryParams, Object body, Map<String, String> headerParams, Map<String, Object> formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException, LWAException {
updateParamsForAuth(authNames, queryParams, headerParams);
final String url = buildUrl(path, queryParams, collectionQueryParams);
@ -1049,7 +1039,6 @@ public class ApiClient {
}
request = lwaAuthorizationSigner.sign(request);
request = awsSigV4Signer.sign(request);
return request;
}

View File

@ -43,15 +43,12 @@ import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}
import com.amazon.SellingPartnerAPIAA.AWSAuthenticationCredentials;
import com.amazon.SellingPartnerAPIAA.AWSAuthenticationCredentialsProvider;
import com.amazon.SellingPartnerAPIAA.AWSAuthenticationCustomCredentialsProvider;
import com.amazon.SellingPartnerAPIAA.AWSSigV4Signer;
import com.amazon.SellingPartnerAPIAA.LWAAccessTokenCache;
import com.amazon.SellingPartnerAPIAA.LWAAccessTokenCacheImpl;
import com.amazon.SellingPartnerAPIAA.LWAAuthorizationCredentials;
import com.amazon.SellingPartnerAPIAA.LWAAuthorizationSigner;
import com.amazon.SellingPartnerAPIAA.RateLimitConfiguration;
import com.amazon.SellingPartnerAPIAA.LWAException;
{{#operations}}
public class {{classname}} {
@ -81,6 +78,7 @@ public class {{classname}} {
* @param progressRequestListener Progress request listener
* @return Call to execute
* @throws ApiException If fail to serialize the request body object
* @throws LWAException If calls to fetch LWA access token fails
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
@ -92,7 +90,7 @@ public class {{classname}} {
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
public com.squareup.okhttp.Call {{operationId}}Call({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
public com.squareup.okhttp.Call {{operationId}}Call({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException, LWAException {
Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
// create path and map variables
@ -144,7 +142,7 @@ public class {{classname}} {
@Deprecated
{{/isDeprecated}}
@SuppressWarnings("rawtypes")
private com.squareup.okhttp.Call {{operationId}}ValidateBeforeCall({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
private com.squareup.okhttp.Call {{operationId}}ValidateBeforeCall({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException, LWAException {
{{^performBeanValidation}}
{{#allParams}}{{#required}}
// verify the required parameter '{{paramName}}' is set
@ -191,6 +189,7 @@ public class {{classname}} {
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/allParams}}{{#returnType}}
* @return {{returnType}}{{/returnType}}
* @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
* @throws LWAException If calls to fetch LWA access token fails
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
@ -202,7 +201,7 @@ public class {{classname}} {
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException,LWAException {
{{#returnType}}ApiResponse<{{{returnType}}}> {{localVariablePrefix}}resp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}}
return {{localVariablePrefix}}resp.getData();{{/returnType}}
}
@ -213,6 +212,7 @@ public class {{classname}} {
* @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/allParams}}
* @return ApiResponse&lt;{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}&gt;
* @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
* @throws LWAException If calls to fetch LWA access token fails
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
@ -224,7 +224,7 @@ public class {{classname}} {
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException,LWAException {
com.squareup.okhttp.Call {{localVariablePrefix}}call = {{operationId}}ValidateBeforeCall({{#allParams}}{{paramName}}, {{/allParams}}null, null);
{{#returnType}}Type {{localVariablePrefix}}localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType();
return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call, {{localVariablePrefix}}localVarReturnType);{{/returnType}}{{^returnType}}return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call);{{/returnType}}
@ -237,6 +237,7 @@ public class {{classname}} {
* @param callback The callback to be executed when the API call finishes
* @return The request call
* @throws ApiException If fail to process the API call, e.g. serializing the request body object
* @throws LWAException If calls to fetch LWA access token fails
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
@ -248,7 +249,7 @@ public class {{classname}} {
{{#isDeprecated}}
@Deprecated
{{/isDeprecated}}
public com.squareup.okhttp.Call {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{localVariablePrefix}}callback) throws ApiException {
public com.squareup.okhttp.Call {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{localVariablePrefix}}callback) throws ApiException, LWAException {
ProgressResponseBody.ProgressListener progressListener = null;
ProgressRequestBody.ProgressRequestListener progressRequestListener = null;
@ -277,19 +278,12 @@ public class {{classname}} {
{{/operation}}
public static class Builder {
private AWSAuthenticationCredentials awsAuthenticationCredentials;
private LWAAuthorizationCredentials lwaAuthorizationCredentials;
private String endpoint;
private LWAAccessTokenCache lwaAccessTokenCache;
private Boolean disableAccessTokenCache = false;
private AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider;
private RateLimitConfiguration rateLimitConfiguration;
private AWSAuthenticationCustomCredentialsProvider awsAuthenticationCustomCredentialsProvider;
public Builder awsAuthenticationCredentials(AWSAuthenticationCredentials awsAuthenticationCredentials) {
this.awsAuthenticationCredentials = awsAuthenticationCredentials;
return this;
}
public Builder lwaAuthorizationCredentials(LWAAuthorizationCredentials lwaAuthorizationCredentials) {
this.lwaAuthorizationCredentials = lwaAuthorizationCredentials;
@ -310,12 +304,7 @@ public class {{classname}} {
this.disableAccessTokenCache = true;
return this;
}
public Builder awsAuthenticationCredentialsProvider(AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) {
this.awsAuthenticationCredentialsProvider = awsAuthenticationCredentialsProvider;
return this;
}
public Builder rateLimitConfigurationOnRequests(RateLimitConfiguration rateLimitConfiguration){
this.rateLimitConfiguration = rateLimitConfiguration;
return this;
@ -326,17 +315,7 @@ public class {{classname}} {
return this;
}
public Builder awsAuthenticationCustomCredentialsProvider(AWSAuthenticationCustomCredentialsProvider awsAuthenticationCustomCredentialsProvider) {
this.awsAuthenticationCustomCredentialsProvider = awsAuthenticationCustomCredentialsProvider;
return this;
}
public {{classname}} build() {
if (awsAuthenticationCredentials == null && awsAuthenticationCustomCredentialsProvider == null) {
throw new RuntimeException("Neither AWSAuthenticationCredentials or AWSAuthenticationCustomCredentialsProvider are set");
}
if (lwaAuthorizationCredentials == null) {
throw new RuntimeException("LWAAuthorizationCredentials not set");
}
@ -344,17 +323,6 @@ public class {{classname}} {
if (StringUtil.isEmpty(endpoint)) {
throw new RuntimeException("Endpoint not set");
}
AWSSigV4Signer awsSigV4Signer;
if (awsAuthenticationCustomCredentialsProvider != null ) {
awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCustomCredentialsProvider);
}
else if (awsAuthenticationCredentialsProvider == null) {
awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCredentials);
}
else {
awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCredentials,awsAuthenticationCredentialsProvider);
}
LWAAuthorizationSigner lwaAuthorizationSigner = null;
if (disableAccessTokenCache) {
@ -368,7 +336,6 @@ public class {{classname}} {
}
return new {{classname}}(new ApiClient()
.setAWSSigV4Signer(awsSigV4Signer)
.setLWAAuthorizationSigner(lwaAuthorizationSigner)
.setBasePath(endpoint)
.setRateLimiter(rateLimitConfiguration));

View File

@ -0,0 +1,46 @@
{{>licenseInfo}}
package {{package}};
import {{invokerPackage}}.ApiException;
{{#imports}}import {{import}};
{{/imports}}
import org.junit.Test;
import org.junit.Ignore;
{{^fullJavaUtil}}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}
import com.amazon.SellingPartnerAPIAA.LWAException;
/**
* API tests for {{classname}}
*/
@Ignore
public class {{classname}}Test {
private final {{classname}} api = new {{classname}}();
{{#operations}}{{#operation}}
/**
* {{summary}}
*
* {{notes}}
*
* @throws ApiException if the Api call fails
* @throws LWAException If calls to fetch LWA access token fails
*/
@Test
public void {{operationId}}Test() throws ApiException, LWAException {
{{#allParams}}
{{{dataType}}} {{paramName}} = null;
{{/allParams}}
{{#returnType}}{{{returnType}}} response = {{/returnType}}api.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
// TODO: test validations
}
{{/operation}}{{/operations}}
}

View File

@ -1,30 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
/**
* AWSAuthenticationCredentials
*/
@Data
@Builder
public class AWSAuthenticationCredentials {
/**
* AWS IAM User Access Key Id
*/
@NonNull
private String accessKeyId;
/**
* AWS IAM User Secret Key
*/
@NonNull
private String secretKey;
/**
* AWS Region
*/
@NonNull
private String region;
}

View File

@ -1,23 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import lombok.Builder;
import lombok.Data;
/**
* AWSAuthenticationCredentialsProvider
*/
@Data
@Builder
public class AWSAuthenticationCredentialsProvider {
/**
* AWS IAM Role ARN
*/
private String roleArn;
/**
* AWS IAM Role Session Name
*/
private String roleSessionName;
private String region;
}

View File

@ -1,23 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import lombok.Builder;
import lombok.Data;
import com.amazonaws.auth.AWSCredentialsProvider;
/**
* AWSAuthenticationCustomCredentialsProvider
*/
@Data
@Builder
public class AWSAuthenticationCustomCredentialsProvider {
/**
* AWS Region
*/
private String region;
/**
* AWS Credentials Provider
*/
private AWSCredentialsProvider awsCredentialsProvider;
}

View File

@ -1,109 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import com.amazonaws.SignableRequest;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.squareup.okhttp.Request;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
/**
* AWS Signature Version 4 Signer
*/
public class AWSSigV4Signer {
private static final String SERVICE_NAME = "execute-api";
@Setter(AccessLevel.PACKAGE)
@Getter(AccessLevel.PACKAGE)
private AWS4Signer aws4Signer;
private AWSCredentials awsCredentials;
@Setter(AccessLevel.PACKAGE)
@Getter(AccessLevel.PACKAGE)
private AWSCredentialsProvider awsCredentialsProvider;
/**
*
* @param awsAuthenticationCredentials AWS Developer Account Credentials
*/
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials) {
aws4Signer = new AWS4Signer();
aws4Signer.setServiceName(SERVICE_NAME);
aws4Signer.setRegionName(awsAuthenticationCredentials.getRegion());
awsCredentials = new BasicAWSCredentials(awsAuthenticationCredentials.getAccessKeyId(),
awsAuthenticationCredentials.getSecretKey());
}
/**
*
* @param awsAuthenticationCredentials and awsAuthenticationCredentialsProvider AWS Developer Account Credentials
*/
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials,
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) {
aws4Signer = new AWS4Signer();
aws4Signer.setServiceName(SERVICE_NAME);
final String region;
AWSSecurityTokenServiceClientBuilder stsClientBuilder = AWSSecurityTokenServiceClientBuilder.standard();
if (awsAuthenticationCredentials != null) {
region = awsAuthenticationCredentials.getRegion();
BasicAWSCredentials awsBasicCredentials = new BasicAWSCredentials(
awsAuthenticationCredentials.getAccessKeyId(),
awsAuthenticationCredentials.getSecretKey()
);
stsClientBuilder.withCredentials(new AWSStaticCredentialsProvider(awsBasicCredentials));
} else {
region = awsAuthenticationCredentialsProvider.getRegion();
}
aws4Signer.setRegionName(region);
awsCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(
awsAuthenticationCredentialsProvider.getRoleArn(),
awsAuthenticationCredentialsProvider.getRoleSessionName())
.withStsClient(stsClientBuilder.withRegion(region).build())
.build();
}
/**
*
* @param awsAuthenticationCustomCredentialsProvider AWS Credentials Provider
*/
public AWSSigV4Signer(AWSAuthenticationCustomCredentialsProvider awsAuthenticationCustomCredentialsProvider) {
aws4Signer = new AWS4Signer();
aws4Signer.setServiceName(SERVICE_NAME);
aws4Signer.setRegionName(awsAuthenticationCustomCredentialsProvider.getRegion());
this.awsCredentialsProvider = awsAuthenticationCustomCredentialsProvider.getAwsCredentialsProvider();
}
/**
*
* @param awsAuthenticationCredentialsProvider AWS Credentials Provider containing the role name to be assumed
*/
public AWSSigV4Signer(AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) {
this(null, awsAuthenticationCredentialsProvider);
}
/**
* Signs a Request with AWS Signature Version 4
*
* @param originalRequest Request to sign (treated as immutable)
* @return Copy of originalRequest with AWS Signature
*/
public Request sign(Request originalRequest) {
SignableRequest<Request> signableRequest = new SignableRequestImpl(originalRequest);
if (awsCredentialsProvider != null) {
aws4Signer.sign(signableRequest, awsCredentialsProvider.getCredentials());
} else {
aws4Signer.sign(signableRequest, awsCredentials);
}
return (Request) signableRequest.getOriginalRequestObject();
}
}

View File

@ -64,8 +64,9 @@ public class LWAAuthorizationSigner {
* Signs a Request with an LWA Access Token
* @param originalRequest Request to sign (treated as immutable)
* @return Copy of originalRequest with LWA signature
* @throws LWAException If calls to fetch LWA access token fails
*/
public Request sign(Request originalRequest) {
public Request sign(Request originalRequest) throws LWAException {
String accessToken = lwaClient.getAccessToken(lwaAccessTokenRequestMeta);
return originalRequest.newBuilder()

View File

@ -11,8 +11,7 @@ import com.squareup.okhttp.Response;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import java.io.IOException;
import org.apache.commons.lang3.EnumUtils;
class LWAClient {
private static final String ACCESS_TOKEN_KEY = "access_token";
@ -25,7 +24,9 @@ class LWAClient {
private OkHttpClient okHttpClient;
private LWAAccessTokenCache lwaAccessTokenCache;
/** Sets cache to store access token until token is expired */
/**
* Sets cache to store access token until token is expired
*/
public void setLWAAccessTokenCache(LWAAccessTokenCache tokenCache) {
this.lwaAccessTokenCache = tokenCache;
}
@ -33,46 +34,54 @@ class LWAClient {
LWAClient(String endpoint) {
okHttpClient = new OkHttpClient();
this.endpoint = endpoint;
}
}
String getAccessToken(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
String getAccessToken(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) throws LWAException {
if (lwaAccessTokenCache != null) {
return getAccessTokenFromCache(lwaAccessTokenRequestMeta);
return getAccessTokenFromCache(lwaAccessTokenRequestMeta);
} else {
return getAccessTokenFromEndpoint(lwaAccessTokenRequestMeta);
}
}
}
String getAccessTokenFromCache(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
String getAccessTokenFromCache(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) throws LWAException {
String accessTokenCacheData = (String) lwaAccessTokenCache.get(lwaAccessTokenRequestMeta);
if (accessTokenCacheData != null) {
return accessTokenCacheData;
} else {
return getAccessTokenFromEndpoint(lwaAccessTokenRequestMeta);
}
return accessTokenCacheData;
} else {
return getAccessTokenFromEndpoint(lwaAccessTokenRequestMeta);
}
}
String getAccessTokenFromEndpoint(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
String getAccessTokenFromEndpoint(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) throws LWAException {
RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE, new Gson().toJson(lwaAccessTokenRequestMeta));
Request accessTokenRequest = new Request.Builder().url(endpoint).post(requestBody).build();
LWAExceptionErrorCode lwaErrorCode = null;
String accessToken;
try {
Response response = okHttpClient.newCall(accessTokenRequest).execute();
if (!response.isSuccessful()) {
throw new IOException("Unsuccessful LWA token exchange");
}
JsonObject responseJson = new JsonParser().parse(response.body().string()).getAsJsonObject();
if (!response.isSuccessful()) {
// Check if response has element error and is a known LWA error code
if (responseJson.has("error") &&
EnumUtils.isValidEnum(LWAExceptionErrorCode.class, responseJson.get("error").getAsString())) {
throw new LWAException(responseJson.get("error").getAsString(),
responseJson.get("error_description").getAsString(), "Error getting LWA Token");
} else { // else throw other LWA error
throw new LWAException(LWAExceptionErrorCode.other.toString(), "Other LWA Exception",
"Error getting LWA Token");
}
}
accessToken = responseJson.get(ACCESS_TOKEN_KEY).getAsString();
if (lwaAccessTokenCache != null) {
long timeToTokenexpiry = responseJson.get(ACCESS_TOKEN_EXPIRES_IN).getAsLong();
lwaAccessTokenCache.put(lwaAccessTokenRequestMeta, accessToken, timeToTokenexpiry);
}
} catch (Exception e) {
throw new RuntimeException("Error getting LWA Access Token", e);
}
return accessToken;
} catch (LWAException e) { // throw LWA exception
throw new LWAException(e.getErrorCode(), e.getErrorMessage(), e.getMessage());
} catch (Exception e) { // throw other runtime exceptions
throw new RuntimeException("Error getting LWA Token");
}
return accessToken;
}
}

View File

@ -0,0 +1,45 @@
package com.amazon.SellingPartnerAPIAA;
public class LWAException extends Exception {
private String errorMessage;
private String errorCode;
LWAException() {
super();
}
LWAException(String errorCode, String errorMessage) {
super();
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
LWAException(String errorCode, String errorMessage, String message) {
super(message);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
LWAException(String errorCode, String errorMessage, Throwable cause) {
super(cause);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
LWAException(String errorCode, String errorMessage, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public String getErrorCode() {
return this.errorCode;
}
public String getErrorMessage() {
return this.errorMessage;
}
}

View File

@ -0,0 +1,13 @@
package com.amazon.SellingPartnerAPIAA;
public enum LWAExceptionErrorCode {
access_denied,
invalid_grant,
invalid_request,
invalid_scope,
server_error,
temporarily_unavailable,
unauthorized_client,
invalid_client,
other;
}

View File

@ -1,148 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import com.amazonaws.ReadLimitInfo;
import com.amazonaws.SignableRequest;
import com.amazonaws.http.HttpMethodName;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.Request;
import okio.Buffer;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class SignableRequestImpl implements SignableRequest<Request> {
private static final String CONTENT_TYPE_HEADER_NAME = "Content-Type";
private Request originalRequest;
private Request.Builder signableRequestBuilder;
SignableRequestImpl(Request originalRequest) {
this.originalRequest = originalRequest;
signableRequestBuilder = originalRequest.newBuilder();
}
@Override
public void addHeader(String name, String value) {
signableRequestBuilder.addHeader(name, value);
}
@Override
public void addParameter(String name, String value) {
HttpUrl newUrl = signableRequestBuilder.build()
.httpUrl()
.newBuilder()
.addEncodedQueryParameter(name, value)
.build();
signableRequestBuilder.url(newUrl);
}
@Override
public void setContent(InputStream inputStream) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, String> getHeaders() {
Map<String, String> headers = new HashMap<>();
Request requestSnapshot = signableRequestBuilder.build();
requestSnapshot.headers()
.names()
.forEach(headerName -> headers.put(headerName, requestSnapshot.header(headerName)));
if (requestSnapshot.body() != null) {
MediaType contentType = requestSnapshot.body().contentType();
if (contentType != null) {
headers.put(CONTENT_TYPE_HEADER_NAME, contentType.toString());
}
}
return headers;
}
@Override
public String getResourcePath() {
return originalRequest.url()
.getPath();
}
@Override
public Map<String, List<String>> getParameters() {
Map<String, List<String>> parameters = new HashMap<>();
try {
List<NameValuePair> nameValuePairs = URLEncodedUtils.parse(originalRequest.url().toURI(),
StandardCharsets.UTF_8);
nameValuePairs.forEach(nameValuePair -> parameters.put(nameValuePair.getName(),
Collections.singletonList(nameValuePair.getValue())));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
return parameters;
}
@Override
public URI getEndpoint() {
URI uri = null;
try {
uri = originalRequest.url().toURI();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
return URI.create(String.format("%s://%s", uri.getScheme(), uri.getHost()));
}
@Override
public HttpMethodName getHttpMethod() {
return HttpMethodName.fromValue(originalRequest.method().toUpperCase());
}
@Override
public int getTimeOffset() {
return 0;
}
@Override
public InputStream getContent() {
ByteArrayInputStream inputStream = null;
if (originalRequest.body() != null) {
try {
Buffer buffer = new Buffer();
originalRequest.body().writeTo(buffer);
inputStream = new ByteArrayInputStream(buffer.readByteArray());
} catch (IOException e) {
throw new RuntimeException("Unable to buffer request body", e);
}
}
return inputStream;
}
@Override
public InputStream getContentUnwrapped() {
return getContent();
}
@Override
public ReadLimitInfo getReadLimitInfo() {
return null;
}
@Override
public Object getOriginalRequestObject() {
return signableRequestBuilder.build();
}
}

View File

@ -1,148 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import com.amazonaws.SignableRequest;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.squareup.okhttp.Request;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class AWSSigV4SignerTest {
private static final String TEST_ACCESS_KEY_ID = "aKey";
private static final String TEST_SECRET_KEY = "sKey";
private static final String TEST_REGION = "us-east";
private static final String TEST_ROLE_ARN = "arnrole";
private static final String TEST_ROLESESSION_NAME = "test";
@Mock
private AWS4Signer mockAWS4Signer;
@Mock
private AWSCredentialsProvider mockAWSCredentialsProvider;
@Mock
private AWSCredentials mockAWSCredentials;
private AWSSigV4Signer underTest;
private AWSSigV4Signer underTestCredentialsProvider;
@Before
public void init() {
underTest = new AWSSigV4Signer(AWSAuthenticationCredentials.builder()
.accessKeyId(TEST_ACCESS_KEY_ID)
.secretKey(TEST_SECRET_KEY)
.region(TEST_REGION)
.build()
);
}
@Test
public void signRequestUsingProvidedCredentials() {
ArgumentCaptor<AWSCredentials> awsCredentialsArgumentCaptor = ArgumentCaptor.forClass(AWSCredentials.class);
underTest.setAws4Signer(mockAWS4Signer);
doNothing()
.when(mockAWS4Signer)
.sign(any(SignableRequest.class), awsCredentialsArgumentCaptor.capture());
underTest.sign(new Request.Builder().url("https://api.amazon.com").build());
AWSCredentials actualAWSCredentials = awsCredentialsArgumentCaptor.getValue();
assertEquals(TEST_ACCESS_KEY_ID, actualAWSCredentials.getAWSAccessKeyId());
assertEquals(TEST_SECRET_KEY, actualAWSCredentials.getAWSSecretKey());
}
@Test
public void setSignerRegion() {
assertEquals(TEST_REGION, underTest.getAws4Signer().getRegionName());
}
@Test
public void setSignerServiceName() {
assertEquals("execute-api", underTest.getAws4Signer().getServiceName());
}
@Test
public void returnSignedRequest() {
ArgumentCaptor<SignableRequest> signableRequestArgumentCaptor = ArgumentCaptor.forClass(SignableRequest.class);
underTest.setAws4Signer(mockAWS4Signer);
Request actualSignedRequest = underTest.sign(new Request.Builder()
.url("http://api.amazon.com")
.build());
verify(mockAWS4Signer)
.sign(signableRequestArgumentCaptor.capture(), any(AWSCredentials.class));
SignableRequest actualSignableRequest = signableRequestArgumentCaptor.getValue();
assertEquals(((Request)actualSignableRequest.getOriginalRequestObject()).url(), actualSignedRequest.url());
}
@Test
public void returnSignedRequestWithCredentialProvider() {
ArgumentCaptor<SignableRequest> signableRequestArgumentCaptor = ArgumentCaptor.forClass(SignableRequest.class);
Mockito.when(mockAWSCredentialsProvider.getCredentials()).thenReturn(mockAWSCredentials);
underTestCredentialsProvider = new AWSSigV4Signer(AWSAuthenticationCredentials.builder()
.accessKeyId(TEST_ACCESS_KEY_ID)
.secretKey(TEST_SECRET_KEY)
.region(TEST_REGION)
.build(), AWSAuthenticationCredentialsProvider.builder()
.roleArn(TEST_ROLE_ARN)
.roleSessionName(TEST_ROLESESSION_NAME)
.build()
);
underTestCredentialsProvider.setAws4Signer(mockAWS4Signer);
underTestCredentialsProvider.setAwsCredentialsProvider(mockAWSCredentialsProvider);
Request actualSignedRequest = underTestCredentialsProvider.sign(new Request.Builder()
.url("http://api.amazon.com")
.build());
verify(mockAWS4Signer)
.sign(signableRequestArgumentCaptor.capture(), any(AWSCredentials.class));
SignableRequest actualSignableRequest = signableRequestArgumentCaptor.getValue();
assertEquals(((Request)actualSignableRequest.getOriginalRequestObject()).url(), actualSignedRequest.url());
}
@Test
public void returnSignedRequestWithCustomCredentialsProvider() {
ArgumentCaptor<SignableRequest> signableRequestArgumentCaptor = ArgumentCaptor.forClass(SignableRequest.class);
Mockito.when(mockAWSCredentialsProvider.getCredentials()).thenReturn(mockAWSCredentials);
underTestCredentialsProvider = new AWSSigV4Signer(AWSAuthenticationCustomCredentialsProvider.builder()
.awsCredentialsProvider(mockAWSCredentialsProvider)
.region(TEST_REGION)
.build());
underTestCredentialsProvider.setAws4Signer(mockAWS4Signer);
Request actualSignedRequest = underTestCredentialsProvider.sign(new Request.Builder()
.url("http://api.amazon.com")
.build());
verify(mockAWS4Signer)
.sign(signableRequestArgumentCaptor.capture(), any(AWSCredentials.class));
SignableRequest actualSignableRequest = signableRequestArgumentCaptor.getValue();
assertEquals(((Request)actualSignableRequest.getOriginalRequestObject()).url(), actualSignedRequest.url());
}
}

View File

@ -98,7 +98,7 @@ public class LWAAuthorizationSignerTest {
@ParameterizedTest
@MethodSource("lwaAuthSigner")
public void requestLWAAccessTokenFromConfiguration(String sellerType, LWAAuthorizationSigner testAuthSigner) {
public void requestLWAAccessTokenFromConfiguration(String sellerType, LWAAuthorizationSigner testAuthSigner) throws LWAException {
LWAClient mockLWAClient = mock(LWAClient.class);
ArgumentCaptor<LWAAccessTokenRequestMeta> lwaAccessTokenRequestMetaArgumentCaptor = ArgumentCaptor.forClass(LWAAccessTokenRequestMeta.class);
@ -126,7 +126,7 @@ public class LWAAuthorizationSignerTest {
@ParameterizedTest
@MethodSource("lwaAuthSigner")
public void returnSignedRequestWithAccessTokenFromLWAClient(String sellerType, LWAAuthorizationSigner testAuthSigner) {
public void returnSignedRequestWithAccessTokenFromLWAClient(String sellerType, LWAAuthorizationSigner testAuthSigner) throws LWAException {
LWAClient mockLWAClient = mock(LWAClient.class);
when(mockLWAClient.getAccessToken(any(LWAAccessTokenRequestMeta.class)))
@ -140,7 +140,7 @@ public class LWAAuthorizationSignerTest {
@ParameterizedTest
@MethodSource("lwaAuthSigner")
public void originalRequestIsImmutable(String sellerType, LWAAuthorizationSigner testAuthSigner) {
public void originalRequestIsImmutable(String sellerType, LWAAuthorizationSigner testAuthSigner) throws LWAException {
LWAClient mockLWAClient = mock(LWAClient.class);
when(mockLWAClient.getAccessToken(any(LWAAccessTokenRequestMeta.class)))
@ -151,7 +151,7 @@ public class LWAAuthorizationSignerTest {
}
@Test
public void returnSignedRequestWithAccessTokenFromLWACache() throws IOException {
public void returnSignedRequestWithAccessTokenFromLWACache() throws IOException, LWAException {
LWAClient testLWAClient = new LWAClient(TEST_ENDPOINT);
testLWAClient.setOkHttpClient(mockOkHttpClient);

View File

@ -53,7 +53,10 @@ public class LWAClientTest {
private static final String SELLER_TYPE_SELLER = "seller";
private static final String SELLER_TYPE_SELLERLESS = "sellerless";
private static final String LWA_EXCEPTION_MSG ="Error getting LWA Token";
private static final String LWA_CLIENT_AUTH_MSG ="Client_authentication_failed";
private static final String LWA_ACCESS_DENIED_MSG ="Authorization_server_denied_the_request";
@Mock
private OkHttpClient mockOkHttpClient;
@ -101,7 +104,7 @@ public class LWAClientTest {
@ParameterizedTest
@MethodSource("lwaClient")
public void makeRequestFromMeta (String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException {
public void makeRequestFromMeta (String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws LWAException,IOException {
ArgumentCaptor<Request> requestArgumentCaptor = ArgumentCaptor.forClass(Request.class);
when(mockOkHttpClient.newCall(requestArgumentCaptor.capture()))
.thenReturn(mockCall);
@ -134,7 +137,7 @@ public class LWAClientTest {
@ParameterizedTest
@MethodSource("lwaClient")
public void returnAccessTokenFromResponse(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException {
public void returnAccessTokenFromResponse(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
@ -145,20 +148,54 @@ public class LWAClientTest {
@ParameterizedTest
@MethodSource("lwaClient")
public void unsuccessfulPostThrowsException(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException {
public void unsuccessfulPostThrowsLwaExceptionUnknownErrorCode(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(400, "Azta|foo"));
Assertions.assertThrows(RuntimeException.class, () -> {
Throwable exception = Assertions.assertThrows(LWAException.class, () -> {
underTest.getAccessToken(testLwaAccessTokenRequestMeta);
});
assertEquals(LWAExceptionErrorCode.other.toString(),((LWAException)exception).getErrorCode());
assertEquals(LWA_EXCEPTION_MSG, exception.getMessage());
}
@ParameterizedTest
@MethodSource("lwaClient")
public void missingAccessTokenInResponseThrowsException(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException {
public void unsuccessfulPostThrowsLwaExceptionKnownErrorCode1(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(401, "Azta|foo","invalid_client","Client_authentication_failed"));
Throwable exception = Assertions.assertThrows(LWAException.class, () -> {
underTest.getAccessToken(testLwaAccessTokenRequestMeta);
});
assertEquals(LWAExceptionErrorCode.invalid_client.toString(),((LWAException)exception).getErrorCode());
assertEquals(LWA_EXCEPTION_MSG, exception.getMessage());
assertEquals(LWA_CLIENT_AUTH_MSG,((LWAException)exception).getErrorMessage());
}
@ParameterizedTest
@MethodSource("lwaClient")
public void unsuccessfulPostThrowsLwaExceptionKnownErrorCode2(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(401, "Azta|foo","access_denied","Authorization_server_denied_the_request"));
Throwable exception = Assertions.assertThrows(LWAException.class, () -> {
underTest.getAccessToken(testLwaAccessTokenRequestMeta);
});
assertEquals(LWAExceptionErrorCode.access_denied.toString(),((LWAException)exception).getErrorCode());
assertEquals(LWA_EXCEPTION_MSG, exception.getMessage());
assertEquals(LWA_ACCESS_DENIED_MSG,((LWAException)exception).getErrorMessage());
}
@ParameterizedTest
@MethodSource("lwaClient")
public void missingAccessTokenInResponseThrowsException(String sellerType, LWAAccessTokenRequestMeta testLwaAccessTokenRequestMeta) throws IOException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
@ -171,7 +208,7 @@ public class LWAClientTest {
//Test for Access Token getting from cache
@Test
public void returnAccessTokenFromCache() throws IOException, InterruptedException {
public void returnAccessTokenFromCache() throws IOException, InterruptedException, LWAException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
@ -187,7 +224,7 @@ public class LWAClientTest {
}
@Test
public void returnAccessTokenFromCacheWithExpiry() throws IOException, InterruptedException {
public void returnAccessTokenFromCacheWithExpiry() throws IOException, InterruptedException, LWAException {
LWAClient client = new LWAClient(TEST_ENDPOINT);
client.setOkHttpClient(mockOkHttpClient);
when(mockOkHttpClient.newCall(any(Request.class)))
@ -202,9 +239,9 @@ public class LWAClientTest {
assertEquals("Azta|foo1", client.getAccessToken(lwaAccessTokenRequestMetaSeller));
}
private static Response buildResponse(int code, String accessToken, String expiryInSeconds) {
private static Response buildResponse(int code, String accessToken, String expiryInSeconds,String errorCode, String errorMessage) {
ResponseBody responseBody = ResponseBody.create(EXPECTED_MEDIA_TYPE,
String.format("{%s:%s,%s:%s}", "access_token", accessToken, "expires_in", expiryInSeconds));
String.format("{%s:%s,%s:%s,%s:%s,%s:%s}", "access_token", accessToken, "expires_in", expiryInSeconds, "error", errorCode, "error_description", errorMessage));
return new Response.Builder()
.request(new Request.Builder().url(TEST_ENDPOINT).build())
@ -215,7 +252,24 @@ public class LWAClientTest {
.build();
}
private static Response buildResponse(int code, String accessToken,String errorCode, String errorMessage) {
return buildResponse(code, accessToken, "3600",errorCode,errorMessage);
}
private static Response buildResponse(int code, String accessToken) {
return buildResponse(code, accessToken, "3600");
}
private static Response buildResponse(int code, String accessToken,String expiryInSeconds) {
ResponseBody responseBody = ResponseBody.create(EXPECTED_MEDIA_TYPE,
String.format("{%s:%s,%s:%s}", "access_token", accessToken, "expires_in", expiryInSeconds));
return new Response.Builder()
.request(new Request.Builder().url(TEST_ENDPOINT).build())
.code(code)
.body(responseBody)
.protocol(Protocol.HTTP_1_1)
.message("OK")
.build();
}
}

View File

@ -1,247 +0,0 @@
package com.amazon.SellingPartnerAPIAA;
import com.amazonaws.http.HttpMethodName;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class SignableRequestImplTest {
private Request testRequest;
private SignableRequestImpl underTest;
@Before
public void init() {
testRequest = new Request.Builder()
.url("http://www.amazon.com/request/library?test=true&sky=blue&right=右")
.get()
.build();
underTest = new SignableRequestImpl(testRequest);
}
@Test
public void getHttpMethod() {
assertEquals(HttpMethodName.GET, underTest.getHttpMethod());
underTest = new SignableRequestImpl(new Request.Builder()
.url("https://www.amazon.com")
.post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "{\"foo\": \"bar\"}"))
.build());
assertEquals(HttpMethodName.POST, underTest.getHttpMethod());
}
@Test
public void getOriginalRequestObject() {
Request actualRequest = (Request)underTest.getOriginalRequestObject();
assertNotSame(testRequest, actualRequest);
assertEquals(testRequest.method(), actualRequest.method());
assertEquals(testRequest.url(), actualRequest.url());
assertEquals(testRequest.headers().toMultimap(), actualRequest.headers().toMultimap());
assertEquals(testRequest.body(), actualRequest.body());
}
@Test
public void getReadLimitInfo() {
assertNull(underTest.getReadLimitInfo());
}
@Test
public void getResourcePath() {
assertEquals("/request/library", underTest.getResourcePath());
}
@Test
public void getResourcePathWithPoundChar() {
testRequest = new Request.Builder()
.url("http://www.amazon.com/request/%23library")
.get()
.build();
underTest = new SignableRequestImpl(testRequest);
assertEquals("/request/%23library", underTest.getResourcePath());
}
@Test
public void noTimeOffset() {
assertEquals(0, underTest.getTimeOffset());
}
@Test
public void getEndpoint() {
assertEquals(URI.create("http://www.amazon.com"), underTest.getEndpoint());
}
@Test
public void headers() {
Map<String, String> expectedHeaders = new HashMap<>();
assertTrue(underTest.getHeaders().isEmpty());
underTest.addHeader("foo", "bar");
expectedHeaders.put("foo", "bar");
assertEquals(expectedHeaders, underTest.getHeaders());
underTest.addHeader("ban", "bop");
expectedHeaders.put("ban", "bop");
assertEquals(expectedHeaders, underTest.getHeaders());
}
@Test
public void getParameters() {
Map<String, List<String>> expectedParamters = new HashMap<>();
expectedParamters.put("test", Collections.singletonList("true"));
expectedParamters.put("sky", Collections.singletonList("blue"));
expectedParamters.put("right", Collections.singletonList("右"));
assertEquals(expectedParamters, underTest.getParameters());
}
@Test
public void getContent() {
String expectedContent = "{\"foo\":\"bar\"}";
StringBuilder actualContent = new StringBuilder();
underTest = new SignableRequestImpl(new Request.Builder()
.url("https://www.amazon.com")
.post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), expectedContent))
.build());
try(Scanner scanner = new Scanner(underTest.getContent())){
while(scanner.hasNext()) {
actualContent.append(scanner.next());
}
}
assertEquals(expectedContent, actualContent.toString());
}
@Test
public void getUnwrappedContent() {
String expectedContent = "{\"ban\":\"bop\"}";
StringBuilder actualContent = new StringBuilder();
underTest = new SignableRequestImpl(new Request.Builder()
.url("https://www.amazon.com")
.post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), expectedContent))
.build());
try(Scanner scanner = new Scanner(underTest.getContentUnwrapped())){
while(scanner.hasNext()) {
actualContent.append(scanner.next());
}
}
assertEquals(expectedContent, actualContent.toString());
}
@Test(expected = UnsupportedOperationException.class)
public void setContentNotSupported() {
underTest.setContent(new ByteArrayInputStream("abc".getBytes()));
}
@Test
public void addParameter() {
underTest.addParameter("left", "左");
HttpUrl actualHttpUrl = ((Request) underTest.getOriginalRequestObject())
.httpUrl();
assertEquals(Collections.singletonList("true"), actualHttpUrl.queryParameterValues("test"));
assertEquals(Collections.singletonList("blue"), actualHttpUrl.queryParameterValues("sky"));
assertEquals(Collections.singletonList("右"), actualHttpUrl.queryParameterValues("right"));
assertEquals(Collections.singletonList("左"), actualHttpUrl.queryParameterValues("left"));
}
@Test
public void gracefulBlankParametersParse() {
testRequest = new Request.Builder()
.url("http://www.amazon.com/request/library? ")
.get()
.build();
underTest = new SignableRequestImpl(testRequest);
assertTrue(underTest.getParameters().isEmpty());
}
@Test
public void gracefulIncompleteParameterPairsParse() {
testRequest = new Request.Builder()
.url("http://www.amazon.com/request/library?isSigned& =false")
.get()
.build();
Map<String, List<String>> expected = new HashMap<>();
expected.put("isSigned", Collections.singletonList(null));
expected.put(" ", Collections.singletonList("false"));
underTest = new SignableRequestImpl(testRequest);
assertEquals(expected, underTest.getParameters());
}
@Test
public void getHeadersIncludesContentTypeFromRequestBody() {
String expected = "application/json; charset=utf-8";
RequestBody requestBody = RequestBody.create(MediaType.parse(expected),
"{\"foo\":\"bar\"}");
testRequest = new Request.Builder()
.url("http://www.amazon.com")
.post(requestBody)
.header("Content-Type", "THIS SHOULD BE OVERRIDDEN WITH REQUEST BODY CONTENT TYPE")
.build();
underTest = new SignableRequestImpl(testRequest);
assertEquals(expected, underTest.getHeaders().get("Content-Type"));
}
@Test
public void missingRequestBodyDoesNotOverwriteExistingContentTypeHeader() {
String expected = "testContentType";
testRequest = new Request.Builder()
.url("http://www.amazon.com")
.get()
.header("Content-Type", expected)
.build();
underTest = new SignableRequestImpl(testRequest);
assertEquals(expected, underTest.getHeaders().get("Content-Type"));
}
@Test
public void missingRequestBodyContentTypeDoesNotOverwriteExistingContentTypeHeader() {
String expected = "testContentType";
testRequest = new Request.Builder()
.url("http://www.amazon.com")
.post(RequestBody.create(null, "foo"))
.header("Content-Type", expected)
.build();
underTest = new SignableRequestImpl(testRequest);
assertEquals(expected, underTest.getHeaders().get("Content-Type"));
}
}