Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AC-1654] idor allow the attacker to disable any one scim provising #3325

Merged
merged 2 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/Api/Controllers/OrganizationConnectionsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ public async Task<OrganizationConnectionResponseModel> CreateConnection([FromBod
[HttpPut("{organizationConnectionId}")]
public async Task<OrganizationConnectionResponseModel> UpdateConnection(Guid organizationConnectionId, [FromBody] OrganizationConnectionRequestModel model)
{
var existingOrganizationConnection = await _organizationConnectionRepository.GetByIdAsync(organizationConnectionId);
if (model == null)
{
throw new NotFoundException();
}

var existingOrganizationConnection = await _organizationConnectionRepository.GetByIdOrganizationIdAsync(organizationConnectionId, model.OrganizationId);
if (existingOrganizationConnection == null)
{
throw new NotFoundException();
Expand Down
1 change: 1 addition & 0 deletions src/Core/Repositories/IOrganizationConnectionRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Bit.Core.Repositories;

public interface IOrganizationConnectionRepository : IRepository<OrganizationConnection, Guid>
{
Task<OrganizationConnection> GetByIdOrganizationIdAsync(Guid id, Guid organizationId);
Task<ICollection<OrganizationConnection>> GetByOrganizationIdTypeAsync(Guid organizationId, OrganizationConnectionType type);
Task<ICollection<OrganizationConnection>> GetEnabledByOrganizationIdTypeAsync(Guid organizationId, OrganizationConnectionType type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ public OrganizationConnectionRepository(GlobalSettings globalSettings)
: base(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
{ }

public async Task<OrganizationConnection> GetByIdOrganizationIdAsync(Guid id, Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<OrganizationConnection>(
$"[{Schema}].[OrganizationConnection_ReadByIdOrganizationId]",
new
{
Id = id,
OrganizationId = organizationId
},
commandType: CommandType.StoredProcedure);

return results.FirstOrDefault();
}
}

public async Task<ICollection<OrganizationConnection>> GetByOrganizationIdTypeAsync(Guid organizationId, OrganizationConnectionType type)
{
using (var connection = new SqlConnection(ConnectionString))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ public OrganizationConnectionRepository(IServiceScopeFactory serviceScopeFactory
{
}

public async Task<OrganizationConnection> GetByIdOrganizationIdAsync(Guid id, Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var connection = await dbContext.OrganizationConnections
.FirstOrDefaultAsync(oc => oc.Id == id && oc.OrganizationId == organizationId);
return Mapper.Map<OrganizationConnection>(connection);
}
}

public async Task<ICollection<OrganizationConnection>> GetByOrganizationIdTypeAsync(Guid organizationId, OrganizationConnectionType type)
{
using (var scope = ServiceScopeFactory.CreateScope())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE PROCEDURE [dbo].[OrganizationConnection_ReadByIdOrganizationId]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON

SELECT
*
FROM
[dbo].[OrganizationConnectionView]
WHERE
[Id] = @Id AND
[OrganizationId] = @OrganizationId
END
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ await sutProvider.GetDependency<ICreateOrganizationConnectionCommand>().Received
public async Task UpdateConnection_RequiresOwnerPermissions(SutProvider<OrganizationConnectionsController> sutProvider)
{
sutProvider.GetDependency<IOrganizationConnectionRepository>()
.GetByIdAsync(Arg.Any<Guid>())
.GetByIdOrganizationIdAsync(Arg.Any<Guid>(), Arg.Any<Guid>())
.Returns(new OrganizationConnection());

var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(default, null));
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(default, new OrganizationConnectionRequestModel()));

Assert.Contains("You do not have permission to update this connection.", exception.Message);
}
Expand All @@ -164,8 +164,8 @@ public async Task UpdateConnection_BillingSync_OnlyOneConnectionOfEachType(Organ
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);

var orgConnectionRepository = sutProvider.GetDependency<IOrganizationConnectionRepository>();
orgConnectionRepository.GetByIdAsync(existing1.Id).Returns(existing1);
orgConnectionRepository.GetByIdAsync(existing2.Id).Returns(existing2);
orgConnectionRepository.GetByIdOrganizationIdAsync(existing1.Id, existing1.OrganizationId).Returns(existing1);
orgConnectionRepository.GetByIdOrganizationIdAsync(existing2.Id, existing2.OrganizationId).Returns(existing2);
orgConnectionRepository.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 });

var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel));
Expand All @@ -186,7 +186,7 @@ public async Task UpdateConnection_Scim_OnlyOneConnectionOfEachType(Organization
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(typedModel.OrganizationId).Returns(true);

sutProvider.GetDependency<IOrganizationConnectionRepository>()
.GetByIdAsync(existing1.Id)
.GetByIdOrganizationIdAsync(existing1.Id, existing1.OrganizationId)
.Returns(existing1);

sutProvider.GetDependency<ICurrentContext>().ManageScim(typedModel.OrganizationId).Returns(true);
Expand All @@ -212,6 +212,7 @@ public async Task UpdateConnection_Success(OrganizationConnection existing, Bill
});
updated.Config = JsonSerializer.Serialize(config);
updated.Id = existing.Id;
updated.OrganizationId = existing.OrganizationId;
updated.Type = OrganizationConnectionType.CloudBillingSync;
var model = RequestModelFromEntity<BillingSyncConfig>(updated);

Expand All @@ -224,7 +225,7 @@ public async Task UpdateConnection_Success(OrganizationConnection existing, Bill
.UpdateAsync<BillingSyncConfig>(default)
.ReturnsForAnyArgs(updated);
sutProvider.GetDependency<IOrganizationConnectionRepository>()
.GetByIdAsync(existing.Id)
.GetByIdOrganizationIdAsync(existing.Id, existing.OrganizationId)
.Returns(existing);

OrganizationLicense organizationLicense = new OrganizationLicense();
Expand Down Expand Up @@ -264,6 +265,7 @@ public async Task UpdateConnection_BillingSyncType_InvalidLicense_ErrorThrows(Or
});
updated.Config = JsonSerializer.Serialize(config);
updated.Id = existing.Id;
updated.OrganizationId = existing.OrganizationId;
updated.Type = OrganizationConnectionType.CloudBillingSync;
var model = RequestModelFromEntity<BillingSyncConfig>(updated);
sutProvider.GetDependency<IGlobalSettings>().SelfHosted.Returns(true);
Expand All @@ -275,7 +277,7 @@ public async Task UpdateConnection_BillingSyncType_InvalidLicense_ErrorThrows(Or
.UpdateAsync<BillingSyncConfig>(default)
.ReturnsForAnyArgs(updated);
sutProvider.GetDependency<IOrganizationConnectionRepository>()
.GetByIdAsync(existing.Id)
.GetByIdOrganizationIdAsync(existing.Id, existing.OrganizationId)
.Returns(existing);

OrganizationLicense organizationLicense = new OrganizationLicense();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CREATE OR ALTER PROCEDURE [dbo].[OrganizationConnection_ReadByIdOrganizationId]
@Id UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON

SELECT
*
FROM
[dbo].[OrganizationConnectionView]
WHERE
[Id] = @Id AND
[OrganizationId] = @OrganizationId
END
GO