-
Notifications
You must be signed in to change notification settings - Fork 811
2FA article for Umbraco 15 #6821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ec98452
5739b08
2a7b678
be1471d
7bd56e0
946a259
e7a9864
bf58734
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,27 +6,41 @@ description: >- | |
|
|
||
| # Two-factor Authentication | ||
|
|
||
| Two-factor authentication (2FA) for Umbraco members is activated by implementing an `ITwoFactorProvider` interface and registering the implementation. The implementation can use third-party packages to archive for example support for authentication apps like Microsoft- or Google Authentication App. | ||
| This article includes guides for implementing two-factor authentication options for both backoffice users and website members: | ||
|
|
||
| * [Two-Factor Authentication for Members](#two-factor-authentication-for-members) | ||
| * [Two-Factor Authentication for Users](#two-factor-authentication-for-users) | ||
|
|
||
| Two-factor authentication (2FA) for Umbraco Users and Members is activated by implementing an `ITwoFactorProvider` interface and registering the implementation. The implementation can use third-party packages to support authentication apps like the Microsoft- or Google Authentication Apps. | ||
|
|
||
| {% hint style="info" %} | ||
| If you are using [Umbraco Cloud](https://umbraco.com/products/umbraco-cloud/), you can enable multi-factor authentication in Umbraco ID. For more information, see the [Multi-Factor Authentication](https://docs.umbraco.com/umbraco-cloud/set-up/multi-factor-authentication-on-cloud) article. | ||
| {% endhint %} | ||
|
|
||
| ## Two-factor authentication for Members | ||
|
|
||
| Since Umbraco does not control how the UI is for member login and profile edit. The UI for 2FA is shipped as part of the Partial View snippets. These can be used as a starting point, before styling the page as you would like. | ||
| The following guide will take you through implementing an option for your website members to enable two-factor authentication. | ||
|
|
||
| {% hint style="info" %} | ||
| A setup for members needs to be implemented on your website in order for you to follow this guide. This setup should include: | ||
|
|
||
| * Login and logout options. | ||
| * Public access restriction configured on at least 1 content item. | ||
|
|
||
| ### Example implementation for Authenticator Apps for Members | ||
| [Learn more about setting up a members section in Umbraco.](../../tutorials/members-registration-and-login.md) | ||
| {% endhint %} | ||
|
|
||
| In the following example, we will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). | ||
| As an example, the guide will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). This package works for both Google and Microsoft authenticator apps. It can be used to generate the QR code needed to activate the app for the website. | ||
|
|
||
| Despite the name, this package works for both Google and Microsoft authenticator apps. It can be used to generate the QR code needed to activate the app for the website. | ||
| 1. Install the GoogleAuthenticator Nuget Package on your project. | ||
| 2. Create a new file in your project: `UmbracoAppAuthenticator.cs`. | ||
| 3. Update the file with the following code snippet. | ||
|
|
||
| {% code title="UmbracoAppAuthenticator.cs" lineNumbers="true" %} | ||
|
|
||
| ```csharp | ||
| using System; | ||
| using System.Threading.Tasks; | ||
| using Google.Authenticator; | ||
| using System.Runtime.Serialization; | ||
| using Umbraco.Cms.Core.Security; | ||
| using Umbraco.Cms.Core.Services; | ||
|
|
||
|
|
@@ -35,17 +49,19 @@ namespace My.Website; | |
| /// <summary> | ||
| /// Model with the required data to setup the authentication app. | ||
| /// </summary> | ||
| public class QrCodeSetupData | ||
|
|
||
| [DataContract] | ||
| public class QrCodeSetupData : ISetupTwoFactorModel | ||
| { | ||
| /// <summary> | ||
| /// The secret unique code for the user and this ITwoFactorProvider. | ||
| /// </summary> | ||
| public string Secret { get; init; } | ||
| public string? Secret { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// The SetupCode from the GoogleAuthenticator code. | ||
| /// </summary> | ||
| public SetupCode SetupCode { get; init; } | ||
| public SetupCode? SetupCode { get; init; } | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -82,13 +98,14 @@ public class UmbracoAppAuthenticator : ITwoFactorProvider | |
| /// <param name="userOrMemberKey">The key of the user or member</param> | ||
| /// <param name="secret">The secret that ensures only this user can connect to the authenticator app</param> | ||
| /// <returns>The required data to setup the authenticator app</returns> | ||
| public Task<object> GetSetupDataAsync(Guid userOrMemberKey, string secret) | ||
| public Task<ISetupTwoFactorModel> GetSetupDataAsync(Guid userOrMemberKey, string secret) | ||
| { | ||
| var member = _memberService.GetByKey(userOrMemberKey); | ||
|
|
||
| var applicationName = "testingOn15"; | ||
| var twoFactorAuthenticator = new TwoFactorAuthenticator(); | ||
| SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode("My application name", member.Username, secret, false); | ||
| return Task.FromResult<object>(new QrCodeSetupData() | ||
| SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode(applicationName, member.Username, secret, false); | ||
| return Task.FromResult<ISetupTwoFactorModel>(new QrCodeSetupData() | ||
| { | ||
| SetupCode = setupInfo, | ||
| Secret = secret | ||
|
|
@@ -111,13 +128,15 @@ public class UmbracoAppAuthenticator : ITwoFactorProvider | |
| public bool ValidateTwoFactorSetup(string secret, string token) => ValidateTwoFactorPIN(secret, token); | ||
| } | ||
| ``` | ||
| {% endcode %} | ||
|
|
||
| First, we create a model with the information required to set up the 2FA provider. Then we implement the `ITwoFactorProvider` with the use of the `TwoFactorAuthenticator` from the GoogleAuthenticator NuGet package. | ||
| {% endcode %} | ||
|
|
||
| Now we need to register the `UmbracoAppAuthenticator` implementation. This can be done on the `IUmbracoBuilder` in your startup or a composer. | ||
| 4. Update `namespace` on line 7 to match your project. | ||
| 5. Customize the `applicationName` variable on line 64. | ||
| 6. Create a Composer and register the `UmbracoAppAuthenticator` implementation as shown below. | ||
|
|
||
| {% code title="UmbracoAppAuthenticatorComposer.cs" lineNumbers="true" %} | ||
|
|
||
| ```csharp | ||
| using Umbraco.Cms.Core.Composing; | ||
| using Umbraco.Cms.Core.DependencyInjection; | ||
|
|
@@ -134,15 +153,28 @@ public class UmbracoAppAuthenticatorComposer : IComposer | |
| } | ||
| } | ||
| ``` | ||
|
|
||
| {% endcode %} | ||
|
|
||
| At this point, the 2FA is active, but no members have set up 2FA yet. The setup of 2FA depends on the type. In the case of App Authenticator, we will add the following to our **view** showing the edit profile of the member. | ||
| At this point, the 2FA is active, but no members have set up 2FA yet. The setup of 2FA depends on the type. In the case of App Authenticator, the **view** showing the option to edit member profiles needs to be modified. | ||
|
|
||
| {% hint style="info" %} | ||
| If you already have a members-only page with the edit profile options, you can skip directly to step 8. | ||
| {% endhint %} | ||
|
|
||
| 7. Add or choose a members-only page that should have the two-factor authentication setup. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should step 7 be moved above the para or at the end of step 11? Currently, the para says " add the following to the view showing the edit profile of the member." then point 7 and then the code of the para which is confusing. Does it make sense what I am trying to say? 🤞😅
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the paragraph, and added a hint about how you can skip a step if you already have a page set up of editing member profiles.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eshanrnh - let me know if it makes sense.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good to me. |
||
| * The page needs to be behind the public access. | ||
| * The page should **not** be using strongly types models. | ||
| 8. Open the view file for the selected page. | ||
| 9. Add the following code: | ||
|
|
||
| {% code title="ExampleMemberPage.cshtml" lineNumbers="true" %} | ||
|
|
||
| ```csharp | ||
| @using Umbraco.Cms.Core.Services | ||
| @using Umbraco.Cms.Web.Website.Controllers | ||
| @using Umbraco.Cms.Web.Website.Models | ||
| @using My.Website @* Or whatever your namespace with the QrCodeSetupData model is *@ | ||
| @using Umbraco.Cms.Core.Services; | ||
| @using Umbraco.Cms.Web.Website.Controllers; | ||
| @using Umbraco.Cms.Web.Website.Models; | ||
| @using My.Website; | ||
| @inject MemberModelBuilderFactory memberModelBuilderFactory | ||
| @inject ITwoFactorLoginService twoFactorLoginService | ||
| @{ | ||
|
|
@@ -159,6 +191,9 @@ At this point, the 2FA is active, but no members have set up 2FA yet. The setup | |
| foreach (var providerName in providerNames) | ||
| { | ||
| var setupData = await twoFactorLoginService.GetSetupInfoAsync(profileModel.Key, providerName); | ||
|
|
||
| // If the `setupData` is `null` for the specified `providerName` it means the provider is already set up. | ||
| // In this case, a button to disable the authentication is shown. | ||
| if (setupData is null) | ||
| { | ||
| @using (Html.BeginUmbracoForm<UmbTwoFactorLoginController>(nameof(UmbTwoFactorLoginController.Disable))) | ||
|
|
@@ -167,6 +202,7 @@ At this point, the 2FA is active, but no members have set up 2FA yet. The setup | |
| <button type="submit">Disable @providerName</button> | ||
| } | ||
| } | ||
| // If `setupData` is not `null` the type is checked and the UI for how to set up the App Authenticator is shown. | ||
| else if(setupData is QrCodeSetupData qrCodeSetupData) | ||
| { | ||
| @using (Html.BeginUmbracoForm<UmbTwoFactorLoginController>(nameof(UmbTwoFactorLoginController.ValidateAndSaveSetup))) | ||
|
|
@@ -185,25 +221,45 @@ At this point, the 2FA is active, but no members have set up 2FA yet. The setup | |
| } | ||
| ``` | ||
|
|
||
| In this razor-code sample, we get the current member's unique key and list all registered `ITwoFactorProvider` implementations. | ||
| {% endcode %} | ||
|
|
||
| 10. Update the `@using` in line 4 to match the namespace of your project. | ||
| 11. [Optional] Customize the text fields and buttons to match your websites tone of voice (lines 33-39). | ||
|
|
||
|  | ||
|
|
||
| ### Test the set up for Members | ||
|
|
||
| If the `setupData` is `null` for the specified `providerName` it means the provider is already set up. In this case, we show a disable button. Otherwise, we check the type and show the UI for how to set up the App Authenticator. We will show the QR Code and an input field to validate the code from the App Authenticator. | ||
| 1. Login to the website using a test member. | ||
| 2. Navigate to the page where the QR code was added. | ||
| 3. Scan the QR code and add the verification code. | ||
| 4. Logout of the website. | ||
| 5. Login and verify that it asks for the two factor authentication. | ||
|
|
||
| The last part required is to use the `Login` Partial View snippet. | ||
| You can also check that the **Two-factor Authentication** option is checked on the member in the Umbraco backoffice. | ||
|
|
||
|  | ||
|
|
||
| ### Notification when 2FA is requested for a member | ||
|
|
||
| When a 2FA login is requested for a member, the `MemberTwoFactorRequestedNotification` is published. This notification can also be used to send the member a one-time password via e-mail or phone. Even though these 2FA types are [not considered secure](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/mfa?view=aspnetcore-6.0#mfa-sms) as App Authentication, it is still a massive improvement compared to no 2FA. | ||
|
|
||
| ## Two-factor authentication for Users | ||
|
|
||
| Umbraco controls how the UI is for user login and user edits, but will still need a view for configuring each 2FA provider. | ||
| The following guide will take you through implementing an option for backoffice users to enable two-factor authentication. | ||
|
|
||
| This guide will not cover setting up the UI for user login and edits as this is handled elsewhere in the CMS. | ||
|
|
||
| ### Example implementation for Authenticator Apps for Users | ||
|
|
||
| In the following example, we will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). Despite the name, this package works for both Google and Microsoft authenticator apps. It can be used to generate the QR code needed to activate the app for the website. | ||
| As an example, the guide will use the [GoogleAuthenticator NuGet Package](https://www.nuget.org/packages/GoogleAuthenticator/). This package works for both Google and Microsoft authenticator apps. It can be used to generate the QR code needed to activate the app for the website. | ||
|
|
||
| 1. Install the GoogleAuthenticator Nuget Package on your project. | ||
| 2. Create a new file in your project: `UmbracoUserAppAuthenticator.cs`. | ||
| 3. Update the file with the following code snippet. | ||
|
|
||
| {% code title="UmbracoUserAppAuthenticator.cs" lineNumbers="true" %} | ||
|
|
||
| {% code title="TwoFactorAuthInfo.cs" lineNumbers="true" %} | ||
| ```csharp | ||
| using System.Runtime.Serialization; | ||
| using Google.Authenticator; | ||
|
|
@@ -263,8 +319,9 @@ public class UmbracoUserAppAuthenticator : ITwoFactorProvider | |
|
|
||
| ArgumentNullException.ThrowIfNull(user); | ||
|
|
||
| var applicationName = "My application name"; | ||
| var twoFactorAuthenticator = new TwoFactorAuthenticator(); | ||
| SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode("My application name", user.Username, secret, false); | ||
| SetupCode setupInfo = twoFactorAuthenticator.GenerateSetupCode(applicationName, user.Username, secret, false); | ||
| return Task.FromResult<ISetupTwoFactorModel>(new TwoFactorAuthInfo() | ||
| { | ||
| QrCodeSetupImageUrl = setupInfo.QrCodeSetupImageUrl, | ||
|
|
@@ -288,20 +345,23 @@ public class UmbracoUserAppAuthenticator : ITwoFactorProvider | |
| public bool ValidateTwoFactorSetup(string secret, string token) => ValidateTwoFactorPIN(secret, token); | ||
| } | ||
| ``` | ||
|
|
||
| {% endcode %} | ||
|
|
||
| First, we create a model with the information required to set up the 2FA provider. Then we implement the `ITwoFactorProvider` with the use of the `TwoFactorAuthenticator` from the GoogleAuthenticator NuGet package. | ||
| 4. Update `namespace` on line 7 to match your project. | ||
| 5. Customize the `applicationName` variable on line 59. | ||
| 6. Create a new file in your project: `UmbracoUserAppAuthenticatorComposer.cs`. | ||
| 7. Implement a new composer and register the `UmbracoUserAppAuthenticator` implementation as shown below. | ||
|
|
||
| Now we need to register the `UmbracoUserAppAuthenticator` implementation and the view to show to set up this provider. This can be done on the `IUmbracoBuilder` in your startup or a composer. | ||
| {% code title="UmbracoUserAppAuthenticatorComposer.cs" lineNumbers="true" %} | ||
|
|
||
| {% code title="UmbracoAppAuthenticatorComposer.cs" lineNumbers="true" %} | ||
| ```csharp | ||
| using Umbraco.Cms.Core.Composing; | ||
| using Umbraco.Cms.Core.Security; | ||
|
|
||
| namespace My.Website; | ||
|
|
||
| public class UmbracoAppAuthenticatorComposer : IComposer | ||
| public class UmbracoUserAppAuthenticatorComposer : IComposer | ||
| { | ||
| public void Compose(IUmbracoBuilder builder) | ||
| { | ||
|
|
@@ -311,11 +371,18 @@ public class UmbracoAppAuthenticatorComposer : IComposer | |
| } | ||
| } | ||
| ``` | ||
|
|
||
| {% endcode %} | ||
|
|
||
| The last thing required is to register the provider in the Backoffice client so that the user can enable it. This can be done in a `umbraco-package.json` file. | ||
| 8. Update the `namespace` on line 4 to match your project. | ||
|
|
||
| With the 2FA in place, the provider needs to be registered in the backoffice client so the user can use it. | ||
|
|
||
| 9. Add a new file to your project directory: `~/App_Plugins/TwoFactorProviders/umbraco-package.json`. | ||
| 10. Add the following code to the new file: | ||
|
|
||
| {% code title="~/App_Plugins/TwoFactorProviders/umbraco-package.json" lineNumbers="true" %} | ||
|
|
||
| ```json | ||
| { | ||
| "$schema": "../../umbraco-package-schema.json", | ||
|
|
@@ -334,27 +401,35 @@ The last thing required is to register the provider in the Backoffice client so | |
| ] | ||
| } | ||
| ``` | ||
|
|
||
| {% endcode %} | ||
|
|
||
| At this point, the 2FA is active, but no users have set up 2FA yet. | ||
|
|
||
| * Each user can now enable the configured 2fa providers on their user. This can be done from the user panel by clicking the user avatar. | ||
| ### Test the set up for Users | ||
|
|
||
| Each user can now enable the configured 2FA providers on their user. | ||
|
|
||
| 1. Access the Umbraco backoffice. | ||
| 2. Click the user avatar in the top-right corner. | ||
|
|
||
|  | ||
|
|
||
| * When clicking the `Configure Two-Factor` button, a new panel is shown, listing all enabled two-factor providers. | ||
| 3. Select `Configure Two-Factor` button to get a list of all enabled two-factor providers. | ||
|
|
||
|  | ||
|
|
||
| * When clicking `Enable` on one of these, the configured view for the specific provider will be shown | ||
| 4. Select `Enable` to show the configured view. | ||
|
|
||
|  | ||
|
|
||
| * When the authenticator is enabled correctly, a disable button is shown instead. | ||
| 5. Follow the instructions to configure 2FA. | ||
|
|
||
| When the authenticator is enabled correctly, a disable button is shown instead. | ||
|
|
||
|  | ||
|
|
||
| * To disable the two-factor authentication on your user, it is required to enter the verification code. Otherwise, admins are allowed to disable providers on other users. | ||
| To disable the two-factor authentication on your user, it is required to enter the verification code. | ||
|
|
||
|  | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.