diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index 219b8dd695..e9f2672d58 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization; using Bit.Core.Models.Api; using Bit.Core.Exceptions; using Bit.Core.Services; +using Bit.Core; namespace Bit.Api.Controllers { @@ -18,25 +19,27 @@ namespace Bit.Api.Controllers private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationService _organizationService; private readonly IUserService _userService; + private readonly CurrentContext _currentContext; public OrganizationsController( IOrganizationRepository organizationRepository, IOrganizationUserRepository organizationUserRepository, IOrganizationService organizationService, - IUserService userService) + IUserService userService, + CurrentContext currentContext) { _organizationRepository = organizationRepository; _organizationUserRepository = organizationUserRepository; _organizationService = organizationService; _userService = userService; + _currentContext = currentContext; } [HttpGet("{id}")] public async Task Get(string id) { - var userId = _userService.GetProperUserId(User).Value; - var organization = await _organizationRepository.GetByIdAsync(new Guid(id), userId); - if(organization == null) + var organization = await _organizationRepository.GetByIdAsync(new Guid(id)); + if(organization == null || !_currentContext.OrganizationAdmin(organization.Id)) { throw new NotFoundException(); } @@ -44,25 +47,6 @@ namespace Bit.Api.Controllers return new OrganizationResponseModel(organization); } - [HttpGet("{id}/extended")] - public async Task GetExtended(string id) - { - var userId = _userService.GetProperUserId(User).Value; - var organization = await _organizationRepository.GetByIdAsync(new Guid(id), userId); - if(organization == null) - { - throw new NotFoundException(); - } - - var organizationUser = await _organizationUserRepository.GetByOrganizationAsync(new Guid(id), userId); - if(organizationUser == null) - { - throw new NotFoundException(); - } - - return new OrganizationExtendedResponseModel(organization, organizationUser); - } - [HttpGet("")] public async Task> Get() { @@ -73,22 +57,20 @@ namespace Bit.Api.Controllers } [HttpPost("")] - public async Task Post([FromBody]OrganizationCreateRequestModel model) + public async Task Post([FromBody]OrganizationCreateRequestModel model) { var user = await _userService.GetUserByPrincipalAsync(User); var organizationSignup = model.ToOrganizationSignup(user); var result = await _organizationService.SignUpAsync(organizationSignup); - return new OrganizationExtendedResponseModel(result.Item1, result.Item2); + return new OrganizationResponseModel(result.Item1); } [HttpPut("{id}")] [HttpPost("{id}")] public async Task Put(string id, [FromBody]OrganizationUpdateRequestModel model) { - var userId = _userService.GetProperUserId(User).Value; - var organization = await _organizationRepository.GetByIdAsync(new Guid(id), userId); - // TODO: Permission checks - if(organization == null) + var organization = await _organizationRepository.GetByIdAsync(new Guid(id)); + if(organization == null || !_currentContext.OrganizationAdmin(organization.Id)) { throw new NotFoundException(); } @@ -101,9 +83,8 @@ namespace Bit.Api.Controllers [HttpPost("{id}/delete")] public async Task Delete(string id) { - var organization = await _organizationRepository.GetByIdAsync(new Guid(id), - _userService.GetProperUserId(User).Value); - if(organization == null) + var organization = await _organizationRepository.GetByIdAsync(new Guid(id)); + if(organization == null || !_currentContext.OrganizationAdmin(organization.Id)) { throw new NotFoundException(); } diff --git a/src/Api/Middleware/CurrentContextMiddleware.cs b/src/Api/Middleware/CurrentContextMiddleware.cs index 61153db4d0..29dda8a9a6 100644 --- a/src/Api/Middleware/CurrentContextMiddleware.cs +++ b/src/Api/Middleware/CurrentContextMiddleware.cs @@ -20,6 +20,39 @@ namespace Bit.Api.Middleware { var securityStampClaim = httpContext.User.Claims.FirstOrDefault(c => c.Type == "device"); currentContext.DeviceIdentifier = securityStampClaim?.Value; + + var orgOwnerClaims = httpContext.User.Claims.Where(c => c.Type == "orgowner"); + if(orgOwnerClaims.Any()) + { + currentContext.Organizations.AddRange(orgOwnerClaims.Select(c => + new CurrentContext.CurrentContentOrganization + { + Id = new System.Guid(c.Value), + Type = Core.Enums.OrganizationUserType.Owner + })); + } + + var orgAdminClaims = httpContext.User.Claims.Where(c => c.Type == "orgadmin"); + if(orgAdminClaims.Any()) + { + currentContext.Organizations.AddRange(orgAdminClaims.Select(c => + new CurrentContext.CurrentContentOrganization + { + Id = new System.Guid(c.Value), + Type = Core.Enums.OrganizationUserType.Admin + })); + } + + var orgUserClaims = httpContext.User.Claims.Where(c => c.Type == "orguser"); + if(orgUserClaims.Any()) + { + currentContext.Organizations.AddRange(orgUserClaims.Select(c => + new CurrentContext.CurrentContentOrganization + { + Id = new System.Guid(c.Value), + Type = Core.Enums.OrganizationUserType.User + })); + } } if(currentContext.DeviceIdentifier == null && httpContext.Request.Headers.ContainsKey("Device-Identifier")) diff --git a/src/Core/CurrentContext.cs b/src/Core/CurrentContext.cs index 27c7605436..b867e6a7bf 100644 --- a/src/Core/CurrentContext.cs +++ b/src/Core/CurrentContext.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using Bit.Core.Models.Table; +using Bit.Core.Enums; namespace Bit.Core { @@ -10,5 +10,26 @@ namespace Bit.Core { public virtual User User { get; set; } public virtual string DeviceIdentifier { get; set; } + public virtual List Organizations { get; set; } = new List(); + + public bool OrganizationUser(Guid orgId) + { + return Organizations.Any(o => o.Id == orgId); + } + public bool OrganizationAdmin(Guid orgId) + { + return Organizations.Any(o => o.Id == orgId && + (o.Type == OrganizationUserType.Owner || o.Type == OrganizationUserType.Admin)); + } + public bool OrganizationOwner(Guid orgId) + { + return Organizations.Any(o => o.Id == orgId && o.Type == OrganizationUserType.Owner); + } + + public class CurrentContentOrganization + { + public Guid Id { get; set; } + public OrganizationUserType Type { get; set; } + } } } diff --git a/src/Core/Models/Api/Response/OrganizationResponseModel.cs b/src/Core/Models/Api/Response/OrganizationResponseModel.cs index 37bd7cb0c0..a7954fd22a 100644 --- a/src/Core/Models/Api/Response/OrganizationResponseModel.cs +++ b/src/Core/Models/Api/Response/OrganizationResponseModel.cs @@ -24,24 +24,8 @@ namespace Bit.Core.Models.Api public string Id { get; set; } public string Name { get; set; } public string Plan { get; set; } - public Core.Enums.PlanType PlanType { get; set; } + public Enums.PlanType PlanType { get; set; } public bool PlanTrial { get; set; } public short MaxUsers { get; set; } } - - public class OrganizationExtendedResponseModel : OrganizationResponseModel - { - public OrganizationExtendedResponseModel(Organization organization, OrganizationUser organizationUser) - : base(organization, "organizationExtended") - { - if(organizationUser == null) - { - throw new ArgumentNullException(nameof(organizationUser)); - } - - Key = organizationUser.Key; - } - - public string Key { get; set; } - } } diff --git a/src/Core/Repositories/IOrganizationRepository.cs b/src/Core/Repositories/IOrganizationRepository.cs index 5c64d4f7ff..2c2788c7a5 100644 --- a/src/Core/Repositories/IOrganizationRepository.cs +++ b/src/Core/Repositories/IOrganizationRepository.cs @@ -7,7 +7,6 @@ namespace Bit.Core.Repositories { public interface IOrganizationRepository : IRepository { - Task GetByIdAsync(Guid id, Guid userId); Task> GetManyByUserIdAsync(Guid userId); } } diff --git a/src/Core/Repositories/SqlServer/OrganizationRepository.cs b/src/Core/Repositories/SqlServer/OrganizationRepository.cs index 92d57522e8..4274d847c4 100644 --- a/src/Core/Repositories/SqlServer/OrganizationRepository.cs +++ b/src/Core/Repositories/SqlServer/OrganizationRepository.cs @@ -19,19 +19,6 @@ namespace Bit.Core.Repositories.SqlServer : base(connectionString) { } - public async Task GetByIdAsync(Guid id, Guid userId) - { - using(var connection = new SqlConnection(ConnectionString)) - { - var results = await connection.QueryAsync( - "[dbo].[Organization_ReadByIdUserId]", - new { Id = id, UserId = userId }, - commandType: CommandType.StoredProcedure); - - return results.SingleOrDefault(); - } - } - public async Task> GetManyByUserIdAsync(Guid userId) { using(var connection = new SqlConnection(ConnectionString)) diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 91194bd070..c999a772e0 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -163,7 +163,6 @@ - diff --git a/src/Sql/dbo/Stored Procedures/Organization_ReadByIdUserId.sql b/src/Sql/dbo/Stored Procedures/Organization_ReadByIdUserId.sql deleted file mode 100644 index 1a494b29ba..0000000000 --- a/src/Sql/dbo/Stored Procedures/Organization_ReadByIdUserId.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE PROCEDURE [dbo].[Organization_ReadByIdUserId] - @Id UNIQUEIDENTIFIER, - @UserId UNIQUEIDENTIFIER -AS -BEGIN - SET NOCOUNT ON - - SELECT - O.* - FROM - [dbo].[OrganizationView] O - INNER JOIN - [dbo].[OrganizationUser] OU ON O.[Id] = OU.[OrganizationId] - WHERE - O.[Id] = @Id - AND OU.[UserId] = @UserId -END \ No newline at end of file