Skip to content

Commit 922a661

Browse files
feat: add support for AWS_LAMBDA auth mode (#358)
1 parent 0435eb2 commit 922a661

File tree

5 files changed

+74
-5
lines changed

5 files changed

+74
-5
lines changed

aws-android-sdk-appsync/src/main/java/com/amazonaws/mobileconnectors/appsync/AWSAppSyncClient.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.amazonaws.mobileconnectors.appsync.fetcher.AppSyncResponseFetchers;
2020
import com.amazonaws.mobileconnectors.appsync.retry.RetryInterceptor;
2121
import com.amazonaws.mobileconnectors.appsync.sigv4.APIKeyAuthProvider;
22+
import com.amazonaws.mobileconnectors.appsync.sigv4.AWSLambdaAuthProvider;
2223
import com.amazonaws.mobileconnectors.appsync.sigv4.AppSyncSigV4SignerInterceptor;
2324
import com.amazonaws.mobileconnectors.appsync.sigv4.BasicAPIKeyAuthProvider;
2425
import com.amazonaws.mobileconnectors.appsync.sigv4.CognitoUserPoolsAuthProvider;
@@ -105,7 +106,8 @@ private enum AuthMode {
105106
API_KEY("API_KEY"),
106107
AWS_IAM("AWS_IAM"),
107108
AMAZON_COGNITO_USER_POOLS("AMAZON_COGNITO_USER_POOLS"),
108-
OPENID_CONNECT("OPENID_CONNECT");
109+
OPENID_CONNECT("OPENID_CONNECT"),
110+
AWS_LAMBDA("AWS_LAMBDA");
109111

110112
private final String name;
111113

@@ -159,6 +161,8 @@ private AWSAppSyncClient(AWSAppSyncClient.Builder builder) {
159161
appSyncSigV4SignerInterceptor = new AppSyncSigV4SignerInterceptor(builder.mCognitoUserPoolsAuthProvider, builder.mRegion.getName());
160162
} else if (builder.mOidcAuthProvider != null) {
161163
appSyncSigV4SignerInterceptor = new AppSyncSigV4SignerInterceptor(builder.mOidcAuthProvider);
164+
} else if (builder.mAWSLambdaAuthProvider != null) {
165+
appSyncSigV4SignerInterceptor = new AppSyncSigV4SignerInterceptor(builder.mAWSLambdaAuthProvider);
162166
} else if (builder.mApiKey != null) {
163167
appSyncSigV4SignerInterceptor = new AppSyncSigV4SignerInterceptor(builder.mApiKey, builder.mRegion.getName(), getClientSubscriptionUUID(builder.mApiKey.getAPIKey()));
164168
} else {
@@ -309,6 +313,7 @@ public static class Builder {
309313
APIKeyAuthProvider mApiKey;
310314
CognitoUserPoolsAuthProvider mCognitoUserPoolsAuthProvider;
311315
OidcAuthProvider mOidcAuthProvider;
316+
AWSLambdaAuthProvider mAWSLambdaAuthProvider;
312317
NormalizedCacheFactory mNormalizedCacheFactory;
313318
CacheKeyResolver mResolver;
314319
ConflictResolverInterface mConflictResolver;
@@ -365,6 +370,11 @@ public Builder oidcAuthProvider(OidcAuthProvider oidcAuthProvider) {
365370
return this;
366371
}
367372

373+
public Builder awsLamdbaAuthProvider(AWSLambdaAuthProvider awsLambdaAuthProvider) {
374+
mAWSLambdaAuthProvider = awsLambdaAuthProvider;
375+
return this;
376+
}
377+
368378
public Builder serverUrl(String serverUrl) {
369379
mServerUrl = serverUrl;
370380
return this;
@@ -525,6 +535,7 @@ public AWSAppSyncClient build() {
525535
authModeObjects.put(mCredentialsProvider, AuthMode.AWS_IAM);
526536
authModeObjects.put(mCognitoUserPoolsAuthProvider, AuthMode.AMAZON_COGNITO_USER_POOLS);
527537
authModeObjects.put(mOidcAuthProvider, AuthMode.OPENID_CONNECT);
538+
authModeObjects.put(mAWSLambdaAuthProvider, AuthMode.AWS_LAMBDA);
528539
authModeObjects.remove(null);
529540

530541
// Validate if only one Auth object is passed in to the builder

aws-android-sdk-appsync/src/main/java/com/amazonaws/mobileconnectors/appsync/SubscriptionAuthorizer.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.amazonaws.http.HttpMethodName;
1616
import com.amazonaws.mobile.config.AWSConfiguration;
1717
import com.amazonaws.mobileconnectors.appsync.sigv4.APIKeyAuthProvider;
18+
import com.amazonaws.mobileconnectors.appsync.sigv4.AWSLambdaAuthProvider;
1819
import com.amazonaws.mobileconnectors.appsync.sigv4.AppSyncV4Signer;
1920
import com.amazonaws.mobileconnectors.appsync.sigv4.BasicCognitoUserPoolsAuthProvider;
2021
import com.amazonaws.mobileconnectors.appsync.sigv4.CognitoUserPoolsAuthProvider;
@@ -45,6 +46,7 @@ class SubscriptionAuthorizer {
4546
private final OidcAuthProvider mOidcAuthProvider;
4647
private final AWSCredentialsProvider mCredentialsProvider;
4748
private final CognitoUserPoolsAuthProvider mCognitoUserPoolsAuthProvider;
49+
private final AWSLambdaAuthProvider mAWSLambdaAuthProvider;
4850
private final String mServerUrl;
4951
private final APIKeyAuthProvider mApiKeyProvider;
5052

@@ -54,6 +56,7 @@ class SubscriptionAuthorizer {
5456
this.mOidcAuthProvider = builder.mOidcAuthProvider;
5557
this.mCredentialsProvider = builder.mCredentialsProvider;
5658
this.mCognitoUserPoolsAuthProvider = builder.mCognitoUserPoolsAuthProvider;
59+
this.mAWSLambdaAuthProvider = builder.mAWSLambdaAuthProvider;
5760
this.mServerUrl = builder.mServerUrl;
5861
this.mApiKeyProvider = builder.mApiKey;
5962
}
@@ -85,6 +88,8 @@ JSONObject getAuthorizationDetails(boolean connectionFlag,
8588
return getAuthorizationDetailsForUserpools();
8689
case "OPENID_CONNECT" :
8790
return getAuthorizationDetailsForOidc();
91+
case "AWS_LAMBDA" :
92+
return getAuthorizationDetailsForAwsLambda();
8893
default :
8994
throw new RuntimeException("Invalid AuthMode read from awsconfiguration.json.");
9095
}
@@ -197,6 +202,16 @@ private JSONObject getAuthorizationDetailsForOidc() {
197202
}
198203
}
199204

205+
private JSONObject getAuthorizationDetailsForAwsLambda() {
206+
try {
207+
return new JSONObject()
208+
.put("host", getHost(mServerUrl))
209+
.put("Authorization", mAWSLambdaAuthProvider.getLatestAuthToken());
210+
} catch (JSONException | MalformedURLException e) {
211+
throw new RuntimeException("Error constructing authorization message json", e);
212+
}
213+
}
214+
200215
private static String getHost(String apiUrl) throws MalformedURLException {
201216
return new URL(apiUrl).getHost();
202217
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.amazonaws.mobileconnectors.appsync.sigv4;
2+
3+
public interface AWSLambdaAuthProvider {
4+
public String getLatestAuthToken();
5+
}

aws-android-sdk-appsync/src/main/java/com/amazonaws/mobileconnectors/appsync/sigv4/AppSyncSigV4SignerInterceptor.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ public class AppSyncSigV4SignerInterceptor implements Interceptor {
4545

4646
private final CognitoUserPoolsAuthProvider cognitoUserPoolsAuthProvider;
4747
private final OidcAuthProvider oidcAuthProvider;
48+
private final AWSLambdaAuthProvider awsLambdaAuthProvider;
4849
private final String awsRegion;
4950
private final AuthMode authMode;
5051

5152
private enum AuthMode {
5253
API_KEY,
5354
IAM,
5455
OIDC_AUTHORIZATION_TOKEN,
55-
USERPOOLS_AUTHORIZATION_TOKEN
56+
USERPOOLS_AUTHORIZATION_TOKEN,
57+
AWS_LAMBDA_AUTHORIZATION_TOKEN
5658
}
5759

5860
public AppSyncSigV4SignerInterceptor(APIKeyAuthProvider apiKey, final String awsRegion, final String subscriberUUID){
@@ -61,6 +63,7 @@ public AppSyncSigV4SignerInterceptor(APIKeyAuthProvider apiKey, final String aws
6163
this.credentialsProvider = null;
6264
this.cognitoUserPoolsAuthProvider = null;
6365
this.oidcAuthProvider = null;
66+
this.awsLambdaAuthProvider = null;
6467
authMode = AuthMode.API_KEY;
6568
this.subscriberUUID = subscriberUUID;
6669
}
@@ -71,6 +74,7 @@ public AppSyncSigV4SignerInterceptor(AWSCredentialsProvider credentialsProvider,
7174
this.apiKey = null;
7275
this.cognitoUserPoolsAuthProvider = null;
7376
this.oidcAuthProvider = null;
77+
this.awsLambdaAuthProvider = null;
7478
authMode = AuthMode.IAM;
7579
subscriberUUID = null;
7680
}
@@ -81,6 +85,7 @@ public AppSyncSigV4SignerInterceptor(CognitoUserPoolsAuthProvider cognitoUserPoo
8185
this.apiKey = null;
8286
this.cognitoUserPoolsAuthProvider = cognitoUserPoolsAuthProvider;
8387
this.oidcAuthProvider = null;
88+
this.awsLambdaAuthProvider = null;
8489
authMode = AuthMode.USERPOOLS_AUTHORIZATION_TOKEN;
8590
subscriberUUID = null;
8691
}
@@ -91,10 +96,22 @@ public AppSyncSigV4SignerInterceptor(OidcAuthProvider oidcAuthProvider){
9196
this.apiKey = null;
9297
this.cognitoUserPoolsAuthProvider = null;
9398
this.oidcAuthProvider = oidcAuthProvider;
99+
this.awsLambdaAuthProvider = null;
94100
authMode = AuthMode.OIDC_AUTHORIZATION_TOKEN;
95101
subscriberUUID = null;
96102
}
97103

104+
public AppSyncSigV4SignerInterceptor(AWSLambdaAuthProvider awsLambdaAuthProvider) {
105+
this.credentialsProvider = null;
106+
this.awsRegion = null;
107+
this.apiKey = null;
108+
this.cognitoUserPoolsAuthProvider = null;
109+
this.oidcAuthProvider = null;
110+
this.awsLambdaAuthProvider = awsLambdaAuthProvider;
111+
authMode = AuthMode.AWS_LAMBDA_AUTHORIZATION_TOKEN;
112+
subscriberUUID = null;
113+
}
114+
98115
@Override
99116
public Response intercept(Chain chain) throws IOException {
100117
Log.d(TAG, "Signer Interceptor called");
@@ -155,6 +172,13 @@ public Response intercept(Chain chain) throws IOException {
155172
IOException ioe = new IOException("Failed to retrieve OIDC token.", e);
156173
throw ioe;
157174
}
175+
} else if (AuthMode.AWS_LAMBDA_AUTHORIZATION_TOKEN.equals(authMode)) {
176+
try {
177+
dr.addHeader(AUTHORIZATION, awsLambdaAuthProvider.getLatestAuthToken());
178+
} catch (Exception e) {
179+
IOException ioe = new IOException("Failed to retrieve AWS Lambda authorization token.", e);
180+
throw ioe;
181+
}
158182
}
159183

160184
//Copy the signed/credentialed request back into an OKHTTP Request object.

aws-android-sdk-appsync/src/test/java/com/amazonaws/mobileconnectors/appsync/AppSyncClientUnitTest.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.amazonaws.auth.CognitoCredentialsProvider;
77
import com.amazonaws.mobile.config.AWSConfiguration;
88
import com.amazonaws.mobileconnectors.appsync.sigv4.APIKeyAuthProvider;
9+
import com.amazonaws.mobileconnectors.appsync.sigv4.AWSLambdaAuthProvider;
910
import com.amazonaws.mobileconnectors.appsync.sigv4.BasicAPIKeyAuthProvider;
1011
import com.amazonaws.mobileconnectors.appsync.sigv4.BasicCognitoUserPoolsAuthProvider;
1112
import com.amazonaws.mobileconnectors.appsync.sigv4.OidcAuthProvider;
@@ -19,7 +20,6 @@
1920
import com.apollographql.apollo.internal.RealAppSyncCall;
2021
import com.apollographql.apollo.internal.RealAppSyncSubscriptionCall;
2122
import com.apollographql.apollo.internal.subscription.SubscriptionManager;
22-
2323
import org.json.JSONException;
2424
import org.json.JSONObject;
2525
import org.junit.Before;
@@ -29,12 +29,10 @@
2929
import org.robolectric.RobolectricTestRunner;
3030
import org.robolectric.RuntimeEnvironment;
3131
import org.robolectric.annotation.Config;
32-
import org.robolectric.shadows.ShadowApplication;
3332

3433
import java.io.ByteArrayInputStream;
3534
import java.util.concurrent.CountDownLatch;
3635
import java.util.concurrent.TimeUnit;
37-
3836
import javax.annotation.Nonnull;
3937

4038
import static junit.framework.TestCase.assertEquals;
@@ -233,6 +231,22 @@ public String getLatestAuthToken() {
233231
assertNotNull(awsAppSyncClient);
234232
}
235233

234+
@Test
235+
public void testAWSLambdaAuthProvider() {
236+
awsConfiguration.setConfiguration("OpenidConnect");
237+
final AWSAppSyncClient awsAppSyncClient = AWSAppSyncClient.builder()
238+
.context(shadowContext)
239+
.awsConfiguration(awsConfiguration)
240+
.awsLamdbaAuthProvider(new AWSLambdaAuthProvider() {
241+
@Override
242+
public String getLatestAuthToken() {
243+
return "AWS_LAMBDA_AUTHORIZATION_TOKEN";
244+
}
245+
})
246+
.build();
247+
assertNotNull(awsAppSyncClient);
248+
}
249+
236250
@Test
237251
public void testRealAppSyncSubscriptionCallErrorHandling() throws InterruptedException {
238252
RealAppSyncSubscriptionCall<Object> call = new RealAppSyncSubscriptionCall(mockSubscription, mockSubscriptionManager, mockApolloClient, mockLogger, mockSubscriptionMetadataRequest);

0 commit comments

Comments
 (0)