diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc24a8d048..44c6094dbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Thank you for your interest in contributing to our project! <3 Whether it's a bu - [Our Design](#our-design) - [Development Process](#development-process) - [Setting up for local development](#setting-up-for-local-development) - - [Packages inside Amplify Flutter](#packages-inside-amplify-flutter) + - [Packages inside Amplify Flutter](#packages-inside-amplify-flutter) - [Steps towards contributions](#steps-towards-contributions) - [Pull Requests](#pull-requests) - [Release](#release) @@ -164,6 +164,7 @@ $ melos run test:unit:flutter ``` or run all unit tests for a given platform + ```bash $ melos run test:unit:android $ melos run test:unit:ios @@ -221,83 +222,6 @@ $ melos run provision_integration_test_resources Note: you will need to have [`jq`](https://github.com/stedolan/jq) installed, which you can install by running `brew install jq`. The provisioning script uses the [Amplify CLI headless mode](https://docs.amplify.aws/cli/usage/headless). -The auth tests require some additional configuration to support lambda triggers for automatically -verifying temporary test users. Note that this should only be done for the test environment, never a production one. This can be done manually by [following this process](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html#aws-lambda-triggers-pre-registration-example-2) or by following these instructions for the amplify CLI: - -``` -$ cd packages/amplify_auth_cognito/example -$ amplify update auth - Please note that certain attributes may not be overwritten if you choose to use defaults settings. - Using service: Cognito, provided by: awscloudformation - What do you want to do? - Walk-through all the auth configurations - Select the authentication/authorization services that you want to use: - User Sign-Up, Sign-In, connected with AWS IAM controls ( Enables per-user Storage features for images or other content, Analytics, and more) - Please enter a name for your identity pool. - authintegrationtest - Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) - No - Do you want to enable 3rd party authentication providers in your identity pool? - No - Do you want to add User Pool Groups? - No - Do you want to add an admin queries API? - No - Multi-factor authentication (MFA) user login options: - OFF - Email based user registration/forgot password: - Enabled (Requires per-user email entry at registration) - Please specify an email verification subject: - Your verification code - Please specify an email verification message: - Your verification code is {####} - Do you want to override the default password policy for this User Pool? - No - Specify the app's refresh token expiration period (in days): - 30 - Do you want to specify the user attributes this app can read and write? - No - Do you want to enable any of the following capabilities? - Do you want to use an OAuth flow? - No - ? Do you want to configure Lambda Triggers for Cognito? - Yes - ? Which triggers do you want to enable for Cognito - Pre Sign-up - ? What functionality do you want to use for Pre Sign-up - Create your own module - Successfully added resource authintegrationtestPreSignup locally. -``` - -When prompted to edit the function now, choose "yes" and add the following code to the `custom.js` file -created by the amplify CLI, from [documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html#aws-lambda-triggers-pre-registration-example-2). - -```js -exports.handler = async event => { - // Confirm the user - event.response.autoConfirmUser = true; - - // Set the email as verified if it is in the request - if (event.request.userAttributes.hasOwnProperty("email")) { - event.response.autoVerifyEmail = true; - } - - // Set the phone number as verified if it is in the request - if (event.request.userAttributes.hasOwnProperty("phone_number")) { - event.response.autoVerifyPhone = true; - } - - // Return to Amazon Cognito - return event; -}; -``` - -Finally, run a push to update the resources with the new function resource (lambda trigger): - -```bash -$ amplify push -``` - Additionally, the storage category requires some manual configuration as the [headless CLI does not yet support storage](https://github.com/aws-amplify/amplify-cli/issues/7378). Those instructions are notes in the [storage example app](packages/amplify_storage_s3/example/README.md). diff --git a/packages/amplify_auth_cognito/example/.gitignore b/packages/amplify_auth_cognito/example/.gitignore index f2544a3f90..218082d361 100644 --- a/packages/amplify_auth_cognito/example/.gitignore +++ b/packages/amplify_auth_cognito/example/.gitignore @@ -8,6 +8,7 @@ .buildlog/ .history .svn/ +**/adminCreateUser.zip # IntelliJ related *.iml @@ -49,7 +50,6 @@ amplify/.config/local-* amplify/logs amplify/mock-data amplify/backend/amplify-meta.json -amplify/backend/awscloudformation amplify/backend/.temp build/ dist/ diff --git a/packages/amplify_auth_cognito/example/integration_test/delete_user_test.dart b/packages/amplify_auth_cognito/example/integration_test/delete_user_test.dart index ca3a5be032..c22f14499c 100644 --- a/packages/amplify_auth_cognito/example/integration_test/delete_user_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/delete_user_test.dart @@ -107,6 +107,12 @@ void main() { }, skip: !Platform.isIOS); group('deleteUser (Android)', () { + setUpAll(() async { + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); + await signOutUser(); + }); testWidgets('should throw an UnimplementedError on Android', (WidgetTester tester) async { try { diff --git a/packages/amplify_auth_cognito/example/integration_test/fetch_session_test.dart b/packages/amplify_auth_cognito/example/integration_test/fetch_session_test.dart index d0e8b362fe..475f08df61 100644 --- a/packages/amplify_auth_cognito/example/integration_test/fetch_session_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/fetch_session_test.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_test/amplify_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -30,16 +32,17 @@ void main() { group('fetchSession', () { setUpAll(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); - // create one user for all tests - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - CognitoUserAttributeKey.email: generateEmail(), - CognitoUserAttributeKey.phoneNumber: mockPhoneNumber - })); + // create one confirmed user for all tests + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + ); }); // sign in prior to each test @@ -78,7 +81,7 @@ void main() { testWidgets('should return isSignedIn as false if the user is signed out', (WidgetTester tester) async { await Amplify.Auth.signOut(); - var res = await Amplify.Auth.fetchAuthSession() as CognitoAuthSession; + var res = await Amplify.Auth.fetchAuthSession(); expect(res.isSignedIn, isFalse); }); }); diff --git a/packages/amplify_auth_cognito/example/integration_test/get_current_user_test.dart b/packages/amplify_auth_cognito/example/integration_test/get_current_user_test.dart index a8ede0d59c..31c55fa3c8 100644 --- a/packages/amplify_auth_cognito/example/integration_test/get_current_user_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/get_current_user_test.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_test/amplify_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -30,16 +32,17 @@ void main() { group('getCurrentUser', () { setUpAll(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); // create one user for all tests - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - CognitoUserAttributeKey.email: generateEmail(), - CognitoUserAttributeKey.phoneNumber: mockPhoneNumber - })); + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + ); }); // sign in prior to each test diff --git a/packages/amplify_auth_cognito/example/integration_test/hub_events_test.dart b/packages/amplify_auth_cognito/example/integration_test/hub_events_test.dart index cbc8e149e8..6ecb0f06b9 100644 --- a/packages/amplify_auth_cognito/example/integration_test/hub_events_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/hub_events_test.dart @@ -94,33 +94,37 @@ void main() { 'should broadcast events for deleteUser', (WidgetTester tester) async { // setup - var nextEvent; + var signinEvent; + var deleteEvent; + var signoutEvent; var event; var eventCount = 0; var authEventStream = Amplify.Hub.availableStreams[HubChannel.Auth]!; authEventStream.listen((event) => eventCount++); // assert sign in event is broadcast - nextEvent = authEventStream.first; + signinEvent = + authEventStream.firstWhere((el) => el.eventName == 'SIGNED_IN'); + deleteEvent = + authEventStream.firstWhere((el) => el.eventName == 'USER_DELETED'); + signoutEvent = + authEventStream.firstWhere((el) => el.eventName == 'SIGNED_OUT'); + await Amplify.Auth.signIn( username: username, password: password, ); - event = await nextEvent; - expect(event.eventName, 'SIGNED_IN'); + var event1 = await signinEvent; + expect(event1.eventName, 'SIGNED_IN'); // assert signed out event is broadcast - nextEvent = authEventStream.first; await Amplify.Auth.deleteUser(); - event = await nextEvent; - expect(event.eventName, 'SIGNED_OUT'); + var event2 = await signoutEvent; + var event3 = await deleteEvent; + expect(event2.eventName, 'SIGNED_OUT'); - // assert delete user event is broadcast - nextEvent = authEventStream.first; - event = await nextEvent; - expect(event.eventName, 'USER_DELETED'); + expect(event3.eventName, 'USER_DELETED'); - // assert 3 total events are broadcast expect(eventCount, 3); }, skip: !Platform.isIOS, diff --git a/packages/amplify_auth_cognito/example/integration_test/main_test.dart b/packages/amplify_auth_cognito/example/integration_test/main_test.dart index 20d2c95ad3..1901605136 100644 --- a/packages/amplify_auth_cognito/example/integration_test/main_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/main_test.dart @@ -32,12 +32,6 @@ void main() async { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('amplify_auth_cognito', () { - setUpAll(() async { - final authPlugin = AmplifyAuthCognito(); - await Amplify.addPlugins([authPlugin]); - await Amplify.configure(amplifyconfig); - }); - sign_in_sign_out_tests.main(); sign_up_tests.main(); user_attributes_tests.main(); diff --git a/packages/amplify_auth_cognito/example/integration_test/sign_in_sign_out_test.dart b/packages/amplify_auth_cognito/example/integration_test/sign_in_sign_out_test.dart index bf1561073b..4526e0b1ec 100644 --- a/packages/amplify_auth_cognito/example/integration_test/sign_in_sign_out_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/sign_in_sign_out_test.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_test/amplify_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -23,24 +25,24 @@ import 'utils/setup_utils.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - + late String username; + late String password; group('signIn', () { - late String username; - late String password; setUp(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); // create new user for each test username = generateUsername(); password = generatePassword(); - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - CognitoUserAttributeKey.email: generateEmail(), - CognitoUserAttributeKey.phoneNumber: mockPhoneNumber - })); + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + ); await signOutUser(); }); @@ -99,17 +101,6 @@ void main() { }); testWidgets('should sign a user out', (WidgetTester tester) async { - // sign up user - final username = generateUsername(); - final password = generatePassword(); - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - CognitoUserAttributeKey.email: generateEmail(), - CognitoUserAttributeKey.phoneNumber: mockPhoneNumber - })); - // Ensure signed in before testing signOut. await Amplify.Auth.signIn(username: username, password: password); final authSession = await Amplify.Auth.fetchAuthSession(); diff --git a/packages/amplify_auth_cognito/example/integration_test/sign_up_test.dart b/packages/amplify_auth_cognito/example/integration_test/sign_up_test.dart index edd406fbd2..4696a4f16d 100644 --- a/packages/amplify_auth_cognito/example/integration_test/sign_up_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/sign_up_test.dart @@ -13,6 +13,7 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -26,7 +27,9 @@ void main() { group('signUp', () { setUpAll(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); await signOutUser(); }); diff --git a/packages/amplify_auth_cognito/example/integration_test/update_password_test.dart b/packages/amplify_auth_cognito/example/integration_test/update_password_test.dart index 50fe7bb0a9..7aea8053e7 100644 --- a/packages/amplify_auth_cognito/example/integration_test/update_password_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/update_password_test.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_test/amplify_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -29,20 +31,21 @@ void main() { group('updatePassword', () { setUpAll(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); }); setUp(() async { // create new user for each test username = generateUsername(); password = generatePassword(); - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - CognitoUserAttributeKey.email: generateEmail(), - CognitoUserAttributeKey.phoneNumber: mockPhoneNumber - })); + await adminCreateUser( + username, + password, + autoConfirm: true, + verifyAttributes: true, + ); await signOutUser(); // sign in with current password diff --git a/packages/amplify_auth_cognito/example/integration_test/user_attributes_test.dart b/packages/amplify_auth_cognito/example/integration_test/user_attributes_test.dart index b83d2d6de5..a101d4839c 100644 --- a/packages/amplify_auth_cognito/example/integration_test/user_attributes_test.dart +++ b/packages/amplify_auth_cognito/example/integration_test/user_attributes_test.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_test/amplify_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; @@ -46,16 +48,22 @@ void main() { group('User Attributes', () { setUpAll(() async { - await configureAuth(); + await configureAuth(additionalPlugins: [ + AmplifyAPI(), + ]); await signOutUser(); - await Amplify.Auth.signUp( - username: username, - password: password, - options: CognitoSignUpOptions(userAttributes: { - emailAttributeKey: email, - phoneNumberAttributeKey: phoneNumber, - nameAttributeKey: name - })); + await adminCreateUser(username, password, + autoConfirm: true, + verifyAttributes: true, + attributes: [ + AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.name, value: name), + AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.email, value: email), + AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.phoneNumber, + value: mockPhoneNumber) + ]); await Amplify.Auth.signIn(username: username, password: password); }); diff --git a/packages/amplify_auth_cognito/example/tool/add_api_request.json b/packages/amplify_auth_cognito/example/tool/add_api_request.json new file mode 100644 index 0000000000..a91b243b35 --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/add_api_request.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "serviceConfiguration": { + "serviceName": "AppSync", + "apiName": "apiIntegrationTestGraphQL", + "transformSchema": "", + "defaultAuthType": { + "mode": "API_KEY", + "expirationTime": 365 + } + } + } + \ No newline at end of file diff --git a/packages/amplify_auth_cognito/example/tool/add_auth_request.json b/packages/amplify_auth_cognito/example/tool/add_auth_request.json index 5f2b41346b..acf118d6fa 100644 --- a/packages/amplify_auth_cognito/example/tool/add_auth_request.json +++ b/packages/amplify_auth_cognito/example/tool/add_auth_request.json @@ -7,6 +7,6 @@ "signinMethod": "USERNAME", "requiredSignupAttributes": ["EMAIL", "PHONE_NUMBER"] }, - "includeIdentityPool": false + "includeIdentityPool": true } } diff --git a/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/cloudformation.json b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/cloudformation.json new file mode 100644 index 0000000000..43036ffced --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/cloudformation.json @@ -0,0 +1,255 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Parameters": { + "CloudWatchRule": { + "Type": "String", + "Default": "NONE", + "Description": " Schedule Expression" + }, + "deploymentBucketName": { + "Type": "String" + }, + "env": { + "Type": "String" + }, + "s3Key": { + "Type": "String" + }, + "stackId": { + "Type": "String" + }, + "authauthintegrationtestUserPoolId": { + "Type": "String", + "Default": "authauthintegrationtestUserPoolId" + } + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, + "Resources": { + "LambdaFunction": { + "Type": "AWS::Lambda::Function", + "Metadata": { + "aws:asset:path": "./src", + "aws:asset:property": "Code" + }, + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "deploymentBucketName" + }, + "S3Key": { + "Ref": "s3Key" + } + }, + "Handler": "index.handler", + "FunctionName": { + "Fn::Join": [ + "", + [ + "amplifyintegrationtestAdminCreateUser", + "-", + { + "Ref": "env" + } + ] + ] + }, + "Environment": { + "Variables": { + "ENV": { + "Ref": "env" + }, + "REGION": { + "Ref": "AWS::Region" + }, + "AUTH_USERPOOLID": { + "Ref": "authauthintegrationtestUserPoolId" + } + } + }, + "Role": { + "Fn::GetAtt": [ + "LambdaExecutionRole", + "Arn" + ] + }, + "Runtime": "nodejs14.x", + "Layers": [], + "Timeout": 25 + } + }, + "LambdaExecutionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "amplifyauthintegLambdaRoleAdminCreateUser", + { + "Fn::Join": [ + "", + [ + "amplifyauthintegLambdaRole", + { + "Ref": "stackId" + }, + "-", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + } + } + }, + "lambdaexecutionpolicy": { + "DependsOn": [ + "LambdaExecutionRole" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "lambda-execution-policy", + "Roles": [ + { + "Ref": "LambdaExecutionRole" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": { + "Fn::Sub": [ + "arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*", + { + "region": { + "Ref": "AWS::Region" + }, + "account": { + "Ref": "AWS::AccountId" + }, + "lambda": { + "Ref": "LambdaFunction" + } + } + ] + } + } + ] + } + } + }, + "AmplifyResourcesPolicy": { + "DependsOn": [ + "LambdaExecutionRole" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "amplify-lambda-execution-policy", + "Roles": [ + { + "Ref": "LambdaExecutionRole" + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "cognito-idp:AdminCreateUser", + "cognito-idp:AdminSetUserSettings", + "cognito-idp:AdminConfirmSignUp", + "cognito-idp:AdminSetUserPassword", + "cognito-idp:AdminEnableUser", + "cognito-idp:AdminUpdateDeviceStatus", + "cognito-idp:AdminSetUserMFAPreference", + "cognito-idp:AdminResetUserPassword", + "cognito-idp:AdminUpdateUserAttributes", + "cognito-idp:AdminUpdateAuthEventFeedback" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:cognito-idp:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":userpool/", + { + "Ref": "authauthintegrationtestUserPoolId" + } + ] + ] + } + ] + } + ] + } + } + } + }, + "Outputs": { + "Name": { + "Value": { + "Ref": "LambdaFunction" + } + }, + "Arn": { + "Value": { + "Fn::GetAtt": [ + "LambdaFunction", + "Arn" + ] + } + }, + "Region": { + "Value": { + "Ref": "AWS::Region" + } + }, + "LambdaExecutionRole": { + "Value": { + "Ref": "LambdaExecutionRole" + } + } + } + } diff --git a/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/event.json b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/event.json new file mode 100644 index 0000000000..fd2722e859 --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/event.json @@ -0,0 +1,5 @@ +{ + "key1": "value1", + "key2": "value2", + "key3": "value3" +} diff --git a/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/index.js b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/index.js new file mode 100644 index 0000000000..06343d0fbc --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/index.js @@ -0,0 +1,90 @@ +/* Amplify Params - DO NOT EDIT + AUTH_USERPOOLID + ENV + REGION +Amplify Params - DO NOT EDIT */ +var aws = require('aws-sdk'); +var cognitoidentityserviceprovider = new aws.CognitoIdentityServiceProvider({ + "region": process.env.REGION, +}); + +exports.handler = async (event) => { + var response = {success: false } + var baseParams = { + UserPoolId: process.env.AUTH_USERPOOLID, + Username: event.arguments.Username + } + + var createUserParams = Object.assign({ + TemporaryPassword: event.arguments.Password + }, baseParams); + + var attributes = []; + + for (const [k, v] of Object.entries(event.arguments)) { + if (['Given_Name','Name', 'Email', 'Phone_Number'].includes(k)) { + attributes.push({"Name": k.toLowerCase(), "Value": v}) + } + } + + if (attributes.length > 0) { + createUserParams["UserAttributes"] = attributes + } + + + await cognitoidentityserviceprovider.adminCreateUser(createUserParams).promise().catch(function(err) { + response['error'] = err.toString(); + return response; + }); + + if (event.arguments.AutoConfirm) { + var passwordParams = Object.assign({ + Password: event.arguments.Password, + Permanent: true, + }, baseParams); + + await cognitoidentityserviceprovider.adminSetUserPassword(passwordParams).promise().catch(function(err) { + response['error'] = err.toString(); + return response; + }) + } + + if (event.arguments.EnableMFA) { + var mfaParams = Object.assign({ + MFAOptions: [ + { + AttributeName: 'phone_number', + DeliveryMedium: 'SMS' + } + ] + }, baseParams); + + await cognitoidentityserviceprovider.adminSetUserSettings(mfaParams).promise().then().catch(function(err) { + response['error'] = err.toString(); + return response; + }) + } + + if (event.arguments.VerifyAttributes) { + var verifyParams = Object.assign({ + UserAttributes: [ + { + Name: 'phone_number_verified', + Value: 'true' + }, + { + Name: 'email_verified', + Value: 'true' + } + ] + }, baseParams); + + await cognitoidentityserviceprovider.adminUpdateUserAttributes(verifyParams).promise().then().catch(function(err) { + response['error'] = err.toString(); + return response; + }) + } + + response['success'] = true; + return response; +}; diff --git a/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/package.json b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/package.json new file mode 100644 index 0000000000..9b6f74fb05 --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/adminCreateUserLambda/src/package.json @@ -0,0 +1,7 @@ +{ + "name": "amplifyintegrationtestAdminCreateUser", + "version": "2.0.0", + "description": "Lambda function generated by Amplify", + "main": "index.js", + "license": "Apache-2.0" +} diff --git a/packages/amplify_auth_cognito/example/tool/provision_integration_test_resources.sh b/packages/amplify_auth_cognito/example/tool/provision_integration_test_resources.sh index b8cae5365f..cb23510867 100755 --- a/packages/amplify_auth_cognito/example/tool/provision_integration_test_resources.sh +++ b/packages/amplify_auth_cognito/example/tool/provision_integration_test_resources.sh @@ -2,6 +2,8 @@ set -e IFS='|' +[ "$AWS_PROFILE" ] && profileName="$AWS_PROFILE" || profileName="default"; + FLUTTERCONFIG="{\ \"ResDir\":\"./lib/\",\ }" @@ -17,9 +19,76 @@ FRONTEND="{\ \"config\":$FLUTTERCONFIG\ }" +AWSCLOUDFORMATIONCONFIG="{\ +\"configLevel\":\"project\",\ +\"useProfile\":"true",\ +\"profileName\":\"$profileName\",\ +\"region\":\"us-west-2\"\ +}" +PROVIDERS="{\ +\"awscloudformation\":$AWSCLOUDFORMATIONCONFIG\ +}" + +# read the request template and the schema +requestTemplate=`cat tool/add_api_request.json` +schema=`cat tool/schema.graphql` + +# escape quotes and remove new lines from schema +schema=${schema//$'"'/'\"'} +schema=${schema//$'\n'/} + +# create the request with the actual schema +request="${requestTemplate//$schema}" + amplify init \ --amplify $AMPLIFY \ --frontend $FRONTEND \ +--providers $PROVIDERS \ --yes cat tool/add_auth_request.json | jq -c | amplify add auth --headless amplify push --yes + +# get the deployment bucket to use as destination for lambda code +deploymentBucket=($(jq -r '.test.awscloudformation.DeploymentBucketName' ./amplify/team-provider-info.json)) +s3Key=amplify-builds/adminCreateUser.zip +userpoolId=($(jq -r '.auth.authintegrationtest.output.UserPoolId' ./amplify/backend/amplify-meta.json)) +stackId=($(jq -r '.test.awscloudformation.StackName' ./amplify/team-provider-info.json)) +stackId=$(echo "$stackId" | sed 's/.*-//' ) + +# check for old stacks/roles +{ + echo "attempting to delete admin-create-user-stack" + aws cloudformation delete-stack --profile=$profileName --stack-name admin-create-user-stack + aws cloudformation wait stack-delete-complete --profile=$profileName --stack-name admin-create-user-stack +} || { + echo "admin-create-user-stack does not exist or could not be deleted." + echo "We will attempt to create the stack." +} + +{ + echo "attempting to delete amplifyauthintegLambdaRoleAdminCreateUser IAM role" + aws iam delete-role --profile=$profileName --role-name amplifyauthintegLambdaRole${appId}-test +} || { + echo "amplifyauthintegLambdaRoleAdminCreateUser does not exist or could not be deleted." + echo "We will attempt to create the role." +} + +# create zip of lambda code from source +cd tool/adminCreateUserLambda/src +zip -r ../adminCreateUser.zip * +cd ../../.. + +# put lambda code into bucket +echo "adding lambda code to S3..." +aws s3api put-object --profile=$profileName --bucket $deploymentBucket --key $s3Key --body ./tool/adminCreateUserLambda/adminCreateUser.zip + +# remove zip file +rm ./tool/adminCreateUserLambda/adminCreateUser.zip + +# create lambda function for adminCreateUser +echo "creating lambda with cloudformation..." +aws cloudformation deploy --profile=$profileName --template-file ./tool/adminCreateUserLambda/cloudformation.json --stack-name admin-create-user-stack --parameter-overrides deploymentBucketName=$deploymentBucket s3Key=$s3Key env=test authauthintegrationtestUserPoolId=$userpoolId stackId=$stackId --capabilities CAPABILITY_NAMED_IAM + +# create api (which uses lambda in mutation) +echo "$request" | jq -c | amplify add api --headless +amplify push --yes diff --git a/packages/amplify_auth_cognito/example/tool/schema.graphql b/packages/amplify_auth_cognito/example/tool/schema.graphql new file mode 100644 index 0000000000..f221c5b47c --- /dev/null +++ b/packages/amplify_auth_cognito/example/tool/schema.graphql @@ -0,0 +1,19 @@ +type Mutation { + adminCreateUser( + Username: String! + Password: String! + AutoConfirm: Boolean + EnableMFA: Boolean + VerifyAttributes: Boolean + Email: String + Phone_Number: String + Name: String + Given_Name: String + ): CreateUserResponse + @function(name: "amplifyintegrationtestAdminCreateUser-${env}") +} + +type CreateUserResponse @model { + success: Boolean! + error: String +} diff --git a/packages/amplify_test/lib/src/integration_test_utils/auth_cognito/integration_test_auth_utils.dart b/packages/amplify_test/lib/src/integration_test_utils/auth_cognito/integration_test_auth_utils.dart index 442cb4a92d..8e967e7adf 100644 --- a/packages/amplify_test/lib/src/integration_test_utils/auth_cognito/integration_test_auth_utils.dart +++ b/packages/amplify_test/lib/src/integration_test_utils/auth_cognito/integration_test_auth_utils.dart @@ -16,7 +16,9 @@ import 'dart:async'; import 'dart:convert'; import 'package:amplify_api/amplify_api.dart'; +import 'package:amplify_auth_cognito/amplify_auth_cognito.dart'; import 'package:amplify_flutter/amplify_flutter.dart'; +// ignore: depend_on_referenced_packages import 'package:flutter_test/flutter_test.dart'; import 'package:stream_transform/stream_transform.dart'; @@ -35,8 +37,8 @@ const deleteDocument = '''mutation DeleteUser(\$Username: String!) { /// A GraphQL document used by the [adminCreateUser] test utility method. const adminCreateUserDocument = - '''mutation CreateUser(\$Username: String!, \$Password: String!, \$AutoConfirm: Boolean!, \$EnableMFA: Boolean!, \$VerifyAttributes: Boolean!) { - adminCreateUser(Username: \$Username, Password: \$Password, AutoConfirm: \$AutoConfirm, EnableMFA: \$EnableMFA, VerifyAttributes: \$VerifyAttributes) { + '''mutation CreateUser(\$Username: String!, \$Password: String!, \$AutoConfirm: Boolean!, \$EnableMFA: Boolean!, \$VerifyAttributes: Boolean!, \$Name: String, \$Given_Name: String, \$Email: String, \$Phone_Number: String) { + adminCreateUser(Username: \$Username, Password: \$Password, AutoConfirm: \$AutoConfirm, EnableMFA: \$EnableMFA, VerifyAttributes: \$VerifyAttributes, Given_Name: \$Given_Name, Name: \$Name, Email: \$Email, Phone_Number: \$Phone_Number) { error success } @@ -74,11 +76,15 @@ Future deleteUser(String username) async { /// The [enableMFA] flag will opt-in the user to using SMS MFA. /// The [verifyAttributes] flag will verify the email and phone, and should be used /// if tests need to bypass the verification step. +/// The [attributes] list passes additional attributes. Future adminCreateUser( - String username, String password, - {bool autoConfirm = false, - bool enableMfa = false, - bool verifyAttributes = false}) async { + String username, + String password, { + bool autoConfirm = false, + bool enableMfa = false, + bool verifyAttributes = false, + List attributes = const [], +}) async { var res = await Amplify.API .mutate( request: GraphQLRequest( @@ -88,6 +94,39 @@ Future adminCreateUser( 'Password': password, 'AutoConfirm': autoConfirm, 'EnableMFA': enableMfa, + 'Name': attributes + .firstWhere( + (el) => el.userAttributeKey == CognitoUserAttributeKey.name, + orElse: () => const AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.name, + value: 'default_name')) + .value, + 'Given_Name': attributes + .firstWhere( + (el) => + el.userAttributeKey == + CognitoUserAttributeKey.givenName, + orElse: () => const AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.givenName, + value: 'default_given_name')) + .value, + 'Email': attributes + .firstWhere( + (el) => + el.userAttributeKey == CognitoUserAttributeKey.email, + orElse: () => const AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.email, + value: 'example@example.com')) + .value, + 'Phone_Number': attributes + .firstWhere( + (el) => + el.userAttributeKey == + CognitoUserAttributeKey.phoneNumber, + orElse: () => const AuthUserAttribute( + userAttributeKey: CognitoUserAttributeKey.phoneNumber, + value: '+15555555')) + .value, 'VerifyAttributes': verifyAttributes, })) .response; diff --git a/packages/amplify_test/pubspec.yaml b/packages/amplify_test/pubspec.yaml index 6648fdda9f..a8d11a8c30 100644 --- a/packages/amplify_test/pubspec.yaml +++ b/packages/amplify_test/pubspec.yaml @@ -12,8 +12,9 @@ dependencies: path: ../amplify_core flutter: sdk: flutter - amplify_api: ^0.3.1 - amplify_flutter: ^0.3.1 + amplify_api: ^0.4.0 + amplify_auth_cognito: ^0.4.0 + amplify_flutter: ^0.4.0 stream_transform: ^2.0.0 dev_dependencies: