diff --git a/bitwarden_license/src/Sso/Controllers/AccountController.cs b/bitwarden_license/src/Sso/Controllers/AccountController.cs
index a2cfeefeef..c9db0290e0 100644
--- a/bitwarden_license/src/Sso/Controllers/AccountController.cs
+++ b/bitwarden_license/src/Sso/Controllers/AccountController.cs
@@ -326,6 +326,16 @@ namespace Bit.Sso.Controllers
var externalUser = result.Principal;
+ // Validate acr claim against expectation before going further
+ if (!string.IsNullOrWhiteSpace(ssoConfigData.ExpectedReturnAcrValue))
+ {
+ var acrClaim = externalUser.FindFirst(JwtClaimTypes.AuthenticationContextClassReference);
+ if (acrClaim?.Value != ssoConfigData.ExpectedReturnAcrValue)
+ {
+ throw new Exception(_i18nService.T("AcrMissingOrInvalid"));
+ }
+ }
+
// Ensure the NameIdentifier used is not a transient name ID, if so, we need a different attribute
// for the user identifier.
static bool nameIdIsNotTransient(Claim c) => c.Type == ClaimTypes.NameIdentifier
diff --git a/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs b/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs
index 623e2dee37..7b457d029c 100644
--- a/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs
+++ b/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs
@@ -333,19 +333,21 @@ namespace Bit.Core.Business.Sso
{
oidcOptions.Scope.AddIfNotExists(scope);
}
+ if (!string.IsNullOrWhiteSpace(config.ExpectedReturnAcrValue))
+ {
+ oidcOptions.Scope.AddIfNotExists(OpenIdConnectScopes.Acr);
+ }
oidcOptions.StateDataFormat = new DistributedCacheStateDataFormatter(_httpContextAccessor, name);
// see: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest (acr_values)
if (!string.IsNullOrWhiteSpace(config.AcrValues))
{
- oidcOptions.Events = new OpenIdConnectEvents
+ oidcOptions.Events ??= new OpenIdConnectEvents();
+ oidcOptions.Events.OnRedirectToIdentityProvider = ctx =>
{
- OnRedirectToIdentityProvider = ctx =>
- {
- ctx.ProtocolMessage.AcrValues = config.AcrValues;
- return Task.CompletedTask;
- }
+ ctx.ProtocolMessage.AcrValues = config.AcrValues;
+ return Task.CompletedTask;
};
}
diff --git a/bitwarden_license/src/Sso/Utilities/OpenIdConnectScopes.cs b/bitwarden_license/src/Sso/Utilities/OpenIdConnectScopes.cs
index 54b6e0a119..983ce8b33f 100644
--- a/bitwarden_license/src/Sso/Utilities/OpenIdConnectScopes.cs
+++ b/bitwarden_license/src/Sso/Utilities/OpenIdConnectScopes.cs
@@ -49,5 +49,16 @@
/// not present (not logged in).
///
public const string OfflineAccess = "offline_access";
+
+ ///
+ /// OPTIONAL. Authentication Context Class Reference. String specifying
+ /// an Authentication Context Class Reference value that identifies the
+ /// Authentication Context Class that the authentication performed
+ /// satisfied.
+ ///
+ ///
+ /// See: https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2
+ ///
+ public const string Acr = "acr";
}
}
diff --git a/src/Core/Models/Data/SsoConfigurationData.cs b/src/Core/Models/Data/SsoConfigurationData.cs
index d7c357a49d..19192c3897 100644
--- a/src/Core/Models/Data/SsoConfigurationData.cs
+++ b/src/Core/Models/Data/SsoConfigurationData.cs
@@ -27,6 +27,7 @@ namespace Bit.Core.Models.Data
public string AdditionalEmailClaimTypes { get; set; }
public string AdditionalNameClaimTypes { get; set; }
public string AcrValues { get; set; }
+ public string ExpectedReturnAcrValue { get; set; }
// SAML2 IDP
public string IdpEntityId { get; set; }
diff --git a/src/Core/Resources/SharedResources.en.resx b/src/Core/Resources/SharedResources.en.resx
index 1a490bc1ef..df876e3aad 100644
--- a/src/Core/Resources/SharedResources.en.resx
+++ b/src/Core/Resources/SharedResources.en.resx
@@ -638,10 +638,18 @@
Requested Authentication Context Class Reference values (acr_values)'acr_values' is an explicit OIDC param, see https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest. It should not be translated.
+
+ Expected "acr" Claim Value In Response (acr validation)
+ 'acr' is an explicit OIDC claim type, see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2 (acr). It should not be translated.
+
You have been logged out of the Bitwarden Business Portal.Access Denied to this resource.
+
+ Expected authentication context class reference (acr) was not returned with the authentication response or is invalid.
+ 'acr' is an explicit OIDC claim type, see https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.2 (acr). It should not be translated.
+