diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeController.cs
index 1336805045..cca2e7277f 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeController.cs
@@ -2,6 +2,7 @@
using Asp.Versioning;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
@@ -15,6 +16,7 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
+using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Cms.Web.Common.Security;
using Umbraco.Extensions;
using IdentitySignInResult = Microsoft.AspNetCore.Identity.SignInResult;
@@ -49,9 +51,9 @@ public class BackOfficeController : SecurityControllerBase
// FIXME: this is a temporary solution to get the new backoffice auth rolling.
// once the old backoffice auth is no longer necessary, clean this up and merge with 2FA handling etc.
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
[HttpPost("login")]
[MapToApiVersion("1.0")]
+ [Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
public async Task Login(LoginRequestModel model)
{
var validated = await _backOfficeUserManager.ValidateCredentialsAsync(model.Username, model.Password);
@@ -87,6 +89,7 @@ public class BackOfficeController : SecurityControllerBase
return Ok();
}
+ [AllowAnonymous]
[HttpPost("verify-2fa")]
[MapToApiVersion("1.0")]
public async Task Verify2FACode(Verify2FACodeModel model)
@@ -137,7 +140,7 @@ public class BackOfficeController : SecurityControllerBase
public required string Password { get; init; }
}
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
+ [AllowAnonymous]
[HttpGet("authorize")]
[MapToApiVersion("1.0")]
public async Task Authorize()
@@ -160,6 +163,7 @@ public class BackOfficeController : SecurityControllerBase
: await AuthorizeExternal(request);
}
+ [AllowAnonymous]
[HttpGet("signout")]
[MapToApiVersion("1.0")]
public async Task Signout()
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/ConfigurationSecurityController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/ConfigurationSecurityController.cs
index 92823e5dc6..cd9a1faf05 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/ConfigurationSecurityController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/ConfigurationSecurityController.cs
@@ -1,15 +1,12 @@
using Asp.Versioning;
-using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Security;
-using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.Security;
[ApiVersion("1.0")]
-[Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
// FIXME: Add requiring password reset token policy when its implemented
public class ConfigurationSecurityController : SecurityControllerBase
{
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordController.cs
index 87ee99ec1f..a068f5d33d 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordController.cs
@@ -7,11 +7,13 @@ using Umbraco.Cms.Api.Management.ViewModels.Security;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
+using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.Security;
[ApiVersion("1.0")]
// FIXME: Add requiring password reset token policy when its implemented
+[Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
public class ResetPasswordController : SecurityControllerBase
{
private readonly IUserService _userService;
@@ -21,7 +23,6 @@ public class ResetPasswordController : SecurityControllerBase
[HttpPost("forgot-password")]
[MapToApiVersion("1.0")]
- [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[UserPasswordEnsureMinimumResponseTime]
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs
index 57a733adc3..54d5e2dae6 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs
@@ -1,4 +1,5 @@
using Asp.Versioning;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
@@ -8,10 +9,12 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
+using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.Security;
[ApiVersion("1.0")]
+[Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
public class ResetPasswordTokenController : SecurityControllerBase
{
private readonly IUserService _userService;
@@ -20,7 +23,6 @@ public class ResetPasswordTokenController : SecurityControllerBase
[HttpPost("forgot-password/reset")]
[MapToApiVersion("1.0")]
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ProblemDetailsBuilder), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetailsBuilder), StatusCodes.Status404NotFound)]
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/SecurityControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/SecurityControllerBase.cs
index 5e447a424a..09b493c484 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/SecurityControllerBase.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/SecurityControllerBase.cs
@@ -1,16 +1,13 @@
-using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services.OperationStatus;
-using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.Security;
[VersionedApiBackOfficeRoute("security")]
[ApiExplorerSettings(GroupName = "Security")]
-[Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
public abstract class SecurityControllerBase : ManagementApiControllerBase
{
protected IActionResult UserOperationStatusResult(UserOperationStatus status, ErrorMessageResult? errorMessageResult = null) =>
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/VerifyResetPasswordTokenController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/VerifyResetPasswordTokenController.cs
index 0c432134e8..b4791de9a9 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Security/VerifyResetPasswordTokenController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/VerifyResetPasswordTokenController.cs
@@ -1,4 +1,5 @@
using Asp.Versioning;
+using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
@@ -17,9 +18,9 @@ public class VerifyResetPasswordTokenController : SecurityControllerBase
public VerifyResetPasswordTokenController(IUserService userService) => _userService = userService;
+ [AllowAnonymous]
[HttpPost("forgot-password/verify")]
[MapToApiVersion("1.0")]
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ProblemDetailsBuilder), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetailsBuilder), StatusCodes.Status404NotFound)]
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs b/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs
index e017b0c6a3..694d5d5735 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs
@@ -19,7 +19,6 @@ public class CreateInitialPasswordUserController : UserControllerBase
public CreateInitialPasswordUserController(IUserService userService) => _userService = userService;
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy on the . Keep it here for now and check FIXME in .
[HttpPost("invite/create-password")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
diff --git a/src/Umbraco.Cms.Api.Management/Controllers/User/VerifyInviteUserController.cs b/src/Umbraco.Cms.Api.Management/Controllers/User/VerifyInviteUserController.cs
index 0252712f4c..9e67cbc971 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/User/VerifyInviteUserController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/User/VerifyInviteUserController.cs
@@ -6,19 +6,17 @@ using Umbraco.Cms.Api.Management.ViewModels.User;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
-using Umbraco.Cms.Web.Common.Authorization;
namespace Umbraco.Cms.Api.Management.Controllers.User;
[ApiVersion("1.0")]
-[Authorize(Policy = AuthorizationPolicies.DenyLocalLoginIfConfigured)]
public class VerifyInviteUserController : UserControllerBase
{
private readonly IUserService _userService;
public VerifyInviteUserController(IUserService userService) => _userService = userService;
- // [AllowAnonymous] // This is handled implicitly by the NewDenyLocalLoginIfConfigured policy. Keep it here for now and check FIXME in .
+ [AllowAnonymous]
[HttpPost("invite/verify")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
diff --git a/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs b/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs
index e4969d9960..e57eb6c742 100644
--- a/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs
+++ b/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs
@@ -9,32 +9,25 @@ namespace Umbraco.Cms.Api.Management.Security.Authorization.DenyLocalLogin;
///
public class DenyLocalLoginHandler : MustSatisfyRequirementAuthorizationHandler
{
- // private readonly IBackOfficeExternalLoginProviders _externalLogins;
- //
- // ///
- // /// Initializes a new instance of the class.
- // ///
- // /// Provides access to instances.
- // public DenyLocalLoginHandler(IBackOfficeExternalLoginProviders externalLogins)
- // => _externalLogins = externalLogins;
- //
- // ///
- // protected override Task IsAuthorized(AuthorizationHandlerContext context, DenyLocalLoginRequirement requirement)
- // => Task.FromResult(!_externalLogins.HasDenyLocalLogin());
+ private readonly IBackOfficeExternalLoginProviders _externalLogins;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Provides access to instances.
+ public DenyLocalLoginHandler(IBackOfficeExternalLoginProviders externalLogins)
+ => _externalLogins = externalLogins;
- // FIXME: Replace the value of isDenied with above implementation, once we have IBackOfficeExternalLoginProviders and related classes
- // moved from Umbraco.Web.Backoffice
- // FIXME: Remove [AllowAnonymous] from implementers of and in when we have the proper implementation
protected override Task IsAuthorized(AuthorizationHandlerContext context, DenyLocalLoginRequirement requirement)
{
- // Some logic here - for now we will always authorize successfully
- var isDenied = false;
+ var isDenied = _externalLogins.HasDenyLocalLogin();
if (isDenied is false)
{
- // Now allow anonymous (RequireAuthenticatedUser() adds this requirement) - necessary for some of the endpoints (BackOfficeController.Login())
- var denyAnonymousUserRequirements = context.PendingRequirements.OfType();
- foreach (var denyAnonymousUserRequirement in denyAnonymousUserRequirements)
+ // AuthorizationPolicies.BackOfficeAccess policy adds this requirement by policy.RequireAuthenticatedUser()
+ // Since we want to "allow anonymous" for some endpoints (i.e. BackOfficeController.Login()), it is necessary to succeed this requirement
+ IEnumerable denyAnonymousUserRequirements = context.PendingRequirements.OfType();
+ foreach (DenyAnonymousAuthorizationRequirement denyAnonymousUserRequirement in denyAnonymousUserRequirements)
{
context.Succeed(denyAnonymousUserRequirement);
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
index 744e02f001..93ab2f63cb 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
@@ -382,12 +382,11 @@ namespace Umbraco.Cms.Core.DependencyInjection
// Authorizers
Services.AddSingleton();
Services.AddSingleton();
+ Services.AddSingleton();
Services.AddSingleton();
Services.AddSingleton();
Services.AddSingleton();
Services.AddSingleton();
- Services.AddSingleton();
-
}
}
}