Auth library updated to support access token reuse and IAM role

This commit is contained in:
Mallampalli 2020-09-23 15:42:38 -07:00
parent 542c2a9b2a
commit f737a56175
14 changed files with 379 additions and 49 deletions

View File

@ -108,6 +108,12 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-sts -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<version>1.11.236</version>
</dependency>
</dependencies>
</project>

View File

@ -529,7 +529,7 @@ public class ApiClient {
this.awsSigV4Signer = awsSigV4Signer;
return this;
}
/**
* Format the given parameter object into string.
*

View File

@ -43,10 +43,13 @@ import java.util.List;
import java.util.Map;
{{/fullJavaUtil}}
import com.amazon.SellingPartnerAPIAA.AWSSigV4Signer;
import com.amazon.SellingPartnerAPIAA.LWAAuthorizationSigner;
import com.amazon.SellingPartnerAPIAA.LWAAuthorizationCredentials;
import com.amazon.SellingPartnerAPIAA.AWSAuthenticationCredentials;
import com.amazon.SellingPartnerAPIAA.AWSAuthenticationCredentialsProvider;
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;
{{#operations}}
public class {{classname}} {
@ -275,6 +278,9 @@ public class {{classname}} {
private AWSAuthenticationCredentials awsAuthenticationCredentials;
private LWAAuthorizationCredentials lwaAuthorizationCredentials;
private String endpoint;
private LWAAccessTokenCache lwaAccessTokenCache;
private Boolean disableAccessTokenCache = false;
private AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider;
public Builder awsAuthenticationCredentials(AWSAuthenticationCredentials awsAuthenticationCredentials) {
this.awsAuthenticationCredentials = awsAuthenticationCredentials;
@ -290,6 +296,22 @@ public class {{classname}} {
this.endpoint = endpoint;
return this;
}
public Builder lwaAccessTokenCache(LWAAccessTokenCache lwaAccessTokenCache) {
this.lwaAccessTokenCache = lwaAccessTokenCache;
return this;
}
public Builder disableAccessTokenCache() {
this.disableAccessTokenCache = true;
return this;
}
public Builder awsAuthenticationCredentialsProvider(AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) {
this.awsAuthenticationCredentialsProvider = awsAuthenticationCredentialsProvider;
return this;
}
public {{classname}} build() {
if (awsAuthenticationCredentials == null) {
@ -304,8 +326,24 @@ public class {{classname}} {
throw new RuntimeException("Endpoint not set");
}
AWSSigV4Signer awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCredentials);
LWAAuthorizationSigner lwaAuthorizationSigner = new LWAAuthorizationSigner(lwaAuthorizationCredentials);
AWSSigV4Signer awsSigV4Signer;
if ( awsAuthenticationCredentialsProvider == null) {
awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCredentials);
}
else {
awsSigV4Signer = new AWSSigV4Signer(awsAuthenticationCredentials,awsAuthenticationCredentialsProvider);
}
LWAAuthorizationSigner lwaAuthorizationSigner = null;
if (disableAccessTokenCache) {
lwaAuthorizationSigner = new LWAAuthorizationSigner(lwaAuthorizationCredentials);
}
else {
if (lwaAccessTokenCache == null) {
lwaAccessTokenCache = new LWAAccessTokenCacheImpl();
}
lwaAuthorizationSigner = new LWAAuthorizationSigner(lwaAuthorizationCredentials,lwaAccessTokenCache);
}
return new {{classname}}(new ApiClient()
.setAWSSigV4Signer(awsSigV4Signer)

View File

@ -0,0 +1,23 @@
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;
}

View File

@ -3,11 +3,15 @@ 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
@ -21,6 +25,10 @@ public class AWSSigV4Signer {
private AWSCredentials awsCredentials;
@Setter(AccessLevel.PACKAGE)
@Getter(AccessLevel.PACKAGE)
private AWSCredentialsProvider awsCredentialsProvider;
/**
*
* @param awsAuthenticationCredentials AWS Developer Account Credentials
@ -33,6 +41,26 @@ public class AWSSigV4Signer {
awsAuthenticationCredentials.getSecretKey());
}
/**
*
* @param awsAuthenticationCredentials and awsAuthenticationCredentialsProvider AWS Developer Account Credentials
*/
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials,
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider) {
aws4Signer = new AWS4Signer();
aws4Signer.setServiceName(SERVICE_NAME);
aws4Signer.setRegionName(awsAuthenticationCredentials.getRegion());
BasicAWSCredentials awsBasicCredentials = new BasicAWSCredentials(awsAuthenticationCredentials.getAccessKeyId(),
awsAuthenticationCredentials.getSecretKey());
awsCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(
awsAuthenticationCredentialsProvider.getRoleArn(),
awsAuthenticationCredentialsProvider.getRoleSessionName())
.withStsClient(AWSSecurityTokenServiceClientBuilder.standard()
.withRegion(awsAuthenticationCredentials.getRegion())
.withCredentials(new AWSStaticCredentialsProvider(awsBasicCredentials)).build())
.build();
}
/**
* Signs a Request with AWS Signature Version 4
*
@ -41,8 +69,11 @@ public class AWSSigV4Signer {
*/
public Request sign(Request originalRequest) {
SignableRequest<Request> signableRequest = new SignableRequestImpl(originalRequest);
aws4Signer.sign(signableRequest, awsCredentials);
if (awsCredentialsProvider != null) {
aws4Signer.sign(signableRequest, awsCredentialsProvider.getCredentials());
} else {
aws4Signer.sign(signableRequest, awsCredentials);
}
return (Request) signableRequest.getOriginalRequestObject();
}
}
}

View File

@ -0,0 +1,6 @@
package com.amazon.SellingPartnerAPIAA;
public interface LWAAccessTokenCache {
String get(Object key);
void put(Object key, String accessToken, long tokenTTLInSeconds);
}

View File

@ -0,0 +1,36 @@
package com.amazon.SellingPartnerAPIAA;
import java.util.concurrent.ConcurrentHashMap;
public class LWAAccessTokenCacheImpl implements LWAAccessTokenCache {
//in milliseconds; to avoid returning a token that would expire before or while a request is made
private long expiryAdjustment = 60 * 1000;
private static final long SECOND_TO_MILLIS = 1000;
private ConcurrentHashMap<Object, Object> accessTokenHashMap =
new ConcurrentHashMap<Object, Object>();
@Override
public void put(Object oLWAAccessTokenRequestMeta, String accessToken, long tokenTTLInSeconds) {
LWAAccessTokenCacheItem accessTokenCacheItem = new LWAAccessTokenCacheItem();
long insertTime = System.currentTimeMillis();
long accessTokenExpiresValueMillis = (tokenTTLInSeconds * SECOND_TO_MILLIS) + insertTime;
accessTokenCacheItem.setAccessToken(accessToken);
accessTokenCacheItem.setAccessTokenExpiredTime(accessTokenExpiresValueMillis);
accessTokenHashMap.put(oLWAAccessTokenRequestMeta, accessTokenCacheItem);
}
@Override
public String get(Object oLWAAccessTokenRequestMeta) {
Object accessTokenValue = accessTokenHashMap.get(oLWAAccessTokenRequestMeta);
if (accessTokenValue != null) {
LWAAccessTokenCacheItem accessTokenData =
(LWAAccessTokenCacheItem) accessTokenValue;
long currentTime = System.currentTimeMillis();
long accessTokenExpiredTime = accessTokenData.getAccessTokenExpiredTime() - expiryAdjustment;
if (currentTime < accessTokenExpiredTime) {
return accessTokenData.getAccessToken();
}
}
return null;
}
}

View File

@ -0,0 +1,11 @@
package com.amazon.SellingPartnerAPIAA;
import lombok.Data;
@Data
class LWAAccessTokenCacheItem {
private String accessToken;
private long accessTokenExpiredTime;
}

View File

@ -10,7 +10,6 @@ import lombok.Setter;
*/
public class LWAAuthorizationSigner {
private static final String SIGNED_ACCESS_TOKEN_HEADER_NAME = "x-amz-access-token";
private final String tokenRequestGrantType;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
@ -18,14 +17,8 @@ public class LWAAuthorizationSigner {
private LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta;
/**
*
* @param lwaAuthorizationCredentials LWA Authorization Credentials for token exchange
*/
public LWAAuthorizationSigner(LWAAuthorizationCredentials lwaAuthorizationCredentials) {
lwaClient = new LWAClient(lwaAuthorizationCredentials.getEndpoint());
private void buildLWAAccessTokenRequestMeta(LWAAuthorizationCredentials lwaAuthorizationCredentials) {
String tokenRequestGrantType;
if (!lwaAuthorizationCredentials.getScopes().isEmpty()) {
tokenRequestGrantType = "client_credentials";
} else {
@ -40,6 +33,33 @@ public class LWAAuthorizationSigner {
.build();
}
/**
*
* @param lwaAuthorizationCredentials LWA Authorization Credentials for token exchange
*/
public LWAAuthorizationSigner(LWAAuthorizationCredentials lwaAuthorizationCredentials) {
lwaClient = new LWAClient(lwaAuthorizationCredentials.getEndpoint());
buildLWAAccessTokenRequestMeta(lwaAuthorizationCredentials);
}
/**
*
* Overloaded Constructor @param lwaAuthorizationCredentials LWA Authorization Credentials for token exchange
* and LWAAccessTokenCache
*/
public LWAAuthorizationSigner(LWAAuthorizationCredentials lwaAuthorizationCredentials,
LWAAccessTokenCache lwaAccessTokenCache) {
lwaClient = new LWAClient(lwaAuthorizationCredentials.getEndpoint());
lwaClient.setLWAAccessTokenCache(lwaAccessTokenCache);
buildLWAAccessTokenRequestMeta(lwaAuthorizationCredentials);
}
/**
* Signs a Request with an LWA Access Token
* @param originalRequest Request to sign (treated as immutable)

View File

@ -16,26 +16,45 @@ import java.io.IOException;
class LWAClient {
private static final String ACCESS_TOKEN_KEY = "access_token";
private static final String ACCESS_TOKEN_EXPIRES_IN = "expires_in";
private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
@Getter
private String endpoint;
@Setter(AccessLevel.PACKAGE)
private OkHttpClient okHttpClient;
private LWAAccessTokenCache lwaAccessTokenCache;
/** Sets cache to store access token until token is expired */
public void setLWAAccessTokenCache(LWAAccessTokenCache tokenCache) {
this.lwaAccessTokenCache = tokenCache;
}
LWAClient(String endpoint) {
okHttpClient = new OkHttpClient();
this.endpoint = endpoint;
}
}
String getAccessToken(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE,
new Gson().toJson(lwaAccessTokenRequestMeta));
Request accessTokenRequest = new Request.Builder()
.url(endpoint)
.post(requestBody)
.build();
if (lwaAccessTokenCache != null) {
return getAccessTokenFromCache(lwaAccessTokenRequestMeta);
} else {
return getAccessTokenFromEndpoint(lwaAccessTokenRequestMeta);
}
}
String getAccessTokenFromCache(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
String accessTokenCacheData = (String) lwaAccessTokenCache.get(lwaAccessTokenRequestMeta);
if (accessTokenCacheData != null) {
return accessTokenCacheData;
} else {
return getAccessTokenFromEndpoint(lwaAccessTokenRequestMeta);
}
}
String getAccessTokenFromEndpoint(LWAAccessTokenRequestMeta lwaAccessTokenRequestMeta) {
RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE, new Gson().toJson(lwaAccessTokenRequestMeta));
Request accessTokenRequest = new Request.Builder().url(endpoint).post(requestBody).build();
String accessToken;
try {
@ -44,15 +63,16 @@ class LWAClient {
throw new IOException("Unsuccessful LWA token exchange");
}
JsonObject responseJson = new JsonParser()
.parse(response.body().string())
.getAsJsonObject();
JsonObject responseJson = new JsonParser().parse(response.body().string()).getAsJsonObject();
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;
}
}
}

View File

@ -3,12 +3,16 @@ 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.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
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;
@ -21,11 +25,18 @@ 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() {
@ -80,4 +91,36 @@ public class AWSSigV4SignerTest {
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());
}
}

View File

@ -1,25 +1,38 @@
package com.amazon.SellingPartnerAPIAA;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.stream.Stream;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_NOTIFICATIONS_API;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_NOTIFICATIONS_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
public class LWAAuthorizationSignerTest {
private static final String TEST_REFRESH_TOKEN = "rToken";
private static final String TEST_CLIENT_SECRET = "cSecret";
@ -29,11 +42,18 @@ public class LWAAuthorizationSignerTest {
private static final String TEST_SCOPE_2 = SCOPE_MIGRATION_API;
private static final String SELLER_TYPE_SELLER = "seller";
private static final String SELLER_TYPE_SELLERLESS = "sellerless";
private static final MediaType EXPECTED_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
private Request request;
private static LWAAuthorizationSigner underTestSeller;
private static LWAAuthorizationSigner underTestSellerless;
@Mock
private OkHttpClient mockOkHttpClient;
@Mock
private Call mockCall;
static {
@ -52,11 +72,12 @@ public class LWAAuthorizationSignerTest {
.build());
}
@BeforeEach
@Before @BeforeEach
public void init() {
request = new Request.Builder()
.url("https://www.amazon.com/api")
.build();
MockitoAnnotations.initMocks(this);
}
@ -78,8 +99,7 @@ public class LWAAuthorizationSignerTest {
@MethodSource("lwaAuthSigner")
public void requestLWAAccessTokenFromConfiguration(String sellerType, LWAAuthorizationSigner testAuthSigner) {
LWAClient mockLWAClient = mock(LWAClient.class);
ArgumentCaptor<LWAAccessTokenRequestMeta> lwaAccessTokenRequestMetaArgumentCaptor = ArgumentCaptor.forClass(
LWAAccessTokenRequestMeta.class);
ArgumentCaptor<LWAAccessTokenRequestMeta> lwaAccessTokenRequestMetaArgumentCaptor = ArgumentCaptor.forClass(LWAAccessTokenRequestMeta.class);
when(mockLWAClient.getAccessToken(lwaAccessTokenRequestMetaArgumentCaptor.capture()))
.thenReturn("foo");
@ -128,4 +148,44 @@ public class LWAAuthorizationSignerTest {
testAuthSigner.setLwaClient(mockLWAClient);
assertNotSame(request, testAuthSigner.sign(request));
}
@Test
public void returnSignedRequestWithAccessTokenFromLWACache() throws IOException {
LWAClient testLWAClient = new LWAClient(TEST_ENDPOINT);
testLWAClient.setOkHttpClient(mockOkHttpClient);
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(200, "Azta|foo", "120"))
.thenReturn(buildResponse(200, "Azta|foo1", "1"));
LWAAccessTokenCache testLWACache = new LWAAccessTokenCacheImpl();
LWAAuthorizationSigner testlwaSigner = new LWAAuthorizationSigner(LWAAuthorizationCredentials.builder()
.clientId(TEST_CLIENT_ID)
.clientSecret(TEST_CLIENT_SECRET)
.refreshToken(TEST_REFRESH_TOKEN)
.endpoint(TEST_ENDPOINT)
.build() , testLWACache );
testlwaSigner.setLwaClient(testLWAClient);
testLWAClient.setLWAAccessTokenCache(testLWACache);
Request actualSignedRequest = testlwaSigner.sign(request);
Request actualSignedSecondRequest = testlwaSigner.sign(request);
assertEquals("Azta|foo", actualSignedSecondRequest.header("x-amz-access-token"));
}
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

@ -12,8 +12,8 @@ import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_NOTIFICATIONS_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
public class LWAClientScopesSerializerDeserializerTest {
private static final String TEST_SCOPE_1 = SCOPE_NOTIFICATIONS_API;

View File

@ -30,13 +30,14 @@ import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_NOTIFICATIONS_API;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_NOTIFICATIONS_API;
import static com.amazon.SellingPartnerAPIAA.ScopeConstants.SCOPE_MIGRATION_API;
@RunWith(MockitoJUnitRunner.class)
public class LWAClientTest {
private static final String TEST_ENDPOINT = "https://www.amazon.com/api";
@ -52,13 +53,13 @@ public class LWAClientTest {
private static final String SELLER_TYPE_SELLER = "seller";
private static final String SELLER_TYPE_SELLERLESS = "sellerless";
@Mock
private OkHttpClient mockOkHttpClient;
@Mock
private Call mockCall;
private LWAClient underTest;
static {
@ -74,17 +75,15 @@ public class LWAClientTest {
.clientSecret("cSecret")
.grantType("cCredentials")
.scopes(new LWAClientScopes(scopesTestSellerless))
.build();
.build();
}
@Before
@BeforeEach
@Before @BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
underTest = new LWAClient(TEST_ENDPOINT);
underTest.setOkHttpClient(mockOkHttpClient);
}
public static Stream<Arguments> lwaClient(){
@ -169,10 +168,43 @@ public class LWAClientTest {
underTest.getAccessToken(testLwaAccessTokenRequestMeta);
});
}
private static Response buildResponse(int code, String accessToken) {
//Test for Access Token getting from cache
@Test
public void returnAccessTokenFromCache() throws IOException, InterruptedException {
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(200, "Azta|foo", "120"))
.thenThrow(IllegalStateException.class);
underTest.setLWAAccessTokenCache(new LWAAccessTokenCacheImpl());
//First call should get from Endpoint
assertEquals("Azta|foo", underTest.getAccessToken(lwaAccessTokenRequestMetaSeller));
//Second call when the cache is still valid, if it goes to end point it will return IllegalStateException.
assertEquals("Azta|foo", underTest.getAccessToken(lwaAccessTokenRequestMetaSeller));
}
@Test
public void returnAccessTokenFromCacheWithExpiry() throws IOException, InterruptedException {
LWAClient client = new LWAClient(TEST_ENDPOINT);
client.setOkHttpClient(mockOkHttpClient);
when(mockOkHttpClient.newCall(any(Request.class)))
.thenReturn(mockCall);
when(mockCall.execute())
.thenReturn(buildResponse(200, "Azta|foo", "1"))
.thenReturn(buildResponse(200, "Azta|foo1", "1"));
//First call should get from Endpoint
assertEquals("Azta|foo", client.getAccessToken(lwaAccessTokenRequestMetaSeller));
//Second call should again go to the endpoint because accesstoken is expired after expiry adjustment.
assertEquals("Azta|foo1", client.getAccessToken(lwaAccessTokenRequestMetaSeller));
}
private static Response buildResponse(int code, String accessToken, String expiryInSeconds) {
ResponseBody responseBody = ResponseBody.create(EXPECTED_MEDIA_TYPE,
String.format("{%s:%s}", "access_token", accessToken));
String.format("{%s:%s,%s:%s}", "access_token", accessToken, "expires_in", expiryInSeconds));
return new Response.Builder()
.request(new Request.Builder().url(TEST_ENDPOINT).build())
@ -182,4 +214,8 @@ public class LWAClientTest {
.message("OK")
.build();
}
private static Response buildResponse(int code, String accessToken) {
return buildResponse(code, accessToken, "3600");
}
}