1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

Auth/PM-3659 - Disable Passkey registration if Require SSO Policy Enabled (#3399)

* PM-3659 - WebAuthnController.cs - Passkey Creation - Add RequireSSO login policy validation to prevent users from creating passkeys if require SSO applies to them.

* PM-3659 - per PR feedback, apply new require SSO validation to options call

* PM-3659 - Remove unneeded comment

* PM-3659 - Per PR feedback, add unit tests for new require SSO scenarios on both Post and Options endpoints on the WebAuthnController

* Remove duplicated line

* Remove extra whitespace
This commit is contained in:
Jared Snider
2023-11-01 13:39:00 -04:00
committed by GitHub
parent 1fb5e49a05
commit f5f64059c5
2 changed files with 64 additions and 5 deletions

View File

@ -5,6 +5,7 @@ using Bit.Api.Models.Response;
using Bit.Core;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.Repositories;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Tokens;
@ -22,15 +23,18 @@ public class WebAuthnController : Controller
private readonly IUserService _userService;
private readonly IWebAuthnCredentialRepository _credentialRepository;
private readonly IDataProtectorTokenFactory<WebAuthnCredentialCreateOptionsTokenable> _createOptionsDataProtector;
private readonly IPolicyService _policyService;
public WebAuthnController(
IUserService userService,
IWebAuthnCredentialRepository credentialRepository,
IDataProtectorTokenFactory<WebAuthnCredentialCreateOptionsTokenable> createOptionsDataProtector)
IDataProtectorTokenFactory<WebAuthnCredentialCreateOptionsTokenable> createOptionsDataProtector,
IPolicyService policyService)
{
_userService = userService;
_credentialRepository = credentialRepository;
_createOptionsDataProtector = createOptionsDataProtector;
_policyService = policyService;
}
[HttpGet("")]
@ -46,6 +50,7 @@ public class WebAuthnController : Controller
public async Task<WebAuthnCredentialCreateOptionsResponseModel> PostOptions([FromBody] SecretVerificationRequestModel model)
{
var user = await VerifyUserAsync(model);
await ValidateRequireSsoPolicyDisabledOrNotApplicable(user.Id);
var options = await _userService.StartWebAuthnLoginRegistrationAsync(user);
var tokenable = new WebAuthnCredentialCreateOptionsTokenable(user, options);
@ -62,7 +67,9 @@ public class WebAuthnController : Controller
public async Task Post([FromBody] WebAuthnCredentialRequestModel model)
{
var user = await GetUserAsync();
await ValidateRequireSsoPolicyDisabledOrNotApplicable(user.Id);
var tokenable = _createOptionsDataProtector.Unprotect(model.Token);
if (!tokenable.TokenIsValid(user))
{
throw new BadRequestException("The token associated with your request is expired. A valid token is required to continue.");
@ -75,6 +82,16 @@ public class WebAuthnController : Controller
}
}
private async Task ValidateRequireSsoPolicyDisabledOrNotApplicable(Guid userId)
{
var requireSsoLogin = await _policyService.AnyPoliciesApplicableToUserAsync(userId, PolicyType.RequireSso);
if (requireSsoLogin)
{
throw new BadRequestException("Passkeys cannot be created for your account. SSO login is required.");
}
}
[HttpPost("{id}/delete")]
public async Task Delete(Guid id, [FromBody] SecretVerificationRequestModel model)
{