mirror of
https://github.com/bitwarden/server
synced 2026-01-03 00:53:37 +00:00
[PM-20592] [PM-22737] [PM-22738] Send grant validator (#6151)
**feat**: create `SendGrantValidator` and initial `SendPasswordValidator` for Send access grants **feat**: add feature flag to toggle Send grant validation logic **feat**: add Send client to Identity and update `ApiClient` to generic `Client` **feat**: register Send services in DI pipeline **feat**: add claims management support to `ProfileService` **feat**: distinguish between invalid grant and invalid request in `SendAccessGrantValidator` **fix**: update parsing of `send_id` from request **fix**: add early return when feature flag is disabled **fix**: rename and organize Send access scope and grant type **fix**: dotnet format **test**: add unit and integration tests for `SendGrantValidator` **test**: update OpenID configuration and API resource claims **doc**: move documentation to interfaces and update inline comments **chore**: add TODO for future support of `CustomGrantTypes`
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
// FIXME: Update this file to be null safe and then delete the line below
|
||||
#nullable disable
|
||||
|
||||
using System.Security.Claims;
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Identity;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -42,8 +40,22 @@ public class ProfileService : IProfileService
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
{
|
||||
var existingClaims = context.Subject.Claims;
|
||||
var newClaims = new List<Claim>();
|
||||
|
||||
// If the client is a Send client, we do not add any additional claims
|
||||
if (context.Client.ClientId == BitwardenClient.Send)
|
||||
{
|
||||
// preserve all claims that were already on context.Subject
|
||||
// which includes the ones added by the SendAccessGrantValidator
|
||||
context.IssuedClaims.AddRange(existingClaims);
|
||||
return;
|
||||
}
|
||||
|
||||
// Whenever IdentityServer issues a new access token or services a UserInfo request, it calls
|
||||
// GetProfileDataAsync to determine which claims to include in the token or response.
|
||||
// In normal user identity scenarios, we have to look up the user to get their claims and update
|
||||
// the issued claims collection as claim info can have changed since the last time the user logged in or the
|
||||
// last time the token was issued.
|
||||
var newClaims = new List<Claim>();
|
||||
var user = await _userService.GetUserByPrincipalAsync(context.Subject);
|
||||
if (user != null)
|
||||
{
|
||||
@@ -63,12 +75,16 @@ public class ProfileService : IProfileService
|
||||
|
||||
// filter out any of the new claims
|
||||
var existingClaimsToKeep = existingClaims
|
||||
.Where(c => !c.Type.StartsWith("org") &&
|
||||
(newClaims.Count == 0 || !newClaims.Any(nc => nc.Type == c.Type)))
|
||||
.ToList();
|
||||
.Where(c =>
|
||||
// Drop any org claims
|
||||
!c.Type.StartsWith("org") &&
|
||||
// If we have no new claims, then keep the existing claims
|
||||
// If we have new claims, then keep the existing claim if it does not match a new claim type
|
||||
(newClaims.Count == 0 || !newClaims.Any(nc => nc.Type == c.Type))
|
||||
).ToList();
|
||||
|
||||
newClaims.AddRange(existingClaimsToKeep);
|
||||
if (newClaims.Any())
|
||||
if (newClaims.Count != 0)
|
||||
{
|
||||
context.IssuedClaims.AddRange(newClaims);
|
||||
}
|
||||
@@ -76,6 +92,13 @@ public class ProfileService : IProfileService
|
||||
|
||||
public async Task IsActiveAsync(IsActiveContext context)
|
||||
{
|
||||
// Send Tokens are not refreshed so when the token has expired the user must request a new one via the authentication method assigned to the send.
|
||||
if (context.Client.ClientId == BitwardenClient.Send)
|
||||
{
|
||||
context.IsActive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// We add the security stamp claim to the persisted grant when we issue the refresh token.
|
||||
// IdentityServer will add this claim to the subject, and here we evaluate whether the security stamp that
|
||||
// was persisted matches the current security stamp of the user. If it does not match, then the user has performed
|
||||
|
||||
Reference in New Issue
Block a user