mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 00:22:50 -05:00
Create sso user api (#886)
* facilitate linking/unlinking existing users from an sso enabled org * added user_identifier to identity methods for sso * moved sso user delete method to account controller * fixed a broken test * Update AccountsController.cs * facilitate linking/unlinking existing users from an sso enabled org * added user_identifier to identity methods for sso * moved sso user delete method to account controller * fixed a broken test * added a token to the existing user sso link flow * added a token to the existing user sso link flow * fixed a typo * added an event log for unlink ssoUser records * fixed a merge issue * fixed a busted test * fixed a busted test * ran a formatter over everything & changed .vscode settings in .gitignore * chagned a variable to use string interpolation * removed a blank line * Changed TokenPurpose enum to a static class of strings * code review cleanups * formatting fix * Changed parameters & logging for delete sso user * changed th method used to get organization user for deleting sso user records Co-authored-by: Kyle Spearrin <kspearrin@users.noreply.github.com>
This commit is contained in:
@ -4,4 +4,9 @@
|
||||
{
|
||||
public const int BypassFiltersEventId = 12482444;
|
||||
}
|
||||
|
||||
public static class TokenPurposes
|
||||
{
|
||||
public const string LinkSso = "LinkSso";
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
OrganizationUser_Updated = 1502,
|
||||
OrganizationUser_Removed = 1503,
|
||||
OrganizationUser_UpdatedGroups = 1504,
|
||||
OrganizationUser_UnlinkedSso = 1505,
|
||||
|
||||
Organization_Updated = 1600,
|
||||
Organization_PurgedVault = 1601,
|
||||
|
@ -28,6 +28,7 @@ namespace Bit.Core.Models.Api
|
||||
Type = organization.Type;
|
||||
Enabled = organization.Enabled;
|
||||
SsoBound = !string.IsNullOrWhiteSpace(organization.SsoExternalId);
|
||||
Identifier = organization.Identifier;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
@ -51,5 +52,6 @@ namespace Bit.Core.Models.Api
|
||||
public OrganizationUserType Type { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public bool SsoBound { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -25,5 +25,6 @@ namespace Bit.Core.Models.Data
|
||||
public Enums.OrganizationUserType Type { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string SsoExternalId { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Models.Table;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Repositories
|
||||
{
|
||||
public interface ISsoUserRepository : IRepository<SsoUser, long>
|
||||
{
|
||||
Task DeleteAsync(Guid userId, Guid? organizationId);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
using Bit.Core.Models.Table;
|
||||
using Dapper;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Data.SqlClient;
|
||||
using System.Data;
|
||||
|
||||
namespace Bit.Core.Repositories.SqlServer
|
||||
{
|
||||
@ -11,5 +16,16 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
public SsoUserRepository(string connectionString, string readOnlyConnectionString)
|
||||
: base(connectionString, readOnlyConnectionString)
|
||||
{ }
|
||||
|
||||
public async Task DeleteAsync(Guid userId, Guid? organizationId)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.ExecuteAsync(
|
||||
$"[{Schema}].[SsoUser_Delete]",
|
||||
new { UserId = userId, OrganizationId = organizationId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,5 +51,6 @@ namespace Bit.Core.Services
|
||||
IEnumerable<ImportedOrganizationUser> newUsers, IEnumerable<string> removeUserExternalIds,
|
||||
bool overwriteExisting);
|
||||
Task RotateApiKeyAsync(Organization organization);
|
||||
Task DeleteSsoUserAsync(Guid userId, Guid? organizationId);
|
||||
}
|
||||
}
|
||||
|
@ -68,5 +68,6 @@ namespace Bit.Core.Services
|
||||
Task<bool> TwoFactorIsEnabledAsync(ITwoFactorProvidersUser user);
|
||||
Task<bool> TwoFactorProviderIsEnabledAsync(TwoFactorProviderType provider, ITwoFactorProvidersUser user);
|
||||
Task<string> GenerateEnterprisePortalSignInTokenAsync(User user);
|
||||
Task<string> GenerateSignInTokenAsync(User user, string purpose);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ namespace Bit.Core.Services
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly ISsoUserRepository _ssoUserRepository;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
@ -56,6 +57,7 @@ namespace Bit.Core.Services
|
||||
IPaymentService paymentService,
|
||||
IPolicyRepository policyRepository,
|
||||
ISsoConfigRepository ssoConfigRepository,
|
||||
ISsoUserRepository ssoUserRepository,
|
||||
IReferenceEventService referenceEventService,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
@ -76,6 +78,7 @@ namespace Bit.Core.Services
|
||||
_paymentService = paymentService;
|
||||
_policyRepository = policyRepository;
|
||||
_ssoConfigRepository = ssoConfigRepository;
|
||||
_ssoUserRepository = ssoUserRepository;
|
||||
_referenceEventService = referenceEventService;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
@ -1497,6 +1500,19 @@ namespace Bit.Core.Services
|
||||
await ReplaceAndUpdateCache(organization);
|
||||
}
|
||||
|
||||
public async Task DeleteSsoUserAsync(Guid userId, Guid? organizationId)
|
||||
{
|
||||
await _ssoUserRepository.DeleteAsync(userId, organizationId);
|
||||
if (organizationId.HasValue)
|
||||
{
|
||||
var organizationUser = await _organizationUserRepository.GetByOrganizationAsync(organizationId.Value, userId);
|
||||
if (organizationUser != null)
|
||||
{
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_UnlinkedSso);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateUsersAsync(Group group, HashSet<string> groupUsers,
|
||||
Dictionary<string, Guid> existingUsersIdDict, HashSet<Guid> existingUsers = null)
|
||||
{
|
||||
|
@ -1087,6 +1087,7 @@ namespace Bit.Core.Services
|
||||
return await CanAccessPremium(user);
|
||||
}
|
||||
|
||||
//TODO refactor this to use the below method and enum
|
||||
public async Task<string> GenerateEnterprisePortalSignInTokenAsync(User user)
|
||||
{
|
||||
var token = await GenerateUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider,
|
||||
@ -1094,6 +1095,14 @@ namespace Bit.Core.Services
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> GenerateSignInTokenAsync(User user, string purpose)
|
||||
{
|
||||
var token = await GenerateUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider,
|
||||
purpose);
|
||||
return token;
|
||||
}
|
||||
|
||||
private async Task<IdentityResult> UpdatePasswordHash(User user, string newPassword,
|
||||
bool validatePassword = true, bool refreshStamp = true)
|
||||
{
|
||||
|
Reference in New Issue
Block a user