mirror of
https://github.com/bitwarden/server
synced 2025-12-15 07:43:54 +00:00
* added column ApiKey to dbo.User * added dbo.User.ApiKey to User_Update * added dbo.User.ApiKey to User_Create * wrote migration script for implementing dbo.User.ApiKey * Added ApiKey prop to the User table model * Created AccountsController method for getting a user's API Key * Created AccountsController method for rotating a user API key * Added support to ApiClient for passed-through ClientSecrets when the request comes from the cli * Added a new conditional to ClientStore to account for user API keys * Wrote unit tests for new user API Key methods * Added a refresh of dbo.UserView to new migration script for ApiKey * Let client_credentials grants into the custom token logic * Cleanup for ApiKey auth in the CLI feature * Created user API key on registration * Removed uneeded code for user API keys * Changed a .Contains() to a .StartsWith() in ClientStore * Changed index that an array is searched on * Added more claims to the user apikey clients * Moved some claim finding logic to a helper method
86 lines
3.1 KiB
C#
86 lines
3.1 KiB
C#
using IdentityServer4.Services;
|
|
using System.Threading.Tasks;
|
|
using IdentityServer4.Models;
|
|
using Bit.Core.Repositories;
|
|
using Bit.Core.Services;
|
|
using System.Security.Claims;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System;
|
|
using IdentityModel;
|
|
using Bit.Core.Utilities;
|
|
|
|
namespace Bit.Core.IdentityServer
|
|
{
|
|
public class ProfileService : IProfileService
|
|
{
|
|
private readonly IUserService _userService;
|
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
|
private readonly ILicensingService _licensingService;
|
|
private readonly CurrentContext _currentContext;
|
|
|
|
public ProfileService(
|
|
IUserService userService,
|
|
IOrganizationUserRepository organizationUserRepository,
|
|
ILicensingService licensingService,
|
|
CurrentContext currentContext)
|
|
{
|
|
_userService = userService;
|
|
_organizationUserRepository = organizationUserRepository;
|
|
_licensingService = licensingService;
|
|
_currentContext = currentContext;
|
|
}
|
|
|
|
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
|
{
|
|
var existingClaims = context.Subject.Claims;
|
|
var newClaims = new List<Claim>();
|
|
|
|
var user = await _userService.GetUserByPrincipalAsync(context.Subject);
|
|
if (user != null)
|
|
{
|
|
var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
|
|
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id);
|
|
foreach (var claim in CoreHelpers.BuildIdentityClaims(user, orgs, isPremium))
|
|
{
|
|
var upperValue = claim.Value.ToUpperInvariant();
|
|
var isBool = upperValue == "TRUE" || upperValue == "FALSE";
|
|
newClaims.Add(isBool ?
|
|
new Claim(claim.Key, claim.Value, ClaimValueTypes.Boolean) :
|
|
new Claim(claim.Key, claim.Value)
|
|
);
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
|
|
newClaims.AddRange(existingClaimsToKeep);
|
|
if (newClaims.Any())
|
|
{
|
|
context.IssuedClaims.AddRange(newClaims);
|
|
}
|
|
}
|
|
|
|
public async Task IsActiveAsync(IsActiveContext context)
|
|
{
|
|
var securityTokenClaim = context.Subject?.Claims.FirstOrDefault(c => c.Type == "sstamp");
|
|
var user = await _userService.GetUserByPrincipalAsync(context.Subject);
|
|
|
|
if (user != null && securityTokenClaim != null)
|
|
{
|
|
context.IsActive = string.Equals(user.SecurityStamp, securityTokenClaim.Value,
|
|
StringComparison.InvariantCultureIgnoreCase);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
context.IsActive = true;
|
|
}
|
|
}
|
|
}
|
|
}
|