From 6a3ab3b2c742ebe96c97b23f715a7a5b6a69548c Mon Sep 17 00:00:00 2001 From: Rachel Hagerman <110480692+rlhagerm@users.noreply.github.com> Date: Wed, 30 Aug 2023 09:28:06 -0500 Subject: [PATCH] .NET v3: Updates and fixes to Cognito MVP. (#5336) * Updates and fixes to Cognito MVP. * Updating logic. --- .../cognito-identity-provider_metadata.yaml | 11 --- dotnetv3/Cognito/Actions/CognitoWrapper.cs | 73 +++++++++---------- dotnetv3/Cognito/README.md | 51 ++++++++----- .../Scenarios/Cognito_Basics/CognitoBasics.cs | 44 ++++++----- .../Scenarios/Cognito_Basics/UIMethods.cs | 12 +-- .../Scenarios/Cognito_Basics/settings.json | 13 ++-- .../package-lock.json | 1 + 7 files changed, 105 insertions(+), 100 deletions(-) diff --git a/.doc_gen/metadata/cognito-identity-provider_metadata.yaml b/.doc_gen/metadata/cognito-identity-provider_metadata.yaml index d4cfbd5dff3..759325d531f 100644 --- a/.doc_gen/metadata/cognito-identity-provider_metadata.yaml +++ b/.doc_gen/metadata/cognito-identity-provider_metadata.yaml @@ -697,15 +697,6 @@ cognito-identity-provider_RespondToAuthChallenge: synopsis: respond to &COG; SRP authentication challenges. category: languages: - .NET: - versions: - - sdk_version: 3 - github: dotnetv3/Cognito - sdkguide: - excerpts: - - description: - snippet_tags: - - Cognito.dotnetv3.RespondToAuthChallenge Python: versions: - sdk_version: 3 @@ -764,10 +755,8 @@ cognito-identity-provider_Scenario_SignUpUserWithMfa: excerpts: - description: snippet_tags: - - Cognito.dotnetv3.Usings - Cognito.dotnetv3.Main - Cognito.dotnetv3.CognitoWrapper - - Cognito.dotnetv3.UIMethods Kotlin: versions: - sdk_version: 1 diff --git a/dotnetv3/Cognito/Actions/CognitoWrapper.cs b/dotnetv3/Cognito/Actions/CognitoWrapper.cs index c75f4b48932..348cb90766a 100644 --- a/dotnetv3/Cognito/Actions/CognitoWrapper.cs +++ b/dotnetv3/Cognito/Actions/CognitoWrapper.cs @@ -47,7 +47,7 @@ public async Task> ListUserPoolsAsync() /// /// Get a list of users for the Amazon Cognito user pool. /// - /// The user pool Id. + /// The user pool ID. /// A list of users. public async Task> ListUsersAsync(string userPoolId) { @@ -70,36 +70,21 @@ public async Task> ListUsersAsync(string userPoolId) // snippet-end:[Cognito.dotnetv3.ListUsers] // snippet-start:[Cognito.dotnetv3.AdminRespondToAuthChallenge] - public async Task AdminRespondToAuthChallengeAsync(string userPoolId, string userName, string clientId, string mfaCode, string session) - { - var challengeResponses = new Dictionary(); - challengeResponses.Add("USERNAME", userName); - challengeResponses.Add("SOFTWARE_TOKEN_MFA_CODE", mfaCode); - - var request = new AdminRespondToAuthChallengeRequest - { - ClientId = clientId, - UserPoolId = userPoolId, - ChallengeResponses = challengeResponses, - Session = session - }; - - var response = await _cognitoService.AdminRespondToAuthChallengeAsync(request); - return response.AuthenticationResult; - } - - // snippet-end:[Cognito.dotnetv3.AdminRespondToAuthChallenge] - - // snippet-start:[Cognito.dotnetv3.RespondToAuthChallenge] /// - /// Respond to an authentication challenge. + /// Respond to an admin authentication challenge. /// /// The name of the user. - /// The client Id. + /// The client ID. /// The multi-factor authentication code. /// The current application session. - /// An async Task. - public async Task RespondToAuthChallengeAsync(string userName, string clientId, string mfaCode, string session) + /// The user pool ID. + /// The result of the authentication response. + public async Task AdminRespondToAuthChallengeAsync( + string userName, + string clientId, + string mfaCode, + string session, + string userPoolId) { Console.WriteLine("SOFTWARE_TOKEN_MFA challenge is generated"); @@ -107,20 +92,21 @@ public async Task RespondToAuthChallengeAsync(string u challengeResponses.Add("USERNAME", userName); challengeResponses.Add("SOFTWARE_TOKEN_MFA_CODE", mfaCode); - var respondToAuthChallengeRequest = new RespondToAuthChallengeRequest + var respondToAuthChallengeRequest = new AdminRespondToAuthChallengeRequest { ChallengeName = ChallengeNameType.SOFTWARE_TOKEN_MFA, ClientId = clientId, ChallengeResponses = challengeResponses, - Session = session + Session = session, + UserPoolId = userPoolId, }; - var response = await _cognitoService.RespondToAuthChallengeAsync(respondToAuthChallengeRequest); - Console.WriteLine($"Response to Authentication {response.AuthenticationResult}"); + var response = await _cognitoService.AdminRespondToAuthChallengeAsync(respondToAuthChallengeRequest); + Console.WriteLine($"Response to Authentication {response.AuthenticationResult.TokenType}"); return response.AuthenticationResult; } - // snippet-end:[Cognito.dotnetv3.RespondToAuthChallenge] + // snippet-end:[Cognito.dotnetv3.AdminRespondToAuthChallenge] // snippet-start:[Cognito.dotnetv3.VerifySoftwareToken] /// @@ -149,7 +135,7 @@ public async Task VerifySoftwareTokenAsync(stri /// Get an MFA token to authenticate the user with the authenticator. /// /// The session name. - /// Returns the session name. + /// The session name. public async Task AssociateSoftwareTokenAsync(string session) { var softwareTokenRequest = new AssociateSoftwareTokenRequest @@ -160,7 +146,7 @@ public async Task AssociateSoftwareTokenAsync(string session) var tokenResponse = await _cognitoService.AssociateSoftwareTokenAsync(softwareTokenRequest); var secretCode = tokenResponse.SecretCode; - Console.Write("Enter the following token into the authenticator: {secretCode}"); + Console.WriteLine($"Use the following secret code to set up the authenticator: {secretCode}"); return tokenResponse.Session; } @@ -168,6 +154,14 @@ public async Task AssociateSoftwareTokenAsync(string session) // snippet-end:[Cognito.dotnetv3.AssociateSoftwareToken] // snippet-start:[Cognito.dotnetv3.AdminInitiateAuth] + /// + /// Initiate an admin auth request. + /// + /// The client ID to use. + /// The ID of the user pool. + /// The username to authenticate. + /// The user's password. + /// The session to use in challenge-response. public async Task AdminInitiateAuthAsync(string clientId, string userPoolId, string userName, string password) { var authParameters = new Dictionary(); @@ -179,7 +173,7 @@ public async Task AdminInitiateAuthAsync(string clientId, string userPoo ClientId = clientId, UserPoolId = userPoolId, AuthParameters = authParameters, - AuthFlow = AuthFlowType.USER_PASSWORD_AUTH, + AuthFlow = AuthFlowType.ADMIN_USER_PASSWORD_AUTH, }; var response = await _cognitoService.AdminInitiateAuthAsync(request); @@ -194,7 +188,7 @@ public async Task AdminInitiateAuthAsync(string clientId, string userPoo /// The client Id of the application. /// The name of the user who is authenticating. /// The password for the user who is authenticating. - /// The response from the call to InitiateAuthAsync. + /// The response from the initiate auth request. public async Task InitiateAuthAsync(string clientId, string userName, string password) { var authParameters = new Dictionary(); @@ -214,7 +208,6 @@ public async Task InitiateAuthAsync(string clientId, strin return response; } - // snippet-end:[Cognito.dotnetv3.InitiateAuth] // snippet-start:[Cognito.dotnetv3.ConfirmSignUp] @@ -224,7 +217,7 @@ public async Task InitiateAuthAsync(string clientId, strin /// The Id of this application. /// The confirmation code sent to the user. /// The username. - /// + /// True if successful. public async Task ConfirmSignupAsync(string clientId, string code, string userName) { var signUpRequest = new ConfirmSignUpRequest @@ -274,7 +267,7 @@ public async Task ConfirmDeviceAsync(string accessToken, string deviceKey, /// /// The Id of the client application. /// The username of user who will receive the code. - /// + /// The delivery details. public async Task ResendConfirmationCodeAsync(string clientId, string userName) { var codeRequest = new ResendConfirmationCodeRequest @@ -298,7 +291,7 @@ public async Task ResendConfirmationCodeAsync(string cl /// /// The name of the user. /// The Id of the Amazon Cognito user pool. - /// + /// Async task. public async Task GetAdminUserAsync(string userName, string poolId) { AdminGetUserRequest userRequest = new AdminGetUserRequest @@ -324,7 +317,7 @@ public async Task GetAdminUserAsync(string userName, string pool /// The user's password. /// The email address of the user. /// A Boolean value indicating whether the user was confirmed. - public async Task SignUpAsync(string clientId, string userName, string password, String email) + public async Task SignUpAsync(string clientId, string userName, string password, string email) { var userAttrs = new AttributeType { diff --git a/dotnetv3/Cognito/README.md b/dotnetv3/Cognito/README.md index a252afe0476..101e8e7331a 100644 --- a/dotnetv3/Cognito/README.md +++ b/dotnetv3/Cognito/README.md @@ -1,4 +1,4 @@ - + # Amazon Cognito Identity Provider code examples for the SDK for .NET ## Overview @@ -24,7 +24,7 @@ Shows how to use the AWS SDK for .NET to work with Amazon Cognito Identity Provi ### Prerequisites -For prerequisites, see the [README](../README.md#Prerequisites) in the `dotnetv3` folder. +For prerequisites, see the [README](README.md#Prerequisites) in the `dotnetv3` folder. @@ -44,30 +44,38 @@ the scenario. Code excerpts that show you how to call individual service functions. -* [Confirm a user](Actions/CognitoWrapper.cs#L220) (`ConfirmSignUp`) -* [Confirm an MFA device for tracking](Actions/CognitoWrapper.cs#L248) (`ConfirmDevice`) -* [Get a token to associate an MFA application with a user](Actions/CognitoWrapper.cs#L147) (`AssociateSoftwareToken`) -* [Get information about a user](Actions/CognitoWrapper.cs#L295) (`AdminGetUser`) +* [Confirm a user](Actions/CognitoWrapper.cs#L213) (`ConfirmSignUp`) +* [Confirm an MFA device for tracking](Actions/CognitoWrapper.cs#L241) (`ConfirmDevice`) +* [Get a token to associate an MFA application with a user](Actions/CognitoWrapper.cs#L133) (`AssociateSoftwareToken`) +* [Get information about a user](Actions/CognitoWrapper.cs#L288) (`AdminGetUser`) * [List the user pools](Actions/CognitoWrapper.cs#L25) (`ListUserPools`) * [List users](Actions/CognitoWrapper.cs#L46) (`ListUsers`) -* [Resend a confirmation code](Actions/CognitoWrapper.cs#L271) (`ResendConfirmationCode`) -* [Respond to SRP authentication challenges](Actions/CognitoWrapper.cs#L93) (`RespondToAuthChallenge`) +* [Resend a confirmation code](Actions/CognitoWrapper.cs#L264) (`ResendConfirmationCode`) * [Respond to an authentication challenge](Actions/CognitoWrapper.cs#L72) (`AdminRespondToAuthChallenge`) -* [Sign up a user](Actions/CognitoWrapper.cs#L318) (`SignUp`) -* [Start authentication with a tracked device](Actions/CognitoWrapper.cs#L190) (`InitiateAuth`) -* [Start authentication with administrator credentials](Actions/CognitoWrapper.cs#L170) (`AdminInitiateAuth`) -* [Verify an MFA application with a user](Actions/CognitoWrapper.cs#L125) (`VerifySoftwareToken`) +* [Sign up a user](Actions/CognitoWrapper.cs#L311) (`SignUp`) +* [Start authentication with a tracked device](Actions/CognitoWrapper.cs#L184) (`InitiateAuth`) +* [Start authentication with administrator credentials](Actions/CognitoWrapper.cs#L156) (`AdminInitiateAuth`) +* [Verify an MFA application with a user](Actions/CognitoWrapper.cs#L111) (`VerifySoftwareToken`) + +### Scenarios + +Code examples that show you how to accomplish a specific task by calling multiple +functions within the same service. + +* [Sign up a user with a user pool that requires MFA](Actions/CognitoWrapper.cs) ## Run the examples ### Instructions -For general instructions to run the examples, see the [README](../README.md#building-and-running-the-code-examples) in the `dotnetv3` folder. +For general instructions to run the examples, see the +[README](../README.md#building-and-running-the-code-examples) in the `dotnetv3` folder. Some projects might include a settings.json file. Before compiling the project, -you can change these values to match your own account and resources. Alternatively, add a settings.local.json file with -your local settings, which will be loaded automatically when the application runs. +you can change these values to match your own account and resources. Alternatively, +add a settings.local.json file with your local settings, which will be loaded automatically +when the application runs. After the example compiles, you can run it from the command line. To do so, navigate to the folder that contains the .csproj file and run the following command: @@ -75,12 +83,14 @@ the folder that contains the .csproj file and run the following command: ``` dotnet run ``` -Alternatively, you can run the example from within your IDE. +Alternatively, you can run the example from within your IDE. + + #### Sign up a user with a user pool that requires MFA This example shows you how to do the following: @@ -89,12 +99,19 @@ This example shows you how to do the following: * Set up multi-factor authentication by associating an MFA application with the user. * Sign in by using a password and an MFA code. + + + + + + + ### Tests ⚠ Running tests might result in charges to your AWS account. -To find instructions for running these tests, see the [README](../README.md#Tests) +To find instructions for running these tests, see the [README](README.md#Tests) in the `dotnetv3` folder. diff --git a/dotnetv3/Cognito/Scenarios/Cognito_Basics/CognitoBasics.cs b/dotnetv3/Cognito/Scenarios/Cognito_Basics/CognitoBasics.cs index 8ca15f81b28..6969c3c1cf6 100644 --- a/dotnetv3/Cognito/Scenarios/Cognito_Basics/CognitoBasics.cs +++ b/dotnetv3/Cognito/Scenarios/Cognito_Basics/CognitoBasics.cs @@ -19,7 +19,6 @@ static async Task Main(string[] args) .ConfigureServices((_, services) => services.AddAWSService() .AddTransient() - .AddTransient() ) .Build(); @@ -34,7 +33,10 @@ static async Task Main(string[] args) .Build(); var cognitoWrapper = host.Services.GetRequiredService(); - var uiMethods = host.Services.GetRequiredService(); + + Console.WriteLine(new string('-', 80)); + UiMethods.DisplayOverview(); + Console.WriteLine(new string('-', 80)); // clientId - The app client Id value that you get from the AWS CDK script. string clientId = configuration["ClientId"]; // "*** REPLACE WITH CLIENT ID VALUE FROM CDK SCRIPT"; @@ -44,7 +46,6 @@ static async Task Main(string[] args) var userName = configuration["UserName"]; var password = configuration["Password"]; var email = configuration["Email"]; - var userPoolId = configuration["UserPoolId"]; // If the username wasn't set in the configuration file, // get it from the user now. @@ -90,12 +91,12 @@ static async Task Main(string[] args) Console.WriteLine($"Adding {userName} to the user pool"); await cognitoWrapper.GetAdminUserAsync(userName, poolId); - uiMethods.DisplayTitle("Get confirmation code"); + UiMethods.DisplayTitle("Get confirmation code"); Console.WriteLine($"Conformation code sent to {userName}."); - Console.Write("Would you like to send a new code? (Yes/No) "); + Console.Write("Would you like to send a new code? (Y/N) "); var answer = Console.ReadLine(); - if (answer.ToLower() == "YES") + if (answer.ToLower() == "y") { await cognitoWrapper.ResendConfirmationCodeAsync(clientId, userName); Console.WriteLine("Sending a new confirmation code"); @@ -106,25 +107,32 @@ static async Task Main(string[] args) await cognitoWrapper.ConfirmSignupAsync(clientId, code, userName); - uiMethods.DisplayTitle("Checking status"); + UiMethods.DisplayTitle("Checking status"); Console.WriteLine($"Rechecking the status of {userName} in the user pool"); await cognitoWrapper.GetAdminUserAsync(userName, poolId); - var authResponse = await cognitoWrapper.InitiateAuthAsync(clientId, userName, password); - var mySession = authResponse.Session; - - var newSession = await cognitoWrapper.AssociateSoftwareTokenAsync(mySession); + Console.WriteLine($"Setting up authenticator for {userName} in the user pool"); + var setupResponse = await cognitoWrapper.InitiateAuthAsync(clientId, userName, password); + var setupSession = await cognitoWrapper.AssociateSoftwareTokenAsync(setupResponse.Session); Console.Write("Enter the 6-digit code displayed in Google Authenticator: "); - string myCode = Console.ReadLine(); + string setupCode = Console.ReadLine(); + + var setupResult = await cognitoWrapper.VerifySoftwareTokenAsync(setupSession, setupCode); + Console.WriteLine($"Setup status: {setupResult}"); + + Console.WriteLine($"Now logging in {userName} in the user pool"); + var authSession = await cognitoWrapper.AdminInitiateAuthAsync(clientId, poolId, userName, password); + + Console.Write("Enter a new 6-digit code displayed in Google Authenticator: "); + string authCode = Console.ReadLine(); - // Verify the TOTP and register for MFA. - await cognitoWrapper.GetAdminUserAsync(newSession, myCode); - Console.Write("Re-enter the 6-digit code displayed in your authenticator"); - string mfaCode = Console.ReadLine(); + var authResult = await cognitoWrapper.AdminRespondToAuthChallengeAsync(userName, clientId, authCode, authSession, poolId); + Console.WriteLine($"Authenticated and received access token: {authResult.AccessToken}"); - var session2 = await cognitoWrapper.AdminInitiateAuthAsync(clientId, userPoolId, userName, password); - await cognitoWrapper.RespondToAuthChallengeAsync(userName, clientId, mfaCode, session2); + Console.WriteLine(new string('-', 80)); + Console.WriteLine("Cognito scenario is complete."); + Console.WriteLine(new string('-', 80)); } } diff --git a/dotnetv3/Cognito/Scenarios/Cognito_Basics/UIMethods.cs b/dotnetv3/Cognito/Scenarios/Cognito_Basics/UIMethods.cs index 5939a446cef..379ea9c5bbb 100644 --- a/dotnetv3/Cognito/Scenarios/Cognito_Basics/UIMethods.cs +++ b/dotnetv3/Cognito/Scenarios/Cognito_Basics/UIMethods.cs @@ -7,14 +7,14 @@ namespace CognitoBasics; /// /// Some useful methods to make screen display easier. /// -public class UiMethods +public static class UiMethods { - public readonly string SepBar = new string('-', Console.WindowWidth); + public static readonly string SepBar = new string('-', Console.WindowWidth); /// /// Show information about the scenario. /// - public void DisplayOverview() + public static void DisplayOverview() { Console.Clear(); DisplayTitle("Welcome to the Amazon Cognito Demo"); @@ -34,7 +34,7 @@ public void DisplayOverview() /// /// Display a message and wait until the user presses enter. /// - public void PressEnter() + public static void PressEnter() { Console.Write("\nPress to continue."); _ = Console.ReadLine(); @@ -45,7 +45,7 @@ public void PressEnter() /// /// The string to pad with spaces. /// The padded string. - public string CenterString(string strToCenter) + public static string CenterString(string strToCenter) { var padAmount = (Console.WindowWidth - strToCenter.Length) / 2; var leftPad = new string(' ', padAmount); @@ -57,7 +57,7 @@ public string CenterString(string strToCenter) /// line of hyphens. /// /// The string to be displayed. - public void DisplayTitle(string strTitle) + public static void DisplayTitle(string strTitle) { Console.WriteLine(SepBar); Console.WriteLine(CenterString(strTitle)); diff --git a/dotnetv3/Cognito/Scenarios/Cognito_Basics/settings.json b/dotnetv3/Cognito/Scenarios/Cognito_Basics/settings.json index f890ad8d7b2..4bfac53daa4 100644 --- a/dotnetv3/Cognito/Scenarios/Cognito_Basics/settings.json +++ b/dotnetv3/Cognito/Scenarios/Cognito_Basics/settings.json @@ -1,12 +1,9 @@ { - "parameterGroupName": "test-parameter-group", - "parameterGroupFamily": "mysql8.0", - "modifyParameterName": "auto_increment_offset", - "modifyParameterValue": "3", - "engineName": "mysql", - "engineVersion": "8.0.28", - "instanceIdentifier": "test-instance-1", - "instanceClass": "db.t3.micro", + "ClientId": "client_id_from_cdk", + "PoolId": "client_id_from_cdk", + "UserName": "username", + "Password": "EXAMPLEPASSWORD", + "Email": "useremail", "adminUserName": "admin", "adminPassword": "EXAMPLEPASSWORD" } diff --git a/resources/cdk/cognito_scenario_user_pool_with_mfa/package-lock.json b/resources/cdk/cognito_scenario_user_pool_with_mfa/package-lock.json index 6c476ab921d..fdd1d44f40a 100644 --- a/resources/cdk/cognito_scenario_user_pool_with_mfa/package-lock.json +++ b/resources/cdk/cognito_scenario_user_pool_with_mfa/package-lock.json @@ -8,6 +8,7 @@ "name": "setup", "version": "0.1.0", "dependencies": { + "aws-cdk-lib": "^2.80.0", "constructs": "^10.1.42", "source-map-support": "^0.5.21" },