Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth,api): cognito user pools auth provider & auth mode for API HTTP requests #1913

Merged
merged 5 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,15 @@ Future<http.BaseRequest> authorizeHttpRequest(http.BaseRequest request,
return authorizedRequest.httpRequest;
case APIAuthorizationType.function:
case APIAuthorizationType.oidc:
case APIAuthorizationType.userPools:
throw UnimplementedError('${authType.name} not implemented.');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested with OIDC/lambda, but I'm thinking when we register the API auth providers from API plugin instantiation with the auth provider repo which define different way to get token, we can just remove this line here and this part should work with those providers.

case APIAuthorizationType.userPools:
final authProvider = _validateAuthProvider(
authProviderRepo.getAuthProvider(authType.authProviderToken),
authType,
);
final authorizedRequest =
await authProvider.authorizeRequest(_httpToAWSRequest(request));
return authorizedRequest.httpRequest;
case APIAuthorizationType.none:
return request;
}
Expand Down
34 changes: 29 additions & 5 deletions packages/api/amplify_api/test/authorize_http_request_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,19 @@ void main() {
final authProviderRepo = AmplifyAuthProviderRepository();

setUpAll(() {
authProviderRepo.registerAuthProvider(
authProviderRepo
..registerAuthProvider(
APIAuthorizationType.apiKey.authProviderToken,
AppSyncApiKeyAuthProvider());
authProviderRepo.registerAuthProvider(
APIAuthorizationType.iam.authProviderToken, TestIamAuthProvider());
AppSyncApiKeyAuthProvider(),
)
..registerAuthProvider(
APIAuthorizationType.iam.authProviderToken,
TestIamAuthProvider(),
)
..registerAuthProvider(
APIAuthorizationType.userPools.authProviderToken,
TestTokenAuthProvider(),
);
});

group('authorizeHttpRequest', () {
Expand Down Expand Up @@ -132,7 +140,23 @@ void main() {
throwsA(isA<ApiException>()));
});

test('authorizes with Cognito User Pools auth mode', () {}, skip: true);
test('authorizes with Cognito User Pools auth mode', () async {
const endpointConfig = AWSApiConfig(
authorizationType: APIAuthorizationType.userPools,
endpoint: _gqlEndpoint,
endpointType: EndpointType.graphQL,
region: _region);
final inputRequest = _generateTestRequest(endpointConfig.endpoint);
final authorizedRequest = await authorizeHttpRequest(
inputRequest,
endpointConfig: endpointConfig,
authProviderRepo: authProviderRepo,
);
expect(
authorizedRequest.headers[AWSHeaders.authorization],
testAccessToken,
);
});

test('authorizes with OIDC auth mode', () {}, skip: true);

Expand Down
9 changes: 9 additions & 0 deletions packages/api/amplify_api/test/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import 'package:aws_signature_v4/aws_signature_v4.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;

const testAccessToken = 'test-access-token-123';

class TestIamAuthProvider extends AWSIamAmplifyAuthProvider {
@override
Future<AWSCredentials> retrieve() async {
Expand All @@ -43,6 +45,13 @@ class TestIamAuthProvider extends AWSIamAmplifyAuthProvider {
}
}

class TestTokenAuthProvider extends TokenAmplifyAuthProvider {
@override
Future<String> getLatestAuthToken() async {
return testAccessToken;
}
}

void validateSignedRequest(http.BaseRequest request) {
const userAgentHeader =
zIsWeb ? AWSHeaders.amzUserAgent : AWSHeaders.userAgent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import 'package:amplify_auth_cognito_dart/src/sdk/cognito_identity_provider.dart
import 'package:amplify_auth_cognito_dart/src/sdk/sdk_bridge.dart';
import 'package:amplify_auth_cognito_dart/src/state/state.dart';
import 'package:amplify_auth_cognito_dart/src/util/cognito_iam_auth_provider.dart';
import 'package:amplify_auth_cognito_dart/src/util/cognito_user_pools_auth_provider.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart';
import 'package:built_collection/built_collection.dart';
Expand Down Expand Up @@ -180,10 +181,15 @@ class AmplifyAuthCognitoDart extends AuthPluginInterface

// Register auth providers to provide auth functionality to other plugins
// without requiring other plugins to call `Amplify.Auth...` directly.
authProviderRepo.registerAuthProvider(
APIAuthorizationType.iam.authProviderToken,
CognitoIamAuthProvider(),
);
authProviderRepo
..registerAuthProvider(
APIAuthorizationType.iam.authProviderToken,
CognitoIamAuthProvider(),
)
..registerAuthProvider(
APIAuthorizationType.userPools.authProviderToken,
CognitoUserPoolsAuthProvider(),
);

if (_stateMachine.getOrCreate(AuthStateMachine.type).currentState.type !=
AuthStateType.notConfigured) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'dart:async';

import 'package:amplify_auth_cognito_dart/amplify_auth_cognito_dart.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:meta/meta.dart';

/// [AmplifyAuthProvider] implementation that adds access token to request headers.
@internal
class CognitoUserPoolsAuthProvider extends TokenAmplifyAuthProvider {
/// Get access token from `Amplify.Auth.fetchAuthSession()`.
@override
Future<String> getLatestAuthToken() async {
final authSession =
await Amplify.Auth.fetchAuthSession() as CognitoAuthSession;
final token = authSession.userPoolTokens?.accessToken.raw;
if (token == null) {
throw const AuthException(
'Unable to fetch access token while authorizing with Cognito User Pools.',
);
}
return token;
}
}
Loading