From ef68eddecd226776d9b8506e999a12c860c83750 Mon Sep 17 00:00:00 2001 From: Laura Rodriguez Date: Mon, 14 Mar 2022 15:48:45 -0400 Subject: [PATCH 1/4] Fix e2e tests. --- ...ageForDirectAuthDemoApplication.feature.cs | 8 +- .../Features/10.1.4-5.TotpSupport.feature.cs | 8 +- .../Features/10.1.TotpSupport.feature.cs | 8 +- ...11-BasicLoginWithPasswordFactor.feature.cs | 8 +- .../3-SelfServicePasswordRecovery.feature.cs | 8 +- .../Features/4-SsrWithEmailAndSms.feature.cs | 8 +- ...aOidcIdpSocialLoginWithPassword.feature.cs | 8 +- ...5.2-DirectAuthSocialLoginWthMFA.feature.cs | 8 +- .../6.1-MfaWithPasswordAndEmail.feature.cs | 8 +- .../6.2-MfaWithPasswordAndSms.feature.cs | 8 +- .../Helpers/TestContext.cs | 1 + .../Pages/SelectAuthenticatorPageSteps.cs | 260 +++++++++--------- .../embedded-auth-with-sdk.E2ETests.csproj | 141 +++++----- .../Controllers/ManageController.cs | 50 ++-- 14 files changed, 267 insertions(+), 265 deletions(-) diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/00-RootPageForDirectAuthDemoApplication.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/00-RootPageForDirectAuthDemoApplication.feature.cs index 81d515cd..f364984a 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/00-RootPageForDirectAuthDemoApplication.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/00-RootPageForDirectAuthDemoApplication.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _0_1RootPageForDirectAuthDemoApplicationFeature : object, Xunit.IClassFixture<_0_1RootPageForDirectAuthDemoApplicationFeature.FixtureData>, System.IDisposable { @@ -139,7 +139,7 @@ public virtual void _0_1_3MaryLogsOutOfTheApp() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.4-5.TotpSupport.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.4-5.TotpSupport.feature.cs index 67483688..bf60e4d6 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.4-5.TotpSupport.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.4-5.TotpSupport.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _10_1TOTPSupportGoogleAuthenticatorPart2Feature : object, Xunit.IClassFixture<_10_1TOTPSupportGoogleAuthenticatorPart2Feature.FixtureData>, System.IDisposable { @@ -342,7 +342,7 @@ public virtual void _10_1_5MarySignsUpForAnAccountWithPasswordSetupsUpRequiredGo this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.TotpSupport.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.TotpSupport.feature.cs index fa7a4d62..687d67c6 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.TotpSupport.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/10.1.TotpSupport.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _10_1TOTPSupportGoogleAuthenticatorFeature : object, Xunit.IClassFixture<_10_1TOTPSupportGoogleAuthenticatorFeature.FixtureData>, System.IDisposable { @@ -363,7 +363,7 @@ public virtual void _10_1_3MarySignsInToTheSampleAppWithPasswordAndGoogleAuthent this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11-BasicLoginWithPasswordFactor.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11-BasicLoginWithPasswordFactor.feature.cs index 5bdeda76..eda66de8 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11-BasicLoginWithPasswordFactor.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11-BasicLoginWithPasswordFactor.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _1_1BasicLoginWithPasswordFactorFeature : object, Xunit.IClassFixture<_1_1BasicLoginWithPasswordFactorFeature.FixtureData>, System.IDisposable { @@ -299,7 +299,7 @@ public virtual void _1_1_8MaryClicksOnTheForgotPasswordLink() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/3-SelfServicePasswordRecovery.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/3-SelfServicePasswordRecovery.feature.cs index a715151e..80279e8b 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/3-SelfServicePasswordRecovery.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/3-SelfServicePasswordRecovery.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _3_1DirectAuthPasswordRecoveryFeature : object, Xunit.IClassFixture<_3_1DirectAuthPasswordRecoveryFeature.FixtureData>, System.IDisposable { @@ -223,7 +223,7 @@ public virtual void _3_1_2MaryTriesToResetAPasswordWithTheWrongEmail() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/4-SsrWithEmailAndSms.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/4-SsrWithEmailAndSms.feature.cs index 01536ce2..0fbe960b 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/4-SsrWithEmailAndSms.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/4-SsrWithEmailAndSms.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _4_1SelfServiceRegistrationWithEmailActivationAndOptionalSMSFeature : object, Xunit.IClassFixture<_4_1SelfServiceRegistrationWithEmailActivationAndOptionalSMSFeature.FixtureData>, System.IDisposable { @@ -478,7 +478,7 @@ public virtual void _4_1_4MarySignsUpForAnAccountWithPasswordSetsUpRequiredEmail this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs index 18d8ddbc..6b24fa67 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _5_1DirectAuthSocialLoginWith1SocialIDPFeature : object, Xunit.IClassFixture<_5_1DirectAuthSocialLoginWith1SocialIDPFeature.FixtureData>, System.IDisposable { @@ -153,7 +153,7 @@ public virtual void _5_1_1MaryLogsInWithSocialIDP() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.2-DirectAuthSocialLoginWthMFA.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.2-DirectAuthSocialLoginWthMFA.feature.cs index ccf7df04..20e353fa 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.2-DirectAuthSocialLoginWthMFA.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/5.2-DirectAuthSocialLoginWthMFA.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _5_2DirectAuthSocialLoginWithMFAFeature : object, Xunit.IClassFixture<_5_2DirectAuthSocialLoginWithMFAFeature.FixtureData>, System.IDisposable { @@ -150,7 +150,7 @@ public virtual void _5_2_1MaryLogsInWithASocialIDPAndGetsAnErrorMessage() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.1-MfaWithPasswordAndEmail.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.1-MfaWithPasswordAndEmail.feature.cs index 2b8b491a..8156ff34 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.1-MfaWithPasswordAndEmail.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.1-MfaWithPasswordAndEmail.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _6_1Multi_FactorAuthenticationWithPasswordAndEmailFeature : object, Xunit.IClassFixture<_6_1Multi_FactorAuthenticationWithPasswordAndEmailFeature.FixtureData>, System.IDisposable { @@ -220,7 +220,7 @@ public virtual void _6_1_3MaryEntersAWrongVerificationCode() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.2-MfaWithPasswordAndSms.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.2-MfaWithPasswordAndSms.feature.cs index 1807dc4e..fab89f2d 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.2-MfaWithPasswordAndSms.feature.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/6.2-MfaWithPasswordAndSms.feature.cs @@ -1,8 +1,8 @@ // ------------------------------------------------------------------------------ // // This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.8.0.0 -// SpecFlow Generator Version:3.8.0.0 +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -17,7 +17,7 @@ namespace embedded_auth_with_sdk.E2ETests.Features using System.Linq; - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public partial class _6_2Multi_FactorAuthenticationWithPasswordAndSMSFeature : object, Xunit.IClassFixture<_6_2Multi_FactorAuthenticationWithPasswordAndSMSFeature.FixtureData>, System.IDisposable { @@ -406,7 +406,7 @@ public virtual void _6_2_4MaryEntersAWrongVerificationCodeOnVerify() this.ScenarioCleanup(); } - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.8.0.0")] + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FixtureData : System.IDisposable { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Helpers/TestContext.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Helpers/TestContext.cs index 286eb659..c85c44dd 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Helpers/TestContext.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Helpers/TestContext.cs @@ -9,6 +9,7 @@ using OpenQA.Selenium; using OtpNet; using ZXing; +using ZXing.Windows.Compatibility; namespace embedded_auth_with_sdk.E2ETests.Helpers { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs index 4be5dec5..f8f4abdc 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs @@ -1,149 +1,149 @@ -using FluentAssertions; -using embedded_auth_with_sdk.E2ETests.PageObjectModels; -using OpenQA.Selenium; -using System; -using TechTalk.SpecFlow; - -namespace embedded_auth_with_sdk.E2ETests.Steps.Pages -{ - [Binding] - public class SelectAuthenticatorPageSteps : BaseTestSteps - { - private SelectAuthenticatorPage _selectAuthenticatorPageModel; - private SelectAuthenticatorAsyncPage _selectAuthenticatorAsyncPageModel; - - public SelectAuthenticatorPageSteps(ITestContext context, - SelectAuthenticatorPage selectAuthenticatorPageModel, - SelectAuthenticatorAsyncPage selectAuthenticatorAsyncPageModel) - : base(context) - { - _selectAuthenticatorPageModel = selectAuthenticatorPageModel; - _selectAuthenticatorAsyncPageModel = selectAuthenticatorAsyncPageModel; - } - - [Then(@"She sees a list of factors")] - [Then(@"she sees a list of factors to register")] - [Then(@"she sees a list of required factors to setup")] - [Then(@"she is presented with a list of factors")] - public void ThenSheIsPresentedWithAnOptionToSelectEmailToVerify() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - } - - [When(@"she selects Email")] - [When(@"She selects Email from the list")] - [When(@"She has selected Email from the list of factors")] - public void WhenSheSelectsEmail() - { - _selectAuthenticatorPageModel.EmailAuthenticator.Click(); - _selectAuthenticatorPageModel.SubmitButton.Click(); - } - - [Then(@"she sees the list of optional factors \(SMS\)")] - [Then(@"she is presented with an option to select Phone")] +using FluentAssertions; +using embedded_auth_with_sdk.E2ETests.PageObjectModels; +using OpenQA.Selenium; +using System; +using TechTalk.SpecFlow; + +namespace embedded_auth_with_sdk.E2ETests.Steps.Pages +{ + [Binding] + public class SelectAuthenticatorPageSteps : BaseTestSteps + { + private SelectAuthenticatorPage _selectAuthenticatorPageModel; + private SelectAuthenticatorAsyncPage _selectAuthenticatorAsyncPageModel; + + public SelectAuthenticatorPageSteps(ITestContext context, + SelectAuthenticatorPage selectAuthenticatorPageModel, + SelectAuthenticatorAsyncPage selectAuthenticatorAsyncPageModel) + : base(context) + { + _selectAuthenticatorPageModel = selectAuthenticatorPageModel; + _selectAuthenticatorAsyncPageModel = selectAuthenticatorAsyncPageModel; + } + + [Then(@"She sees a list of factors")] + [Then(@"she sees a list of factors to register")] + [Then(@"she sees a list of required factors to setup")] + [Then(@"she is presented with a list of factors")] + public void ThenSheIsPresentedWithAnOptionToSelectEmailToVerify() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + } + + [When(@"she selects Email")] + [When(@"She selects Email from the list")] + [When(@"She has selected Email from the list of factors")] + public void WhenSheSelectsEmail() + { + _selectAuthenticatorPageModel.EmailAuthenticator.Click(); + _selectAuthenticatorPageModel.SubmitButton.Click(); + } + + [Then(@"she sees the list of optional factors \(SMS\)")] + [Then(@"she is presented with an option to select Phone")] [Then(@"she is presented with an option to select SMS to enroll")] - public void ThenSheSeesTheListOfOptionalFactorsSMS() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - Func getSmsFactor = () => _selectAuthenticatorPageModel.PhoneAuthenticator; - getSmsFactor.Should().NotThrow(); - _selectAuthenticatorPageModel.PhoneAuthenticator.Displayed.Should().BeTrue(); - } - - [Then(@"she sees the list of optional factors")] - public void ThenSheSeesTheListOfOptionalFactors() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - } - - - [Then(@"she is presented with an option to select SMS to verify")] - public void ThenSheIsPresentedWithAnOptionToSelectSmsToVerify() - { - _selectAuthenticatorAsyncPageModel.AssertPageOpenedAndValid(); - Func getSmsFactor = () => _selectAuthenticatorAsyncPageModel.SmsAuthenticator; - getSmsFactor.Should().NotThrow(); - _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Displayed.Should().BeTrue(); - } - - [Then(@"she is presented with an option to select Email to verify")] - public void SheIsPresentedWithAnOptionToSelectEmailToVerify() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - Func getSmsFactor = () => _selectAuthenticatorPageModel.EmailAuthenticator; - getSmsFactor.Should().NotThrow(); - _selectAuthenticatorPageModel.EmailAuthenticator.Displayed.Should().BeTrue(); - } - - [When(@"She selects SMS from the list")] - public void WhenSheSelectsSMSFromTheList() - { - _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Click(); - _selectAuthenticatorAsyncPageModel.SubmitButton.Click(); - } - - [When(@"she selects Phone")] - [When(@"She selects Phone from the list")] - [When(@"she selects Phone from the list")] - public void WhenSheSelectsPhone() - { - _selectAuthenticatorPageModel.PhoneAuthenticator.Click(); - _selectAuthenticatorPageModel.SubmitButton.Click(); - } - - [Then(@"she sees the Select Authenticator page with password as the only option")] - public void ThenSheSeesTheSelectAuthenticatorPageWithPasswordAsAnOnlyOption() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - Func getPasswordFunc = () => _selectAuthenticatorPageModel.PasswordAuthenticator; - getPasswordFunc.Should().NotThrow(); - } - - [When(@"she chooses password factor option")] - public void WhenSheChoosesPasswordFactorOption() - { - _selectAuthenticatorPageModel.PasswordAuthenticator.Click(); - } - - [When(@"she submits the select authenticator form")] - public void WhenSheSubmitsTheSelectAuthenticatorForm() - { - _selectAuthenticatorPageModel.SubmitButton.Click(); - } - - [When(@"she selects Skip")] - public void WhenSheSelectsOnSMS() - { - _selectAuthenticatorPageModel.SkipThisStepButton.Click(); - } - - + public void ThenSheSeesTheListOfOptionalFactorsSMS() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + Func getSmsFactor = () => _selectAuthenticatorPageModel.PhoneAuthenticator; + getSmsFactor.Should().NotThrow(); + _selectAuthenticatorPageModel.PhoneAuthenticator.Displayed.Should().BeTrue(); + } + + [Then(@"she sees the list of optional factors")] + public void ThenSheSeesTheListOfOptionalFactors() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + } + + + [Then(@"she is presented with an option to select SMS to verify")] + public void ThenSheIsPresentedWithAnOptionToSelectSmsToVerify() + { + _selectAuthenticatorAsyncPageModel.AssertPageOpenedAndValid(); + Func getSmsFactor = () => _selectAuthenticatorAsyncPageModel.SmsAuthenticator; + getSmsFactor.Should().NotThrow(); + _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Displayed.Should().BeTrue(); + } + + [Then(@"she is presented with an option to select Email to verify")] + public void SheIsPresentedWithAnOptionToSelectEmailToVerify() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + Func getSmsFactor = () => _selectAuthenticatorPageModel.EmailAuthenticator; + getSmsFactor.Should().NotThrow(); + _selectAuthenticatorPageModel.EmailAuthenticator.Displayed.Should().BeTrue(); + } + + [When(@"She selects SMS from the list")] + public void WhenSheSelectsSMSFromTheList() + { + _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Click(); + _selectAuthenticatorAsyncPageModel.SubmitButton.Click(); + } + + [When(@"she selects Phone")] + [When(@"She selects Phone from the list")] + [When(@"she selects Phone from the list")] + public void WhenSheSelectsPhone() + { + _selectAuthenticatorPageModel.PhoneAuthenticator.Click(); + _selectAuthenticatorPageModel.SubmitButton.Click(); + } + + [Then(@"she sees the Select Authenticator page with password as the only option")] + public void ThenSheSeesTheSelectAuthenticatorPageWithPasswordAsAnOnlyOption() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + Func getPasswordFunc = () => _selectAuthenticatorPageModel.PasswordAuthenticator; + getPasswordFunc.Should().NotThrow(); + } + + [When(@"she chooses password factor option")] + public void WhenSheChoosesPasswordFactorOption() + { + _selectAuthenticatorPageModel.PasswordAuthenticator.Click(); + } + + [When(@"she submits the select authenticator form")] + public void WhenSheSubmitsTheSelectAuthenticatorForm() + { + _selectAuthenticatorPageModel.SubmitButton.Click(); + } + + [When(@"she selects Skip")] + public void WhenSheSelectsOnSMS() + { + _selectAuthenticatorPageModel.SkipThisStepButton.Click(); + } + + [When(@"she skips optional authenticators if prompted")] public void WhenSheSkipsOptionalAuthenticatorsIfPrompted() - { + { if (_selectAuthenticatorPageModel.IsPageOpened) { _selectAuthenticatorPageModel.SkipThisStepButton.Click(); } } - + [Then(@"she sees the list of required factors \(Google Authenticator\) to enroll")] [Then(@"she is presented with an option to select Google Authenticator to verify")] - public void ThenSheSeesTheListOfRequiredFactorsGoogleAuthenticatorToEnroll() - { - _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); - Func getPasswordFunc = () => _selectAuthenticatorPageModel.GoogleAuthenticator; - getPasswordFunc.Should().NotThrow(); + public void ThenSheSeesTheListOfRequiredFactorsGoogleAuthenticatorToEnroll() + { + _selectAuthenticatorPageModel.AssertPageOpenedAndValid(); + Func getPasswordFunc = () => _selectAuthenticatorPageModel.GoogleAuthenticator; + getPasswordFunc.Should().NotThrow(); } [When(@"She selects Google Authenticator from the list")] public void WhenSheSelectsGoogleAuthenticatorFromTheList() { - _selectAuthenticatorPageModel.GoogleAuthenticator.Click(); - _selectAuthenticatorPageModel.SubmitButton.Click(); + _selectAuthenticatorPageModel.GoogleAuthenticator.Click(); + _selectAuthenticatorPageModel.SubmitButton.Click(); } - } -} + } +} diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj index 7f82041f..bc89bcc3 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj @@ -1,72 +1,73 @@ - - - - net5.0 - - false - - embedded_auth_with_sdk.E2ETests - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - + + + + net5.0 + + false + + embedded_auth_with_sdk.E2ETests + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + - - - - - True - - - - - - PreserveNewest - - - - - - SpecFlowSingleFileGenerator - 5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs - - - + + + + + True + + + + + + PreserveNewest + + + + + + SpecFlowSingleFileGenerator + 5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs + + + diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs index 47d41a86..20065c78 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs @@ -686,20 +686,20 @@ public async Task SelectRecoveryAuthenticatorAsync(SelectRecoveryA } } - [HttpPost] - [AllowAnonymous] - [ValidateAntiForgeryToken] - public async Task ChangePasswordWithRecoveryTokenAsync(ChangePasswordWithRecoveryTokenViewModel model) - { - if (!ModelState.IsValid) - { - return View("ChangePasswordWithRecoveryToken", model); - } - - try - { - var recoverPasswordResponse = await _idxClient.RecoverPasswordAsync( - new RecoverPasswordOptions + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task ChangePasswordWithRecoveryTokenAsync(ChangePasswordWithRecoveryTokenViewModel model) + { + if (!ModelState.IsValid) + { + return View("ChangePasswordWithRecoveryToken", model); + } + + try + { + var recoverPasswordResponse = await _idxClient.RecoverPasswordAsync( + new RecoverPasswordOptions { RecoveryToken = model.RecoveryToken, Username = model.UserName, @@ -712,16 +712,16 @@ public async Task ChangePasswordWithRecoveryTokenAsync(ChangePassw _idxClient.Configuration, recoverPasswordResponse.TokenInfo); _authenticationManager.SignIn(new AuthenticationProperties(), identity); - return RedirectToAction("Index", "Home"); - } - return RedirectToAction("Index", "Home"); - } - catch (OktaException exception) - { - ModelState.AddModelError(string.Empty, exception.Message); - return View("ChangePasswordWithRecoveryToken", model); - } - } - + return RedirectToAction("Index", "Home"); + } + return RedirectToAction("Index", "Home"); + } + catch (OktaException exception) + { + ModelState.AddModelError(string.Empty, exception.Message); + return View("ChangePasswordWithRecoveryToken", model); + } + } + } } \ No newline at end of file From 569e38aba2aa524e5064f7e8a4cf0ac6f644a302 Mon Sep 17 00:00:00 2001 From: Laura Rodriguez Date: Thu, 17 Mar 2022 14:58:11 -0400 Subject: [PATCH 2/4] Add unlock account functionality. Update sample application with unlock account models/views. --- .../Controllers/AccountController.cs | 38 ++++++- .../Controllers/ManageController.cs | 47 +++++++- .../Models/SelectAuthenticatorViewModel.cs | 29 +++-- .../Models/UnlockAccountViewModel.cs | 15 +++ .../Views/Account/Login.cshtml | 24 +++-- .../Views/Account/UnlockAccount.cshtml | 79 ++++++++++++++ .../Views/Manage/VerifyAuthenticator.cshtml | 102 +++++++++--------- .../embedded-auth-with-sdk.csproj | 2 + src/Okta.Idx.Sdk/AuthenticationStatus.cs | 5 + src/Okta.Idx.Sdk/IIdxClient.cs | 16 +++ src/Okta.Idx.Sdk/IdxClient.cs | 90 ++++++++++++++++ src/Okta.Idx.Sdk/IdxMessages.cs | 34 +++--- src/Okta.Idx.Sdk/MessagesType.cs | 16 +++ src/Okta.Idx.Sdk/RemediationType.cs | 15 +++ src/Okta.Idx.Sdk/UnlockAccountOptions.cs | 18 ++++ 15 files changed, 444 insertions(+), 86 deletions(-) create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/UnlockAccountViewModel.cs create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/UnlockAccount.cshtml create mode 100644 src/Okta.Idx.Sdk/MessagesType.cs create mode 100644 src/Okta.Idx.Sdk/UnlockAccountOptions.cs diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/AccountController.cs b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/AccountController.cs index d473e1a3..71386fbc 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/AccountController.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/AccountController.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using System.Web; @@ -229,5 +230,40 @@ public async Task RecoverPasswordWithTokenAsync(RecoverPasswordWit return View("~/Views/Manage/ChangePasswordWithRecoveryToken.cshtml", changePasswordViewModel); } + + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task UnlockAccountAsync() + { + try + { + var response = await _idxClient.UnlockAccountAsync(); + + if (response.AuthenticationStatus == AuthenticationStatus.AwaitingAuthenticatorSelection) + { + Session["idxContext"] = response.IdxContext; + Session["authenticators"] = + ViewModelHelper.ConvertToAuthenticatorViewModelList(response.Authenticators); + var authenticators = (IList)Session["authenticators"] ?? + new List(); + + var viewModel = new UnlockAccountViewModel + { + Authenticators = authenticators, + CanSkip = TempData["canSkip"] != null && (bool)TempData["canSkip"] + }; + + return View("UnlockAccount", viewModel); + } + + return View("Login"); + } + catch (OktaException ex) + { + TempData["MessageToUser"] = $"Oops! Something went wrong. Try again. {ex.Message}"; + return View("Login"); + } + } } } diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs index 20065c78..4b18046f 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Controllers/ManageController.cs @@ -404,11 +404,6 @@ public ActionResult SelectAuthenticator() { Authenticators = authenticators, AuthenticatorId = authenticators.FirstOrDefault()?.AuthenticatorId, - PasswordId = authenticators.FirstOrDefault(x => x.Name.ToLower() == "password")?.AuthenticatorId, - PhoneId = authenticators.FirstOrDefault(x => x.Name.ToLower() == "phone")?.AuthenticatorId, - WebAuthnId = authenticators.FirstOrDefault(x => x.Name.ToLower() == "security key or biometric")?.AuthenticatorId, - TotpId = authenticators.FirstOrDefault(x => x.Name.ToLower() == "google authenticator")?.AuthenticatorId, - OktaVerifyId = authenticators.FirstOrDefault(x => x.Name.ToLower() == "okta verify")?.AuthenticatorId, CanSkip = TempData["canSkip"] != null && (bool)TempData["canSkip"] }; @@ -644,6 +639,48 @@ public async Task SelectAuthenticatorAsync(SelectAuthenticatorView } } + [HttpPost] + [AllowAnonymous] + [ValidateAntiForgeryToken] + public async Task SelectUnlockAccountAuthenticatorAsync(UnlockAccountViewModel model) + { + var authenticators = (IList)Session["authenticators"]; + + if (!ModelState.IsValid) + { + model.Authenticators = authenticators; + return View("~/Views/Account/UnlockAccount.cshtml", model); + } + + var unlockAccountOptions = new UnlockAccountOptions + { + AuthenticatorId = model.AuthenticatorId, + Username = model.UserName, + }; + + try + { + var response = await _idxClient.SelectUnlockAccountAuthenticatorAsync(unlockAccountOptions, + (IIdxContext)Session["idxContext"]); + + if (response.AuthenticationStatus == AuthenticationStatus.AwaitingAuthenticatorVerification) + { + return View("VerifyAuthenticator"); + } + + model.Authenticators = authenticators; + ModelState.AddModelError(string.Empty, $"Something went wrong. Expected {AuthenticationStatus.AwaitingAuthenticatorVerification} but got {response.AuthenticationStatus}"); + return View("~/Views/Account/UnlockAccount.cshtml", model); + } + catch (OktaException exception) + { + ModelState.AddModelError(string.Empty, exception.Message); + model.Authenticators = authenticators; + return View("~/Views/Account/UnlockAccount.cshtml", model); + } + } + + public ActionResult SelectRecoveryAuthenticator() { var viewModel = new SelectRecoveryAuthenticatorViewModel diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/SelectAuthenticatorViewModel.cs b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/SelectAuthenticatorViewModel.cs index f72b2b97..b1749dd4 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/SelectAuthenticatorViewModel.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/SelectAuthenticatorViewModel.cs @@ -13,19 +13,36 @@ public class SelectAuthenticatorViewModel [Display(Name = "Authenticator ID")] public string AuthenticatorId { get; set; } - public string PasswordId { get; set; } + public string PasswordId { get; private set; } - public string PhoneId { get; set; } + public string PhoneId { get; private set; } - public string WebAuthnId { get; set; } + public string WebAuthnId { get; private set; } - public string TotpId { get; set; } + public string TotpId { get; private set; } - public string OktaVerifyId { get; set; } + public string OktaVerifyId { get; private set; } public bool CanSkip { get; set; } - public IList Authenticators { get; set; } + private IList _authenticators; + public IList Authenticators + { + get => _authenticators; + + set + { + _authenticators = value; + AuthenticatorId = _authenticators?.FirstOrDefault()?.AuthenticatorId; + PasswordId = _authenticators?.FirstOrDefault(x => x.Name.ToLower() == "password")?.AuthenticatorId; + PhoneId = _authenticators?.FirstOrDefault(x => x.Name.ToLower() == "phone")?.AuthenticatorId; + WebAuthnId = _authenticators?.FirstOrDefault(x => x.Name.ToLower() == "security key or biometric") + ?.AuthenticatorId; + TotpId = _authenticators?.FirstOrDefault(x => x.Name.ToLower() == "google authenticator") + ?.AuthenticatorId; + OktaVerifyId = _authenticators?.FirstOrDefault(x => x.Name.ToLower() == "okta verify")?.AuthenticatorId; + } + } public bool IsPasswordSelected => PasswordId != null && PasswordId == AuthenticatorId; diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/UnlockAccountViewModel.cs b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/UnlockAccountViewModel.cs new file mode 100644 index 00000000..d1ced037 --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Models/UnlockAccountViewModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; + +namespace embedded_auth_with_sdk.Models +{ + public class UnlockAccountViewModel : SelectAuthenticatorViewModel + { + [Required] + [Display(Name = "Username")] + public string UserName { get; set; } + } +} \ No newline at end of file diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml index 11b913c4..ce5ed93d 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml @@ -88,12 +88,24 @@
@using (Html.BeginForm("RecoverPasswordWithToken", "Account", FormMethod.Get, new { @class = "form-horizontal", role = "form" })) { -
-
- -
-
- } +
+
+ +
+
+ } +
+ +
+ @using (Html.BeginForm("UnlockAccountAsync", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) + { + @Html.AntiForgeryToken() +
+
+ +
+
+ }
diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/UnlockAccount.cshtml b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/UnlockAccount.cshtml new file mode 100644 index 00000000..b9cd8a8f --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/UnlockAccount.cshtml @@ -0,0 +1,79 @@ +@model embedded_auth_with_sdk.Models.UnlockAccountViewModel + +@{ + ViewBag.Title = "Unlock your account"; + Layout = "~/Views/Shared/_Layout.cshtml"; +} + +
+
+
+
+ @using (Html.BeginForm("SelectUnlockAccountAuthenticatorAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) + { + @Html.AntiForgeryToken() +

Unlock your account

+
Enter your username and select an authenticator
+
+ @Html.ValidationSummary(true, "", new { @class = "text-danger", @id = "validationErrorMessage" }) + +
+
+
+ @Html.LabelFor(m => m.UserName, new { @class = "control-label" }) +
+
+ @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" }) + @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" }) +
+
+
+ +
+ @Html.ValidationSummary(true, "", new { @class = "text-danger" }) + @Html.HiddenFor(m => m.PasswordId) + @Html.HiddenFor(m => m.PhoneId) + @Html.HiddenFor(m => m.WebAuthnId) + @Html.HiddenFor(m => m.OktaVerifyId) + @Html.HiddenFor(m => m.TotpId) +
+
+
    + @foreach (var authenticator in Model.Authenticators) + { +
    + +
    + } +
+
+
+ @Html.ValidationMessageFor(m => m.AuthenticatorId, "", new { @class = "text-danger" }) +
+
+ +
+
+ } + @if (Model.CanSkip) + { + using (Html.BeginForm("SkipAuthenticatorSelectionAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) + { +
+
+ +
+
+ } + + } + +
+
+
+@section Scripts { + @Scripts.Render("~/bundles/jqueryval") +} diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Manage/VerifyAuthenticator.cshtml b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Manage/VerifyAuthenticator.cshtml index 50ea61c1..bc2df3e0 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Manage/VerifyAuthenticator.cshtml +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Manage/VerifyAuthenticator.cshtml @@ -1,53 +1,53 @@ -@model embedded_auth_with_sdk.Models.VerifyAuthenticatorViewModel -@{ - ViewBag.Title = ViewBag.Title ?? "Verify your authenticator."; -} - -
- -
-
-
- @using (Html.BeginForm("VerifyAuthenticatorAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) - { - @Html.AntiForgeryToken() -

Verify authenticator.

-
Enter the passcode to continue.
-
- @Html.ValidationSummary(true, "", new { @class = "text-danger" }) -
-
-
- @Html.LabelFor(m => m.Code, new { @class = "control-label" }) -
-
- @Html.TextBoxFor(m => m.Code, new { @class = "form-control", @id="passcodeInput" }) - @Html.ValidationMessageFor(m => m.Code, "", new { @class = "text-danger" }) -
-
-
- -
-
- -
-
- } -
+@model embedded_auth_with_sdk.Models.VerifyAuthenticatorViewModel +@{ + ViewBag.Title = ViewBag.Title ?? "Verify your authenticator."; +} + +
+ +
+
+
+ @using (Html.BeginForm("VerifyAuthenticatorAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) + { + @Html.AntiForgeryToken() +

Verify authenticator.

+
Enter the passcode to continue.
+
+ @Html.ValidationSummary(true, "", new { @class = "text-danger" }) +
+
+
+ @Html.LabelFor(m => m.Code, new { @class = "control-label" }) +
+
+ @Html.TextBoxFor(m => m.Code, new { @class = "form-control", @id="passcodeInput" }) + @Html.ValidationMessageFor(m => m.Code, "", new { @class = "text-danger" }) +
+
+
+ +
+
+ +
+
+ } +
-@using (Html.BeginForm("ResendAuthenticatorAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) - { - @Html.AntiForgeryToken() -
-
- -
-
- } -
-
-
- -@section Scripts { - @Scripts.Render("~/bundles/jqueryval") +@using (Html.BeginForm("ResendAuthenticatorAsync", "Manage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) + { + @Html.AntiForgeryToken() +
+
+ +
+
+ } + +
+
+ +@section Scripts { + @Scripts.Render("~/bundles/jqueryval") } \ No newline at end of file diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/embedded-auth-with-sdk.csproj b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/embedded-auth-with-sdk.csproj index 57ba5c91..571d250f 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/embedded-auth-with-sdk.csproj +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/embedded-auth-with-sdk.csproj @@ -367,6 +367,7 @@ + @@ -444,6 +445,7 @@ + diff --git a/src/Okta.Idx.Sdk/AuthenticationStatus.cs b/src/Okta.Idx.Sdk/AuthenticationStatus.cs index f01e3b36..af09ff53 100644 --- a/src/Okta.Idx.Sdk/AuthenticationStatus.cs +++ b/src/Okta.Idx.Sdk/AuthenticationStatus.cs @@ -54,5 +54,10 @@ public enum AuthenticationStatus /// Waiting for an authenticator selection to continue with the authentication process. /// AwaitingChallengeAuthenticatorSelection, + + /// + /// The user's account was successfully unlocked. + /// + UnlockAccountSuccess, } } diff --git a/src/Okta.Idx.Sdk/IIdxClient.cs b/src/Okta.Idx.Sdk/IIdxClient.cs index 2c45685d..2e6bdfd4 100644 --- a/src/Okta.Idx.Sdk/IIdxClient.cs +++ b/src/Okta.Idx.Sdk/IIdxClient.cs @@ -221,6 +221,22 @@ public interface IIdxClient : IOktaClient /// The authentication response. Task SkipAuthenticatorSelectionAsync(IIdxContext idxContext, CancellationToken cancellationToken = default); + /// + /// Starts the flow to unlocks the user's account + /// + /// The cancellation token. + /// The authentication response. + Task UnlockAccountAsync(CancellationToken cancellationToken = default); + + /// + /// Selects the authenticator to unlock the user's account + /// + /// The options. + /// The IDX context. + /// The cancellation token. + /// The authentication response. + Task SelectUnlockAccountAuthenticatorAsync(UnlockAccountOptions unlockAccountOptions, IIdxContext idxContext, CancellationToken cancellationToken = default); + /// /// Gets available identity providers. /// diff --git a/src/Okta.Idx.Sdk/IdxClient.cs b/src/Okta.Idx.Sdk/IdxClient.cs index 68619675..82c0728d 100644 --- a/src/Okta.Idx.Sdk/IdxClient.cs +++ b/src/Okta.Idx.Sdk/IdxClient.cs @@ -1187,6 +1187,14 @@ private async Task VerifyAuthenticatorAsync(IdxRequestPa { currentRemediationType = RemediationType.SelectAuthenticatorEnroll; } + //// If terminal state due to successful unlock account + //if (introspectResponse.IdxMessages?.Messages?.FirstOrDefault(x => x.I18n.Key == MessagesType.SelfServiceUnlockUserSuccess) != null) + //{ + // return new AuthenticationResponse + // { + // AuthenticationStatus = AuthenticationStatus.UnlockAccountSuccess, + // }; + //} else { if (currentRemediationType == RemediationType.EnrollAuthenticator && @@ -1289,11 +1297,21 @@ private async Task VerifyAuthenticatorAsync(IdxRequestPa }; } + // If terminal state due to successful unlock account + if (challengeAuthenticatorResponse.IdxMessages?.Messages?.FirstOrDefault(x => x.I18n.Key == MessagesType.SelfServiceUnlockUserSuccess) != null) + { + return new AuthenticationResponse + { + AuthenticationStatus = AuthenticationStatus.UnlockAccountSuccess, + }; + } + throw new UnexpectedRemediationException( new List { RemediationType.ResetAuthenticator, RemediationType.SelectAuthenticatorEnroll, + RemediationType.UnlockAccountSuccess, }, challengeAuthenticatorResponse); } @@ -1902,5 +1920,77 @@ public async Task PollAuthenticatorPushStatusAsync(IIdxContext idx }, challengeResponse); } + + public async Task UnlockAccountAsync(CancellationToken cancellationToken = default) + { + var idxContext = await InteractAsync(cancellationToken: cancellationToken); + var introspectResponse = await IntrospectAsync(idxContext, cancellationToken); + + var unlockAccountRemediation = introspectResponse.FindRemediationOption(RemediationType.UnlockAccount, true); + + var idxRequestPayload = new IdxRequestPayload + { + StateHandle = introspectResponse.StateHandle, + }; + + var unlockAccountResponse = await unlockAccountRemediation.ProceedAsync(idxRequestPayload, cancellationToken); + + if (unlockAccountResponse.ContainsRemediationOption(RemediationType.SelectAuthenticatorUnlockAccount)) + { + return new AuthenticationResponse + { + IdxContext = idxContext, + AuthenticationStatus = AuthenticationStatus.AwaitingAuthenticatorSelection, + Authenticators = IdxResponseHelper.ConvertToAuthenticators(unlockAccountResponse.Authenticators.Value, unlockAccountResponse.AuthenticatorEnrollments.Value), + }; + } + + throw new UnexpectedRemediationException(RemediationType.SelectAuthenticatorUnlockAccount, + unlockAccountResponse); + } + + public async Task SelectUnlockAccountAuthenticatorAsync(UnlockAccountOptions unlockAccountOptions, IIdxContext idxContext, CancellationToken cancellationToken = default) + { + var introspectResponse = await IntrospectAsync(idxContext, cancellationToken); + + var idxRequestPayload = new IdxRequestPayload + { + StateHandle = introspectResponse.StateHandle, + }; + + idxRequestPayload.SetProperty("identifier", unlockAccountOptions.Username); + idxRequestPayload.SetProperty("authenticator", new + { + id = unlockAccountOptions.AuthenticatorId, + }); + + var selectAuthenticatorUnlockAccountRemediation = introspectResponse.FindRemediationOption(RemediationType.SelectAuthenticatorUnlockAccount, true); + + var selectAuthenticatorResponse = await selectAuthenticatorUnlockAccountRemediation.ProceedAsync(idxRequestPayload, cancellationToken); + + // WebAuthN enrollment data is available in authenticatorSelectionResponse.CurrentAuthenticator instead of authenticatorSelectionResponse.CurrentAuthenticatorEnrollment unlike other authenticators + var currentAuthenticatorEnrollment = + selectAuthenticatorResponse.CurrentAuthenticatorEnrollment?.Value ?? + selectAuthenticatorResponse.CurrentAuthenticator?.Value; + + if (selectAuthenticatorResponse.ContainsRemediationOption(RemediationType.AuthenticatorVerificationData)) + { + return new AuthenticationResponse + { + IdxContext = idxContext, + AuthenticationStatus = AuthenticationStatus.AwaitingChallengeAuthenticatorData, + CurrentAuthenticatorEnrollment = IdxResponseHelper.ConvertToAuthenticator(selectAuthenticatorResponse.Authenticators.Value, currentAuthenticatorEnrollment, selectAuthenticatorResponse.AuthenticatorEnrollments.Value), + }; + } + else //(authenticatorSelectionResponse.ContainsRemediationOption(RemediationType.ChallengeAuthenticator)) + { + return new AuthenticationResponse + { + IdxContext = idxContext, + AuthenticationStatus = AuthenticationStatus.AwaitingAuthenticatorVerification, + CurrentAuthenticatorEnrollment = IdxResponseHelper.ConvertToAuthenticator(selectAuthenticatorResponse.Authenticators.Value, currentAuthenticatorEnrollment, selectAuthenticatorResponse.AuthenticatorEnrollments?.Value), + }; + } + } } } diff --git a/src/Okta.Idx.Sdk/IdxMessages.cs b/src/Okta.Idx.Sdk/IdxMessages.cs index d0e06507..6bf7d28f 100644 --- a/src/Okta.Idx.Sdk/IdxMessages.cs +++ b/src/Okta.Idx.Sdk/IdxMessages.cs @@ -1,19 +1,19 @@ -// -// Copyright (c) 2020 - present Okta, Inc. All rights reserved. -// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -// - -using System.Collections.Generic; - -namespace Okta.Idx.Sdk -{ +// +// Copyright (c) 2020 - present Okta, Inc. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Okta.Idx.Sdk +{ /// /// Idx Messages type - /// - public class IdxMessages : Resource, IIdxMessages - { - public string Type => GetStringProperty("type"); - - public IList Messages => GetArrayProperty("value"); - } -} + /// + public class IdxMessages : Resource, IIdxMessages + { + public string Type => GetStringProperty("type"); + + public IList Messages => GetArrayProperty("value"); + } +} diff --git a/src/Okta.Idx.Sdk/MessagesType.cs b/src/Okta.Idx.Sdk/MessagesType.cs new file mode 100644 index 00000000..dccd59de --- /dev/null +++ b/src/Okta.Idx.Sdk/MessagesType.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2020 - present Okta, Inc. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Okta.Idx.Sdk +{ + public class MessagesType + { + public static readonly string SelfServiceUnlockUserSuccess = "oie.selfservice.unlock_user.success.message"; + } +} diff --git a/src/Okta.Idx.Sdk/RemediationType.cs b/src/Okta.Idx.Sdk/RemediationType.cs index 1b5c047a..b924bc42 100644 --- a/src/Okta.Idx.Sdk/RemediationType.cs +++ b/src/Okta.Idx.Sdk/RemediationType.cs @@ -109,5 +109,20 @@ public static class RemediationType /// This is not a remediation itself, but it's used internally to identify unknown remediations. /// public static readonly string Unknown = "unknown"; + + /// + /// This is not a remediation itself, but it's used internally to identify successful unlock account. + /// + public static readonly string UnlockAccountSuccess = "unlock-account-success"; + + /// + /// unlock-account + /// + public static readonly string UnlockAccount = "unlock-account"; + + /// + /// select-authenticator-unlock-account + /// + public static readonly string SelectAuthenticatorUnlockAccount = "select-authenticator-unlock-account"; } } diff --git a/src/Okta.Idx.Sdk/UnlockAccountOptions.cs b/src/Okta.Idx.Sdk/UnlockAccountOptions.cs new file mode 100644 index 00000000..e597e07b --- /dev/null +++ b/src/Okta.Idx.Sdk/UnlockAccountOptions.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) 2020 - present Okta, Inc. All rights reserved. +// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Okta.Idx.Sdk +{ + public class UnlockAccountOptions + { + public string Username { get; set; } + + public string AuthenticatorId { get; set; } + } +} From f7fdd6e0fc8101dfd51d6fc37b429827973fbff8 Mon Sep 17 00:00:00 2001 From: Laura Rodriguez Date: Tue, 22 Mar 2022 14:24:10 -0400 Subject: [PATCH 3/4] Add e2e tests for scenario 11.1.3 --- .../11.1.3-UnlockAccountWithTotp.feature | 33 +++ .../11.1.3-UnlockAccountWithTotp.feature.cs | 203 ++++++++++++++++++ .../PageObjectModels/BasePage.cs | 1 + .../PageObjectModels/LoginPage.cs | 5 + .../PageObjectModels/UnlockAccountPage.cs | 33 +++ .../Steps/Pages/LoginPageSteps.cs | 23 ++ .../Steps/UnlockAccountWithTOTPSteps.cs | 94 ++++++++ .../embedded-auth-with-sdk.E2ETests.csproj | 7 + 8 files changed, 399 insertions(+) create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature.cs create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/UnlockAccountPage.cs create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature new file mode 100644 index 00000000..0c777d97 --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature @@ -0,0 +1,33 @@ +Feature: 11.1.3 - Unlock Account with TOTP + +Background: + Given a SPA, WEB APP or MOBILE Sign On Policy that defines Password as required + And Password Policy is set to Lock out user after 1 unsuccessful attempt + And the Password Policy Rule "Users can perform self-service" has "Unlock Account" checked + And the Password Policy Rule "Users can initiate Recovery with" has "Phone" and "Email" checked + And the Password Policy Rule "Additional Verification is" has "Not Required" checked + And a User named "Mary" exists, and this user has already setup email and password factors + #And Mary has entered an incorrect password to trigger an account lockout + + +Scenario: Mary recovers from a locked account with Email OTP + Given Mary navigates to the Basic Login View + And she has inserted her username + When she fills in her incorrect password + And she submits the Login form + Then she should see the message "Authentication failed" + #When she sees a link to unlock her account + When she clicks the link to unlock her account + Then she sees a page to input her user name and select Email, Phone, or Okta Verify to unlock her account + When she inputs her email + And she selects Email to unlock her account + #Then she should see a screen telling her to "Verify with your email" + Then she sees a page to input her code + #And she should see an input box for a code to enter from the email + When She inputs the correct code from the Email + #When she enters the OTP from her email in the original tab + #And she submits the verification form + Then she is redirected to the Basic Login View + And she should see the terminal message "Account Successfully Unlocked!" + #Then she should see a terminal page that says "Account Successfully Unlocked!" + #And she should see a link on the page to go back to the Basic Login View diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature.cs new file mode 100644 index 00000000..e2355ffb --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.1.3-UnlockAccountWithTotp.feature.cs @@ -0,0 +1,203 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (https://www.specflow.org/). +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace embedded_auth_with_sdk.E2ETests.Features +{ + using TechTalk.SpecFlow; + using System; + using System.Linq; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public partial class _11_1_3_UnlockAccountWithTOTPFeature : object, Xunit.IClassFixture<_11_1_3_UnlockAccountWithTOTPFeature.FixtureData>, System.IDisposable + { + + private static TechTalk.SpecFlow.ITestRunner testRunner; + + private string[] _featureTags = ((string[])(null)); + + private Xunit.Abstractions.ITestOutputHelper _testOutputHelper; + +#line 1 "11.1.3-UnlockAccountWithTotp.feature" +#line hidden + + public _11_1_3_UnlockAccountWithTOTPFeature(_11_1_3_UnlockAccountWithTOTPFeature.FixtureData fixtureData, embedded_auth_with_sdk_E2ETests_XUnitAssemblyFixture assemblyFixture, Xunit.Abstractions.ITestOutputHelper testOutputHelper) + { + this._testOutputHelper = testOutputHelper; + this.TestInitialize(); + } + + public static void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Features", "11.1.3 - Unlock Account with TOTP", null, ProgrammingLanguage.CSharp, ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + public static void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + public virtual void TestInitialize() + { + } + + public virtual void TestTearDown() + { + testRunner.OnScenarioEnd(); + } + + public virtual void ScenarioInitialize(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioInitialize(scenarioInfo); + testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(_testOutputHelper); + } + + public virtual void ScenarioStart() + { + testRunner.OnScenarioStart(); + } + + public virtual void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + public virtual void FeatureBackground() + { +#line 3 +#line hidden +#line 4 + testRunner.Given("a SPA, WEB APP or MOBILE Sign On Policy that defines Password as required", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line hidden +#line 5 + testRunner.And("Password Policy is set to Lock out user after 1 unsuccessful attempt", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 6 + testRunner.And("the Password Policy Rule \"Users can perform self-service\" has \"Unlock Account\" ch" + + "ecked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 7 + testRunner.And("the Password Policy Rule \"Users can initiate Recovery with\" has \"Phone\" and \"Emai" + + "l\" checked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 8 + testRunner.And("the Password Policy Rule \"Additional Verification is\" has \"Not Required\" checked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 9 + testRunner.And("a User named \"Mary\" exists, and this user has already setup email and password fa" + + "ctors", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden + } + + void System.IDisposable.Dispose() + { + this.TestTearDown(); + } + + [Xunit.SkippableFactAttribute(DisplayName="Mary recovers from a locked account with Email OTP")] + [Xunit.TraitAttribute("FeatureTitle", "11.1.3 - Unlock Account with TOTP")] + [Xunit.TraitAttribute("Description", "Mary recovers from a locked account with Email OTP")] + public virtual void MaryRecoversFromALockedAccountWithEmailOTP() + { + string[] tagsOfScenario = ((string[])(null)); + System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Mary recovers from a locked account with Email OTP", null, tagsOfScenario, argumentsOfScenario, this._featureTags); +#line 13 +this.ScenarioInitialize(scenarioInfo); +#line hidden + bool isScenarioIgnored = default(bool); + bool isFeatureIgnored = default(bool); + if ((tagsOfScenario != null)) + { + isScenarioIgnored = tagsOfScenario.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((this._featureTags != null)) + { + isFeatureIgnored = this._featureTags.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((isScenarioIgnored || isFeatureIgnored)) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 3 +this.FeatureBackground(); +#line hidden +#line 14 + testRunner.Given("Mary navigates to the Basic Login View", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line hidden +#line 15 + testRunner.And("she has inserted her username", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 16 + testRunner.When("she fills in her incorrect password", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 17 + testRunner.And("she submits the Login form", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 18 + testRunner.Then("she should see the message \"Authentication failed\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 20 + testRunner.When("she clicks the link to unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 21 + testRunner.Then("she sees a page to input her user name and select Email, Phone, or Okta Verify to" + + " unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 22 + testRunner.When("she inputs her email", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 23 + testRunner.And("she selects Email to unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 25 + testRunner.Then("she sees a page to input her code", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 27 + testRunner.When("She inputs the correct code from the Email", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 30 + testRunner.Then("she is redirected to the Basic Login View", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 31 + testRunner.And("she should see the terminal message \"Account Successfully Unlocked!\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden + } + this.ScenarioCleanup(); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class FixtureData : System.IDisposable + { + + public FixtureData() + { + _11_1_3_UnlockAccountWithTOTPFeature.FeatureSetup(); + } + + void System.IDisposable.Dispose() + { + _11_1_3_UnlockAccountWithTOTPFeature.FeatureTearDown(); + } + } + } +} +#pragma warning restore +#endregion diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/BasePage.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/BasePage.cs index 42d309cf..17c2942b 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/BasePage.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/BasePage.cs @@ -16,6 +16,7 @@ public abstract class BasePage public string FullPageUrl => $"{_baseUrl}/{RelativePageUri}"; public bool IsPageOpened => WaitForCondition(()=>_webDriver.Url.StartsWith(FullPageUrl)); public IWebElement ValidationErrors => _webDriver.FindElement(By.XPath("//div[@class=\"validation-summary-errors text-danger\"]")); + public BasePage(WebDriverDriver webDriverDriver, ITestConfiguration testConfiguration) { _webDriver = webDriverDriver.WebDriver; diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/LoginPage.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/LoginPage.cs index 8518e489..2b6b6c73 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/LoginPage.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/LoginPage.cs @@ -12,6 +12,9 @@ public LoginPage(WebDriverDriver webDriverDriver, ITestConfiguration testConfigu public override string RelativePageUri => "Account/Login"; public IWebElement LoginButton => _webDriver.FindElement(By.Id("LoginBtn")); public IWebElement ForgotPasswordButton => _webDriver.FindElement(By.Id("ForgotPasswordBtn")); + + public IWebElement UnlockAccountButton => _webDriver.FindElement(By.Id("UnlockAccountBtn")); + public IWebElement UserNameInput => _webDriver.FindElement(By.Id("UserName")); public IWebElement PasswordInput => _webDriver.FindElement(By.Id("Password")); @@ -19,6 +22,8 @@ public LoginPage(WebDriverDriver webDriverDriver, ITestConfiguration testConfigu public IWebElement GoogleIdpButton => _webDriver.FindElement(By.XPath("//input[contains(@value, \"Google\")]")); public IWebElement OktaIdpButton => _webDriver.FindElement(By.XPath("//input[contains(@value, \"Okta\")]")); + public IWebElement TerminalMessage => _webDriver.FindElement(By.Id("MessageToUser")); + public override void AssertPageOpenedAndValid() { base.AssertPageOpenedAndValid(); diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/UnlockAccountPage.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/UnlockAccountPage.cs new file mode 100644 index 00000000..f40e5a23 --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/UnlockAccountPage.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using embedded_auth_with_sdk.E2ETests.Drivers; +using FluentAssertions; +using OpenQA.Selenium; +using TechTalk.SpecFlow; + +namespace embedded_auth_with_sdk.E2ETests.PageObjectModels +{ + [Binding] + public class UnlockAccountPage : BasePage + { + public override string RelativePageUri => "Account/UnlockAccountAsync"; + + public UnlockAccountPage(WebDriverDriver webDriverDriver, ITestConfiguration testConfiguration) + : base(webDriverDriver, testConfiguration) + { } + + public IWebElement UserNameInput => _webDriver.FindElement(By.Id("UserName")); + public IWebElement EmailAuthenticator => _webDriver.FindElement(By.XPath("//label[contains(normalize-space(.),\"Email\")]")); + public IWebElement PhoneAuthenticator => _webDriver.FindElement(By.XPath("//label[contains(normalize-space(.),\"Phone\")]")); + public IWebElement SubmitButton => _webDriver.FindElement(By.XPath("//input[@type=\"submit\"]")); + + public override void AssertPageOpenedAndValid() + { + base.AssertPageOpenedAndValid(); + Title.Should().StartWith("Unlock"); + } + } +} diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/LoginPageSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/LoginPageSteps.cs index 85b5b509..15885ab4 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/LoginPageSteps.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/LoginPageSteps.cs @@ -79,5 +79,28 @@ public void WhenSheClicksTheOktaButton() { _loginPageModel.OktaIdpButton.Click(); } + + [When(@"she sees a link to unlock her account")] + public void WhenSheSeesALinkToUnlockHerAccount() + { + } + + [When(@"she clicks the link to unlock her account")] + public void WhenSheClicksTheLinkToUnlockHerAccount() + { + _loginPageModel.UnlockAccountButton.Click(); + } + + [Then(@"she is redirected to the Basic Login View")] + public void SheIsRedirectedToTheRootView() + { + _loginPageModel.AssertPageOpenedAndValid(); + } + + [Then(@"she should see the terminal message ""(.*)""")] + public void SheShouldSeeTheMessage(string terminalMessage) + { + _loginPageModel.TerminalMessage.Text.Should().Contain(terminalMessage); + } } } diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs new file mode 100644 index 00000000..4aa886a9 --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs @@ -0,0 +1,94 @@ +using System; +using embedded_auth_with_sdk.E2ETests.PageObjectModels; +using TechTalk.SpecFlow; + +namespace embedded_auth_with_sdk.E2ETests.Steps +{ + [Binding] + public class UnlockAccountWithTOTPSteps : BaseTestSteps + { + private UnlockAccountPage _unlockAccountPageModel; + public UnlockAccountWithTOTPSteps(ITestContext context, UnlockAccountPage unlockAccountPageModel) : base(context) + { + _unlockAccountPageModel = unlockAccountPageModel; + } + + [Given(@"Password Policy is set to Lock out user after (.*) unsuccessful attempt")] + public void GivenPasswordPolicyIsSetToLockOutUserAfterUnsuccessfulAttempt(int p0) + { + } + + [Given(@"the Password Policy Rule ""(.*)"" has ""(.*)"" checked")] + public void GivenThePasswordPolicyRuleHasChecked(string p0, string p1) + { + } + + //[Given(@"the Password Policy Rule ""(.*)"" has ""(.*)"" and ""(.*)"" checked")] + //public void GivenThePasswordPolicyRuleHasAndChecked(string p0, string p1, string p2) + //{ + //} + + [When(@"she inputs her email")] + public void WhenSheInputsHerEmail() + { + _unlockAccountPageModel.UserNameInput.SendKeys(_context.UserProfile.Email); + } + + [When(@"she selects Email to unlock her account")] + public void WhenSheSelectsEmail() + { + _unlockAccountPageModel.EmailAuthenticator.Click(); + _unlockAccountPageModel.SubmitButton.Click(); + } + + + [Then(@"she sees a page to input her user name and select Email, Phone, or Okta Verify to unlock her account")] + public void ThenSheSeesAPageToInputHerUserNameAndSelectEmailPhoneOrOktaVerifyToUnlockHerAccount() + { + _unlockAccountPageModel.AssertPageOpenedAndValid(); + } + + + //[When(@"she enters the OTP from her email in the original tab")] + //public void WhenSheEntersTheOTPFromHerEmailInTheOriginalTab() + //{ + // ScenarioContext.Current.Pending(); + //} + + //[When(@"submits the form")] + //public void WhenSubmitsTheForm() + //{ + // ScenarioContext.Current.Pending(); + //} + + //[Then(@"she sees a page to input her user name and select Email, Phone, or Okta Verify to unlock her account")] + //public void ThenSheSeesAPageToInputHerUserNameAndSelectEmailPhoneOrOktaVerifyToUnlockHerAccount() + //{ + // ScenarioContext.Current.Pending(); + //} + + //[Then(@"she should see a screen telling her to ""(.*)""")] + //public void ThenSheShouldSeeAScreenTellingHerTo(string p0) + //{ + // ScenarioContext.Current.Pending(); + //} + + //[Then(@"she should see an input box for a code to enter from the email")] + //public void ThenSheShouldSeeAnInputBoxForACodeToEnterFromTheEmail() + //{ + // ScenarioContext.Current.Pending(); + //} + + //[Then(@"she should see a terminal page that says ""(.*)""")] + //public void ThenSheShouldSeeATerminalPageThatSays(string p0) + //{ + // ScenarioContext.Current.Pending(); + //} + + //[Then(@"she should see a link on the page to go back to the Basic Login View")] + //public void ThenSheShouldSeeALinkOnThePageToGoBackToTheBasicLoginView() + //{ + // ScenarioContext.Current.Pending(); + //} + } +} diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj index bc89bcc3..e2b0e698 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj @@ -53,6 +53,9 @@ + + True + True @@ -65,6 +68,10 @@ + + SpecFlowSingleFileGenerator + 11.1.3-UnlockAccountWithTotp.feature.cs + SpecFlowSingleFileGenerator 5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs From e8fecdfea8be79b5c47a16194e7dceb33137fd23 Mon Sep 17 00:00:00 2001 From: Laura Rodriguez Date: Wed, 23 Mar 2022 15:51:18 -0400 Subject: [PATCH 4/4] Add e2e test to cover unlock account with MFA (phone). --- .../11.2-UnlockAccountWithMfa.feature | 33 +++ .../11.2-UnlockAccountWithMfa.feature.cs | 215 ++++++++++++++++++ ...lectUnlockAccountAuthenticatorAsyncPage.cs | 23 ++ .../BasicLoginWithPasswordFactorSteps.cs | 7 + .../Pages/SelectAuthenticatorPageSteps.cs | 13 +- .../Steps/UnlockAccountWithTOTPSteps.cs | 6 + .../embedded-auth-with-sdk.E2ETests.csproj | 7 + .../Views/Account/Login.cshtml | 6 +- 8 files changed, 306 insertions(+), 4 deletions(-) create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature.cs create mode 100644 samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/SelectUnlockAccountAuthenticatorAsyncPage.cs diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature new file mode 100644 index 00000000..056c50db --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature @@ -0,0 +1,33 @@ +Feature: 11.2.1 - Unlock Account with TOTP and SMS + +Background: + Given a SPA, WEB APP or MOBILE Sign On Policy that defines Password as required + And Password Policy is set to Lock out user after 1 unsuccessful attempt + And the Password Policy Rule "Users can perform self-service" has "Unlock Account" checked + And the Password Policy Rule "Users can initiate Recovery with" has "Phone" and "Email" checked + And the Password Policy Rule "Additional Verification is" has "Not Required" checked + And a User named "Mary" exists, and this user has already setup email, phone and password factors + #And Mary has entered an incorrect password to trigger an account lockout + + +Scenario: Mary recovers from a locked account with Email OTP + Given Mary navigates to the Basic Login View + And she has inserted her username + When she fills in her incorrect password + And she submits the Login form + Then she should see the message "Authentication failed" + #When she sees a link to unlock her account + When she clicks the link to unlock her account + Then she sees a page to input her user name and select Email, Phone, or Okta Verify to unlock her account + When she inputs her email + #And she selects Email to unlock her account + And She selects Phone from the list + Then she is presented with an option to select SMS to verify and unlock her account + When She selects SMS from the list + And She selects "Receive a Code" + Then the screen changes to receive an input for a code + When She inputs the correct code from the SMS + And She selects "Verify" + Then she is redirected to the Basic Login View + And she should see the terminal message "Account Successfully Unlocked!" + \ No newline at end of file diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature.cs new file mode 100644 index 00000000..b152953c --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Features/11.2-UnlockAccountWithMfa.feature.cs @@ -0,0 +1,215 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by SpecFlow (https://www.specflow.org/). +// SpecFlow Version:3.9.0.0 +// SpecFlow Generator Version:3.9.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ +#region Designer generated code +#pragma warning disable +namespace embedded_auth_with_sdk.E2ETests.Features +{ + using TechTalk.SpecFlow; + using System; + using System.Linq; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public partial class _11_2_1_UnlockAccountWithTOTPAndSMSFeature : object, Xunit.IClassFixture<_11_2_1_UnlockAccountWithTOTPAndSMSFeature.FixtureData>, System.IDisposable + { + + private static TechTalk.SpecFlow.ITestRunner testRunner; + + private string[] _featureTags = ((string[])(null)); + + private Xunit.Abstractions.ITestOutputHelper _testOutputHelper; + +#line 1 "11.2-UnlockAccountWithMfa.feature" +#line hidden + + public _11_2_1_UnlockAccountWithTOTPAndSMSFeature(_11_2_1_UnlockAccountWithTOTPAndSMSFeature.FixtureData fixtureData, embedded_auth_with_sdk_E2ETests_XUnitAssemblyFixture assemblyFixture, Xunit.Abstractions.ITestOutputHelper testOutputHelper) + { + this._testOutputHelper = testOutputHelper; + this.TestInitialize(); + } + + public static void FeatureSetup() + { + testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Features", "11.2.1 - Unlock Account with TOTP and SMS", null, ProgrammingLanguage.CSharp, ((string[])(null))); + testRunner.OnFeatureStart(featureInfo); + } + + public static void FeatureTearDown() + { + testRunner.OnFeatureEnd(); + testRunner = null; + } + + public virtual void TestInitialize() + { + } + + public virtual void TestTearDown() + { + testRunner.OnScenarioEnd(); + } + + public virtual void ScenarioInitialize(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) + { + testRunner.OnScenarioInitialize(scenarioInfo); + testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(_testOutputHelper); + } + + public virtual void ScenarioStart() + { + testRunner.OnScenarioStart(); + } + + public virtual void ScenarioCleanup() + { + testRunner.CollectScenarioErrors(); + } + + public virtual void FeatureBackground() + { +#line 3 +#line hidden +#line 4 + testRunner.Given("a SPA, WEB APP or MOBILE Sign On Policy that defines Password as required", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line hidden +#line 5 + testRunner.And("Password Policy is set to Lock out user after 1 unsuccessful attempt", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 6 + testRunner.And("the Password Policy Rule \"Users can perform self-service\" has \"Unlock Account\" ch" + + "ecked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 7 + testRunner.And("the Password Policy Rule \"Users can initiate Recovery with\" has \"Phone\" and \"Emai" + + "l\" checked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 8 + testRunner.And("the Password Policy Rule \"Additional Verification is\" has \"Not Required\" checked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 9 + testRunner.And("a User named \"Mary\" exists, and this user has already setup email, phone and pass" + + "word factors", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden + } + + void System.IDisposable.Dispose() + { + this.TestTearDown(); + } + + [Xunit.SkippableFactAttribute(DisplayName="Mary recovers from a locked account with Email OTP")] + [Xunit.TraitAttribute("FeatureTitle", "11.2.1 - Unlock Account with TOTP and SMS")] + [Xunit.TraitAttribute("Description", "Mary recovers from a locked account with Email OTP")] + public virtual void MaryRecoversFromALockedAccountWithEmailOTP() + { + string[] tagsOfScenario = ((string[])(null)); + System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); + TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Mary recovers from a locked account with Email OTP", null, tagsOfScenario, argumentsOfScenario, this._featureTags); +#line 13 +this.ScenarioInitialize(scenarioInfo); +#line hidden + bool isScenarioIgnored = default(bool); + bool isFeatureIgnored = default(bool); + if ((tagsOfScenario != null)) + { + isScenarioIgnored = tagsOfScenario.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((this._featureTags != null)) + { + isFeatureIgnored = this._featureTags.Where(__entry => __entry != null).Where(__entry => String.Equals(__entry, "ignore", StringComparison.CurrentCultureIgnoreCase)).Any(); + } + if ((isScenarioIgnored || isFeatureIgnored)) + { + testRunner.SkipScenario(); + } + else + { + this.ScenarioStart(); +#line 3 +this.FeatureBackground(); +#line hidden +#line 14 + testRunner.Given("Mary navigates to the Basic Login View", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line hidden +#line 15 + testRunner.And("she has inserted her username", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 16 + testRunner.When("she fills in her incorrect password", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 17 + testRunner.And("she submits the Login form", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 18 + testRunner.Then("she should see the message \"Authentication failed\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 20 + testRunner.When("she clicks the link to unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 21 + testRunner.Then("she sees a page to input her user name and select Email, Phone, or Okta Verify to" + + " unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 22 + testRunner.When("she inputs her email", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 24 + testRunner.And("She selects Phone from the list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 25 + testRunner.Then("she is presented with an option to select SMS to verify and unlock her account", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 26 + testRunner.When("She selects SMS from the list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 27 + testRunner.And("She selects \"Receive a Code\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 28 + testRunner.Then("the screen changes to receive an input for a code", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 29 + testRunner.When("She inputs the correct code from the SMS", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line hidden +#line 30 + testRunner.And("She selects \"Verify\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden +#line 31 + testRunner.Then("she is redirected to the Basic Login View", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); +#line hidden +#line 32 + testRunner.And("she should see the terminal message \"Account Successfully Unlocked!\"", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); +#line hidden + } + this.ScenarioCleanup(); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class FixtureData : System.IDisposable + { + + public FixtureData() + { + _11_2_1_UnlockAccountWithTOTPAndSMSFeature.FeatureSetup(); + } + + void System.IDisposable.Dispose() + { + _11_2_1_UnlockAccountWithTOTPAndSMSFeature.FeatureTearDown(); + } + } + } +} +#pragma warning restore +#endregion diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/SelectUnlockAccountAuthenticatorAsyncPage.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/SelectUnlockAccountAuthenticatorAsyncPage.cs new file mode 100644 index 00000000..080e63d2 --- /dev/null +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/PageObjectModels/SelectUnlockAccountAuthenticatorAsyncPage.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using embedded_auth_with_sdk.E2ETests.Drivers; +using OpenQA.Selenium; + +namespace embedded_auth_with_sdk.E2ETests.PageObjectModels +{ + public class SelectUnlockAccountAuthenticatorAsyncPage : BasePage + { + public override string RelativePageUri => "Manage/SelectUnlockAccountAuthenticatorAsync"; + public SelectUnlockAccountAuthenticatorAsyncPage(WebDriverDriver webDriverDriver, ITestConfiguration testConfiguration) + : base(webDriverDriver, testConfiguration) + { } + + public IWebElement SmsAuthenticator => _webDriver.FindElement(By.XPath("//label[contains(normalize-space(.),\"sms\")]")); + public IWebElement SubmitButton => _webDriver.FindElement(By.XPath("//input[@Value=\"Submit\"]")); + + public IWebElement PhoneAuthenticator => _webDriver.FindElement(By.XPath("//label[contains(normalize-space(.),\"Phone\")]")); + } +} diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/BasicLoginWithPasswordFactorSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/BasicLoginWithPasswordFactorSteps.cs index 60dd7fab..012b5229 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/BasicLoginWithPasswordFactorSteps.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/BasicLoginWithPasswordFactorSteps.cs @@ -21,5 +21,12 @@ public async Task GivenAUserNamedExistsAndThisUserHasAlreadySetupEmailAndPasswor { await _context.SetActivePasswordUserAsync(userName); } + + [Given(@"a User named ""(.*)"" exists, and this user has already setup email, phone and password factors")] + public async Task GivenAUserNamedExistsAndThisUserHasAlreadySetupEmailAndPhoneAndPasswordFactors(string userName) + { + await _context.SetActivePasswordAndSmsUserAsync(userName); + await _context.EnrollPhoneAuthenticator(); + } } } diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs index f8f4abdc..df56c7a2 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/Pages/SelectAuthenticatorPageSteps.cs @@ -11,14 +11,16 @@ public class SelectAuthenticatorPageSteps : BaseTestSteps { private SelectAuthenticatorPage _selectAuthenticatorPageModel; private SelectAuthenticatorAsyncPage _selectAuthenticatorAsyncPageModel; + private SelectUnlockAccountAuthenticatorAsyncPage _selectUnlockAccountAuthenitcatorAsyncPageModel; public SelectAuthenticatorPageSteps(ITestContext context, SelectAuthenticatorPage selectAuthenticatorPageModel, - SelectAuthenticatorAsyncPage selectAuthenticatorAsyncPageModel) + SelectAuthenticatorAsyncPage selectAuthenticatorAsyncPageModel, SelectUnlockAccountAuthenticatorAsyncPage selectUnlockAccountAuthenitcatorAsyncPageModel) : base(context) { _selectAuthenticatorPageModel = selectAuthenticatorPageModel; _selectAuthenticatorAsyncPageModel = selectAuthenticatorAsyncPageModel; + _selectUnlockAccountAuthenitcatorAsyncPageModel = selectUnlockAccountAuthenitcatorAsyncPageModel; } [Then(@"She sees a list of factors")] @@ -66,6 +68,15 @@ public void ThenSheIsPresentedWithAnOptionToSelectSmsToVerify() _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Displayed.Should().BeTrue(); } + [Then(@"she is presented with an option to select SMS to verify and unlock her account")] + public void ThenSheIsPresentedWithAnOptionToSelectSmsToVerifyAndUnlockHerAccount() + { + _selectUnlockAccountAuthenitcatorAsyncPageModel.AssertPageOpenedAndValid(); + Func getSmsFactor = () => _selectAuthenticatorAsyncPageModel.SmsAuthenticator; + getSmsFactor.Should().NotThrow(); + _selectAuthenticatorAsyncPageModel.SmsAuthenticator.Displayed.Should().BeTrue(); + } + [Then(@"she is presented with an option to select Email to verify")] public void SheIsPresentedWithAnOptionToSelectEmailToVerify() { diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs index 4aa886a9..fcb65ac9 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/Steps/UnlockAccountWithTOTPSteps.cs @@ -48,6 +48,12 @@ public void ThenSheSeesAPageToInputHerUserNameAndSelectEmailPhoneOrOktaVerifyToU _unlockAccountPageModel.AssertPageOpenedAndValid(); } + [When(@"she selects Phone from the list")] + public void WhenSheSelectsPhone() + { + _unlockAccountPageModel.PhoneAuthenticator.Click(); + _unlockAccountPageModel.SubmitButton.Click(); + } //[When(@"she enters the OTP from her email in the original tab")] //public void WhenSheEntersTheOTPFromHerEmailInTheOriginalTab() diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj index e2b0e698..319bf20e 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj +++ b/samples/samples-aspnet/embedded-auth-with-sdk/Okta.Idx.Sdk.E2ETests/embedded-auth-with-sdk.E2ETests.csproj @@ -56,6 +56,9 @@ True + + True + True @@ -72,6 +75,10 @@ SpecFlowSingleFileGenerator 11.1.3-UnlockAccountWithTotp.feature.cs + + SpecFlowSingleFileGenerator + 11.2-UnlockAccountWithMfa.feature.cs + SpecFlowSingleFileGenerator 5.1-OktaOidcIdpSocialLoginWithPassword.feature.cs diff --git a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml index ce5ed93d..59ad4e82 100644 --- a/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml +++ b/samples/samples-aspnet/embedded-auth-with-sdk/embedded-auth-with-sdk/Views/Account/Login.cshtml @@ -11,7 +11,7 @@ @if(TempData["MessageToUser"]!=null) {
-

@TempData["MessageToUser"]

+

@TempData["MessageToUser"]


} @@ -69,9 +69,9 @@ @* Remove this section if you don't want or need social login buttons *@ -
+ @*
@Html.Partial("Idps", Model.IdpOptions) -
+
*@
@using (Html.BeginForm("Register", "Account", FormMethod.Get, new { @class = "form-horizontal", role = "form" }))