diff --git a/src/Api/Controllers/CiphersController.cs b/src/Api/Controllers/CiphersController.cs index ce1bf18672..e180c83a0d 100644 --- a/src/Api/Controllers/CiphersController.cs +++ b/src/Api/Controllers/CiphersController.cs @@ -88,7 +88,7 @@ namespace Bit.Api.Controllers public async Task> Get() { var userId = _userService.GetProperUserId(User).Value; - var hasOrgs = _currentContext.Organizations.Any(); + var hasOrgs = _currentContext.Organizations?.Any() ?? false; // TODO: Use hasOrgs proper for cipher listing here? var ciphers = await _cipherRepository.GetManyByUserIdAsync(userId, true || hasOrgs); Dictionary> collectionCiphersGroupDict = null; diff --git a/src/Core/CurrentContext.cs b/src/Core/CurrentContext.cs index 9baf55906d..a344f1e2a4 100644 --- a/src/Core/CurrentContext.cs +++ b/src/Core/CurrentContext.cs @@ -15,8 +15,6 @@ namespace Bit.Core private bool _builtHttpContext; private bool _builtClaimsPrincipal; private string _ip; - private Dictionary> _orgUsers = - new Dictionary>(); public virtual HttpContext HttpContext { get; set; } public virtual Guid? UserId { get; set; } @@ -24,8 +22,7 @@ namespace Bit.Core public virtual string DeviceIdentifier { get; set; } public virtual DeviceType? DeviceType { get; set; } public virtual string IpAddress => GetRequestIp(); - public virtual List Organizations { get; set; } = - new List(); + public virtual List Organizations { get; set; } public virtual Guid? InstallationId { get; set; } public void Build(HttpContext httpContext) @@ -84,6 +81,7 @@ namespace Bit.Core DeviceIdentifier = GetClaimValue(claimsDict, "device"); + Organizations = new List(); if(claimsDict.ContainsKey("orgowner")) { Organizations.AddRange(claimsDict["orgowner"].Select(c => @@ -117,27 +115,30 @@ namespace Bit.Core public bool OrganizationUser(Guid orgId) { - return Organizations.Any(o => o.Id == orgId); + return Organizations?.Any(o => o.Id == orgId) ?? false; } + public bool OrganizationAdmin(Guid orgId) { - return Organizations.Any(o => o.Id == orgId && - (o.Type == OrganizationUserType.Owner || o.Type == OrganizationUserType.Admin)); + return Organizations?.Any(o => o.Id == orgId && + (o.Type == OrganizationUserType.Owner || o.Type == OrganizationUserType.Admin)) ?? false; } + public bool OrganizationOwner(Guid orgId) { - return Organizations.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Owner); + return Organizations?.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Owner) ?? false; } - public async Task> OrganizationMembershipAsync( + public async Task> OrganizationMembershipAsync( IOrganizationUserRepository organizationUserRepository, Guid userId) { - if(!_orgUsers.ContainsKey(userId)) + if(Organizations == null) { - _orgUsers.Add(userId, await organizationUserRepository.GetManyByUserAsync(userId)); + var userOrgs = await organizationUserRepository.GetManyByUserAsync(userId); + Organizations = userOrgs.Where(ou => ou.Status == OrganizationUserStatusType.Confirmed) + .Select(ou => new CurrentContentOrganization(ou)).ToList(); } - - return _orgUsers[userId]; + return Organizations; } private string GetRequestIp() @@ -172,6 +173,14 @@ namespace Bit.Core public class CurrentContentOrganization { + public CurrentContentOrganization() { } + + public CurrentContentOrganization(OrganizationUser orgUser) + { + Id = orgUser.OrganizationId; + Type = orgUser.Type; + } + public Guid Id { get; set; } public OrganizationUserType Type { get; set; } } diff --git a/src/Core/Identity/AuthenticatorTokenProvider.cs b/src/Core/Identity/AuthenticatorTokenProvider.cs index 8f8e3ae266..e7bcd789ec 100644 --- a/src/Core/Identity/AuthenticatorTokenProvider.cs +++ b/src/Core/Identity/AuthenticatorTokenProvider.cs @@ -21,7 +21,7 @@ namespace Bit.Core.Identity public async Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Authenticator); - if(string.IsNullOrWhiteSpace((string)provider.MetaData["Key"])) + if(string.IsNullOrWhiteSpace((string)provider?.MetaData["Key"])) { return false; } diff --git a/src/Core/IdentityServer/ProfileService.cs b/src/Core/IdentityServer/ProfileService.cs index 2ea7ad81a5..e2cf823be1 100644 --- a/src/Core/IdentityServer/ProfileService.cs +++ b/src/Core/IdentityServer/ProfileService.cs @@ -59,29 +59,26 @@ namespace Bit.Core.IdentityServer var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id); if(orgs.Any()) { - var groupedOrgs = orgs.Where(o => o.Status == Enums.OrganizationUserStatusType.Confirmed) - .GroupBy(o => o.Type); - - foreach(var group in groupedOrgs) + foreach(var group in orgs.GroupBy(o => o.Type)) { switch(group.Key) { case Enums.OrganizationUserType.Owner: foreach(var org in group) { - newClaims.Add(new Claim("orgowner", org.OrganizationId.ToString())); + newClaims.Add(new Claim("orgowner", org.Id.ToString())); } break; case Enums.OrganizationUserType.Admin: foreach(var org in group) { - newClaims.Add(new Claim("orgadmin", org.OrganizationId.ToString())); + newClaims.Add(new Claim("orgadmin", org.Id.ToString())); } break; case Enums.OrganizationUserType.User: foreach(var org in group) { - newClaims.Add(new Claim("orguser", org.OrganizationId.ToString())); + newClaims.Add(new Claim("orguser", org.Id.ToString())); } break; default: diff --git a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs index 25a070c02d..0e27f9999e 100644 --- a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs +++ b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs @@ -224,16 +224,16 @@ namespace Bit.Core.IdentityServer Organization firstEnabledOrg = null; var orgs = (await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id)) - .Where(o => o.Status == OrganizationUserStatusType.Confirmed).ToList(); + .ToList(); if(orgs.Any()) { var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); - var twoFactorOrgs = orgs.Where(o => OrgUsing2fa(orgAbilities, o.OrganizationId)); + var twoFactorOrgs = orgs.Where(o => OrgUsing2fa(orgAbilities, o.Id)); if(twoFactorOrgs.Any()) { var userOrgs = await _organizationRepository.GetManyByUserIdAsync(user.Id); firstEnabledOrg = userOrgs.FirstOrDefault( - o => orgs.Any(om => om.OrganizationId == o.Id) && o.TwoFactorIsEnabled()); + o => orgs.Any(om => om.Id == o.Id) && o.TwoFactorIsEnabled()); } } diff --git a/src/Core/Services/Implementations/EventService.cs b/src/Core/Services/Implementations/EventService.cs index de3e7034d1..729bf69d63 100644 --- a/src/Core/Services/Implementations/EventService.cs +++ b/src/Core/Services/Implementations/EventService.cs @@ -46,35 +46,16 @@ namespace Bit.Core.Services }; var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); - IEnumerable orgEvents; - if(_currentContext.UserId.HasValue) - { - orgEvents = _currentContext.Organizations - .Where(o => CanUseEvents(orgAbilities, o.Id)) - .Select(o => new EventMessage(_currentContext) - { - OrganizationId = o.Id, - UserId = userId, - ActingUserId = userId, - Type = type, - Date = DateTime.UtcNow - }); - } - else - { - var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, userId); - orgEvents = orgs - .Where(o => o.Status == OrganizationUserStatusType.Confirmed && - CanUseEvents(orgAbilities, o.OrganizationId)) - .Select(o => new EventMessage(_currentContext) - { - OrganizationId = o.OrganizationId, - UserId = userId, - ActingUserId = userId, - Type = type, - Date = DateTime.UtcNow - }); - } + var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, userId); + var orgEvents = orgs.Where(o => CanUseEvents(orgAbilities, o.Id)) + .Select(o => new EventMessage(_currentContext) + { + OrganizationId = o.Id, + UserId = userId, + ActingUserId = userId, + Type = type, + Date = DateTime.UtcNow + }); if(orgEvents.Any()) { diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index 076e6b68bb..14089f4405 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -831,13 +831,13 @@ namespace Bit.Core.Services { return true; } - if(!_currentContext?.Organizations?.Any() ?? true) + var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id); + if(!orgs.Any()) { return false; } - var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); - return _currentContext.Organizations.Any(o => orgAbilities.ContainsKey(o.Id) && + return orgs.Any(o => orgAbilities.ContainsKey(o.Id) && orgAbilities[o.Id].UsersGetPremium && orgAbilities[o.Id].Enabled); } diff --git a/src/Notifications/NotificationsHub.cs b/src/Notifications/NotificationsHub.cs index a3be4e0ee9..3bfc227c3a 100644 --- a/src/Notifications/NotificationsHub.cs +++ b/src/Notifications/NotificationsHub.cs @@ -19,9 +19,12 @@ namespace Bit.Notifications { var currentContext = new CurrentContext(); currentContext.Build(Context.User); - foreach(var org in currentContext.Organizations) + if(currentContext.Organizations != null) { - await Groups.AddToGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); + foreach(var org in currentContext.Organizations) + { + await Groups.AddToGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); + } } _connectionCounter.Increment(); await base.OnConnectedAsync(); @@ -31,9 +34,12 @@ namespace Bit.Notifications { var currentContext = new CurrentContext(); currentContext.Build(Context.User); - foreach(var org in currentContext.Organizations) + if(currentContext.Organizations != null) { - await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); + foreach(var org in currentContext.Organizations) + { + await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Organization_{org.Id}"); + } } _connectionCounter.Decrement(); await base.OnDisconnectedAsync(exception);