Block enabled 2fa in the UI without cookie consent (#2035)
* Block enabled 2fa in the UI without cookie consent * Guard against feature not being there * Set up tweak * Fix
This commit is contained in:
parent
9405d058fa
commit
da9318f431
|
|
@ -1,4 +1,5 @@
|
||||||
@page
|
@page
|
||||||
|
@using Microsoft.AspNetCore.Http.Features
|
||||||
@model TwoFactorAuthenticationModel
|
@model TwoFactorAuthenticationModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Two-factor authentication (2FA)";
|
ViewData["Title"] = "Two-factor authentication (2FA)";
|
||||||
|
|
@ -7,50 +8,64 @@
|
||||||
|
|
||||||
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
<partial name="_StatusMessage" model="Model.StatusMessage" />
|
||||||
<h4>@ViewData["Title"]</h4>
|
<h4>@ViewData["Title"]</h4>
|
||||||
@if (Model.Is2faEnabled)
|
@{
|
||||||
{
|
var consentFeature = HttpContext.Features.Get<ITrackingConsentFeature>();
|
||||||
if (Model.RecoveryCodesLeft == 0)
|
@if (consentFeature?.CanTrack ?? true)
|
||||||
|
{
|
||||||
|
@if (Model.Is2faEnabled)
|
||||||
|
{
|
||||||
|
if (Model.RecoveryCodesLeft == 0)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>You have no recovery codes left.</strong>
|
||||||
|
<p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Model.RecoveryCodesLeft == 1)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>You have 1 recovery code left.</strong>
|
||||||
|
<p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Model.RecoveryCodesLeft <= 3)
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong>
|
||||||
|
<p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Model.IsMachineRemembered)
|
||||||
|
{
|
||||||
|
<form method="post" style="display: inline-block">
|
||||||
|
<button type="submit" class="btn btn-default">Forget this browser</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
<a asp-page="./Disable2fa" class="btn btn-default">Disable 2FA</a>
|
||||||
|
<a asp-page="./GenerateRecoveryCodes" class="btn btn-default">Reset recovery codes</a>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h5>Authenticator app</h5>
|
||||||
|
@if (!Model.HasAuthenticator)
|
||||||
|
{
|
||||||
|
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-default">Add authenticator app</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-default">Set up authenticator app</a>
|
||||||
|
<a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-default">Reset authenticator app</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<strong>You have no recovery codes left.</strong>
|
<strong>Privacy and cookie policy have not been accepted.</strong>
|
||||||
<p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
|
<p>You must accept the policy before you can enable two factor authentication.</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else if (Model.RecoveryCodesLeft == 1)
|
|
||||||
{
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<strong>You have 1 recovery code left.</strong>
|
|
||||||
<p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else if (Model.RecoveryCodesLeft <= 3)
|
|
||||||
{
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong>
|
|
||||||
<p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Model.IsMachineRemembered)
|
|
||||||
{
|
|
||||||
<form method="post" style="display: inline-block">
|
|
||||||
<button type="submit" class="btn btn-default">Forget this browser</button>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
<a asp-page="./Disable2fa" class="btn btn-default">Disable 2FA</a>
|
|
||||||
<a asp-page="./GenerateRecoveryCodes" class="btn btn-default">Reset recovery codes</a>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<h5>Authenticator app</h5>
|
|
||||||
@if (!Model.HasAuthenticator)
|
|
||||||
{
|
|
||||||
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-default">Add authenticator app</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-default">Setup authenticator app</a>
|
|
||||||
<a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-default">Reset authenticator app</a>
|
|
||||||
}
|
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<partial name="_ValidationScriptsPartial" />
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
@page
|
@page
|
||||||
|
@using Microsoft.AspNetCore.Http.Features
|
||||||
@model TwoFactorAuthenticationModel
|
@model TwoFactorAuthenticationModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Two-factor authentication (2FA)";
|
ViewData["Title"] = "Two-factor authentication (2FA)";
|
||||||
|
|
@ -7,49 +8,62 @@
|
||||||
|
|
||||||
<partial name="_StatusMessage" for="StatusMessage" />
|
<partial name="_StatusMessage" for="StatusMessage" />
|
||||||
<h4>@ViewData["Title"]</h4>
|
<h4>@ViewData["Title"]</h4>
|
||||||
@if (Model.Is2faEnabled)
|
@{
|
||||||
{
|
var consentFeature = HttpContext.Features.Get<ITrackingConsentFeature>();
|
||||||
if (Model.RecoveryCodesLeft == 0)
|
@if (consentFeature?.CanTrack ?? true)
|
||||||
|
{
|
||||||
|
@if (Model.Is2faEnabled)
|
||||||
|
{
|
||||||
|
if (Model.RecoveryCodesLeft == 0)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>You have no recovery codes left.</strong>
|
||||||
|
<p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Model.RecoveryCodesLeft == 1)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>You have 1 recovery code left.</strong>
|
||||||
|
<p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Model.RecoveryCodesLeft <= 3)
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong>
|
||||||
|
<p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Model.IsMachineRemembered)
|
||||||
|
{
|
||||||
|
<form method="post" style="display: inline-block">
|
||||||
|
<button type="submit" class="btn btn-primary">Forget this browser</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
<a asp-page="./Disable2fa" class="btn btn-primary">Disable 2FA</a>
|
||||||
|
<a asp-page="./GenerateRecoveryCodes" class="btn btn-primary">Reset recovery codes</a>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h5>Authenticator app</h5>
|
||||||
|
@if (!Model.HasAuthenticator)
|
||||||
|
{
|
||||||
|
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Add authenticator app</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Set up authenticator app</a>
|
||||||
|
<a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-primary">Reset authenticator app</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<strong>You have no recovery codes left.</strong>
|
<strong>Privacy and cookie policy have not been accepted.</strong>
|
||||||
<p>You must <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a> before you can log in with a recovery code.</p>
|
<p>You must accept the policy before you can enable two factor authentication.</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else if (Model.RecoveryCodesLeft == 1)
|
|
||||||
{
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
<strong>You have 1 recovery code left.</strong>
|
|
||||||
<p>You can <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
else if (Model.RecoveryCodesLeft <= 3)
|
|
||||||
{
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<strong>You have @Model.RecoveryCodesLeft recovery codes left.</strong>
|
|
||||||
<p>You should <a asp-page="./GenerateRecoveryCodes">generate a new set of recovery codes</a>.</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Model.IsMachineRemembered)
|
|
||||||
{
|
|
||||||
<form method="post" style="display: inline-block">
|
|
||||||
<button type="submit" class="btn btn-primary">Forget this browser</button>
|
|
||||||
</form>
|
|
||||||
}
|
|
||||||
<a asp-page="./Disable2fa" class="btn btn-primary">Disable 2FA</a>
|
|
||||||
<a asp-page="./GenerateRecoveryCodes" class="btn btn-primary">Reset recovery codes</a>
|
|
||||||
}
|
|
||||||
|
|
||||||
<h5>Authenticator app</h5>
|
|
||||||
@if (!Model.HasAuthenticator)
|
|
||||||
{
|
|
||||||
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Add authenticator app</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<a id="enable-authenticator" asp-page="./EnableAuthenticator" class="btn btn-primary">Setup authenticator app</a>
|
|
||||||
<a id="reset-authenticator" asp-page="./ResetAuthenticator" class="btn btn-primary">Reset authenticator app</a>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
internal DefaultUIContext WithPasswordLogin() =>
|
internal DefaultUIContext WithPasswordLogin() =>
|
||||||
new DefaultUIContext(this) { PasswordLoginEnabled = true };
|
new DefaultUIContext(this) { PasswordLoginEnabled = true };
|
||||||
|
|
||||||
|
internal DefaultUIContext WithCookieConsent() =>
|
||||||
|
new DefaultUIContext(this) { CookiePolicyAccepted = true };
|
||||||
|
|
||||||
public string AuthenticatorKey
|
public string AuthenticatorKey
|
||||||
{
|
{
|
||||||
get => GetValue<string>(nameof(AuthenticatorKey));
|
get => GetValue<string>(nameof(AuthenticatorKey));
|
||||||
|
|
@ -84,5 +87,11 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
get => GetValue<bool>(nameof(PasswordLoginEnabled));
|
get => GetValue<bool>(nameof(PasswordLoginEnabled));
|
||||||
set => SetValue(nameof(PasswordLoginEnabled), value);
|
set => SetValue(nameof(PasswordLoginEnabled), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CookiePolicyAccepted
|
||||||
|
{
|
||||||
|
get => GetValue<bool>(nameof(CookiePolicyAccepted));
|
||||||
|
set => SetValue(nameof(CookiePolicyAccepted), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,23 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
await UserStories.EnableTwoFactorAuthentication(index);
|
Assert.NotNull(await UserStories.EnableTwoFactorAuthentication(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CannotEnableTwoFactorAuthenticationWithoutCookieConsent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var client = ServerFactory
|
||||||
|
.CreateClient();
|
||||||
|
|
||||||
|
var userName = $"{Guid.NewGuid()}@example.com";
|
||||||
|
var password = $"!Test.Password1$";
|
||||||
|
|
||||||
|
var index = await UserStories.RegisterNewUserAsync(client, userName, password);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.Null(await UserStories.EnableTwoFactorAuthentication(index, consent: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -241,6 +257,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
var twoFactorKey = showRecoveryCodes.Context.AuthenticatorKey;
|
var twoFactorKey = showRecoveryCodes.Context.AuthenticatorKey;
|
||||||
|
|
||||||
// Use a new client to simulate a new browser session.
|
// Use a new client to simulate a new browser session.
|
||||||
|
await UserStories.AcceptCookiePolicy(newClient);
|
||||||
var index = await UserStories.LoginExistingUser2FaAsync(newClient, userName, password, twoFactorKey);
|
var index = await UserStories.LoginExistingUser2FaAsync(newClient, userName, password, twoFactorKey);
|
||||||
await UserStories.ResetAuthenticator(index);
|
await UserStories.ResetAuthenticator(index);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,19 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TwoFactorAuthentication> ClickTwoFactorLinkAsync()
|
public async Task<TwoFactorAuthentication> ClickTwoFactorLinkAsync(bool consent = true)
|
||||||
{
|
{
|
||||||
|
// Accept cookie consent if requested
|
||||||
|
if (consent)
|
||||||
|
{
|
||||||
|
await UserStories.AcceptCookiePolicy(Client);
|
||||||
|
}
|
||||||
|
|
||||||
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
||||||
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
||||||
|
|
||||||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
var context = consent ? Context.WithCookieConsent() : Context;
|
||||||
|
return new TwoFactorAuthentication(Client, twoFactor, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TwoFactorAuthentication> ClickTwoFactorEnabledLinkAsync()
|
public async Task<TwoFactorAuthentication> ClickTwoFactorEnabledLinkAsync()
|
||||||
|
|
@ -60,6 +67,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||||
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
var goToTwoFactor = await Client.GetAsync(_twoFactorLink.Href);
|
||||||
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
var twoFactor = await ResponseAssert.IsHtmlDocumentAsync(goToTwoFactor);
|
||||||
Context.TwoFactorEnabled = true;
|
Context.TwoFactorEnabled = true;
|
||||||
|
Context.CookiePolicyAccepted = true;
|
||||||
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
return new TwoFactorAuthentication(Client, twoFactor, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,20 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests.Account.Manage
|
||||||
public TwoFactorAuthentication(HttpClient client, IHtmlDocument twoFactor, DefaultUIContext context)
|
public TwoFactorAuthentication(HttpClient client, IHtmlDocument twoFactor, DefaultUIContext context)
|
||||||
: base(client, twoFactor, context)
|
: base(client, twoFactor, context)
|
||||||
{
|
{
|
||||||
if (!Context.TwoFactorEnabled)
|
if (Context.CookiePolicyAccepted)
|
||||||
{
|
{
|
||||||
_enableAuthenticatorLink = HtmlAssert.HasLink("#enable-authenticator", twoFactor);
|
if (!Context.TwoFactorEnabled)
|
||||||
|
{
|
||||||
|
_enableAuthenticatorLink = HtmlAssert.HasLink("#enable-authenticator", twoFactor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_resetAuthenticatorLink = HtmlAssert.HasLink("#reset-authenticator", twoFactor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_resetAuthenticatorLink = HtmlAssert.HasLink("#reset-authenticator", twoFactor);
|
Assert.Contains("You must accept the policy before you can enable two factor authentication.", twoFactor.DocumentElement.TextContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
return await register.SubmitRegisterFormForValidUserAsync(userName, password);
|
return await register.SubmitRegisterFormForValidUserAsync(userName, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static async Task<Index> LoginExistingUserAsync(HttpClient client, string userName, string password)
|
internal static async Task<Index> LoginExistingUserAsync(HttpClient client, string userName, string password)
|
||||||
{
|
{
|
||||||
var index = await Index.CreateAsync(client);
|
var index = await Index.CreateAsync(client);
|
||||||
|
|
@ -105,12 +106,16 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
return await login2Fa.Send2FACodeAsync(twoFactorKey);
|
return await login2Fa.Send2FACodeAsync(twoFactorKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<ShowRecoveryCodes> EnableTwoFactorAuthentication(Index index)
|
internal static async Task<ShowRecoveryCodes> EnableTwoFactorAuthentication(Index index, bool consent = true)
|
||||||
{
|
{
|
||||||
var manage = await index.ClickManageLinkAsync();
|
var manage = await index.ClickManageLinkAsync();
|
||||||
var twoFactor = await manage.ClickTwoFactorLinkAsync();
|
var twoFactor = await manage.ClickTwoFactorLinkAsync(consent);
|
||||||
var enableAuthenticator = await twoFactor.ClickEnableAuthenticatorLinkAsync();
|
if (consent)
|
||||||
return await enableAuthenticator.SendValidCodeAsync();
|
{
|
||||||
|
var enableAuthenticator = await twoFactor.ClickEnableAuthenticatorLinkAsync();
|
||||||
|
return await enableAuthenticator.SendValidCodeAsync();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<ResetAuthenticator> ResetAuthenticator(Index index)
|
internal static async Task<ResetAuthenticator> ResetAuthenticator(Index index)
|
||||||
|
|
@ -219,5 +224,11 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||||
ResponseAssert.IsOK(download);
|
ResponseAssert.IsOK(download);
|
||||||
return JsonConvert.DeserializeObject<JObject>(await download.Content.ReadAsStringAsync());
|
return JsonConvert.DeserializeObject<JObject>(await download.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static async Task AcceptCookiePolicy(HttpClient client)
|
||||||
|
{
|
||||||
|
var goToPrivacy = await client.GetAsync("/Privacy");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
namespace Identity.DefaultUI.WebSite.Pages
|
namespace Identity.DefaultUI.WebSite.Pages
|
||||||
|
|
@ -9,6 +10,7 @@ namespace Identity.DefaultUI.WebSite.Pages
|
||||||
{
|
{
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
|
HttpContext.Features.Get<ITrackingConsentFeature>().GrantConsent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue