Skip to content

Commit

Permalink
fix(idp): delete iam identity provider (#1026)
Browse files Browse the repository at this point in the history
Refs: #1025
Reviewed-By: Norbert Truchsess <[email protected]>
Co-authored-by: Norbert Truchsess <[email protected]>
  • Loading branch information
Phil91 and ntruchsess authored Sep 20, 2024
1 parent cd5ca62 commit 3b1a8d5
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ public interface IIdentityProviderRepository
IAsyncEnumerable<(string Email, string? FirstName, string? LastName)> GetCompanyUserEmailForIdpWithoutOwnerAndRoleId(IEnumerable<Guid> userRoleIds, Guid identityProviderId);
Task<IdpData?> GetIdentityProviderDataForProcessIdAsync(Guid processId);
void CreateIdentityProviderAssignedProcessRange(IEnumerable<(Guid IdentityProviderId, Guid ProcessId)> identityProviderProcessIds);
Task<string?> GetIamIdentityProviderForIdp(Guid identityProviderId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,10 @@ public IAsyncEnumerable<Guid> GetIdpLinkedCompanyUserIds(Guid identityProviderId

public void CreateIdentityProviderAssignedProcessRange(IEnumerable<(Guid IdentityProviderId, Guid ProcessId)> identityProviderProcessIds) =>
_context.AddRange(identityProviderProcessIds.Select(x => new IdentityProviderAssignedProcess(x.IdentityProviderId, x.ProcessId)));

public Task<string?> GetIamIdentityProviderForIdp(Guid identityProviderId) =>
_context.IamIdentityProviders
.Where(x => x.IdentityProviderId == identityProviderId)
.Select(x => x.IamIdpAlias)
.SingleOrDefaultAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@

namespace Org.Eclipse.TractusX.Portal.Backend.Processes.IdentityProviderProvisioning.Executor;

public class IdentityProviderProvisioningProcessTypeExecutor : IProcessTypeExecutor
public class IdentityProviderProvisioningProcessTypeExecutor(
IPortalRepositories portalRepositories,
IProvisioningManager provisioningManager)
: IProcessTypeExecutor
{
private readonly IPortalRepositories _portalRepositories;
private readonly IProvisioningManager _provisioningManager;

private static readonly IEnumerable<ProcessStepTypeId> ExecutableProcessSteps =
[
ProcessStepTypeId.DELETE_IDP_SHARED_REALM,
Expand All @@ -41,13 +41,7 @@ public class IdentityProviderProvisioningProcessTypeExecutor : IProcessTypeExecu
ProcessStepTypeId.DELETE_IDENTITY_PROVIDER,
];
private IdpData? _idpData = null;
public IdentityProviderProvisioningProcessTypeExecutor(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager)
{
_portalRepositories = portalRepositories;
_provisioningManager = provisioningManager;
}
private IdpData? _idpData;
public ProcessTypeId GetProcessTypeId() => ProcessTypeId.IDENTITYPROVIDER_PROVISIONING;
public bool IsExecutableStepTypeId(ProcessStepTypeId processStepTypeId) => ExecutableProcessSteps.Contains(processStepTypeId);
Expand All @@ -56,13 +50,9 @@ public IdentityProviderProvisioningProcessTypeExecutor(IPortalRepositories porta

public async ValueTask<IProcessTypeExecutor.InitializationResult> InitializeProcess(Guid processId, IEnumerable<ProcessStepTypeId> processStepTypeIds)
{
var idpData = await _portalRepositories.GetInstance<IIdentityProviderRepository>().GetIdentityProviderDataForProcessIdAsync(processId).ConfigureAwait(ConfigureAwaitOptions.None);
_idpData = await portalRepositories.GetInstance<IIdentityProviderRepository>().GetIdentityProviderDataForProcessIdAsync(processId).ConfigureAwait(ConfigureAwaitOptions.None)
?? throw new ConflictException($"process {processId} does not exist or is not associated with an Identity Provider");

if (idpData == null)
{
throw new ConflictException($"process {processId} does not exist or is not associated with an Identity Provider");
}
_idpData = idpData;
return new IProcessTypeExecutor.InitializationResult(false, null);
}

Expand All @@ -85,7 +75,7 @@ public IdentityProviderProvisioningProcessTypeExecutor(IPortalRepositories porta
ProcessStepTypeId.DELETE_IDP_SHARED_REALM => await DeleteSharedRealmAsync(_idpData).ConfigureAwait(ConfigureAwaitOptions.None),
ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT => await DeleteIdpSharedServiceAccount(_idpData).ConfigureAwait(ConfigureAwaitOptions.None),
ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER => await DeleteCentralIdentityProvider(_idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None),
ProcessStepTypeId.DELETE_IDENTITY_PROVIDER => DeleteIdentityProvider(_idpData.IdentityProviderId),
ProcessStepTypeId.DELETE_IDENTITY_PROVIDER => await DeleteIdentityProvider(_idpData.IdentityProviderId).ConfigureAwait(ConfigureAwaitOptions.None),
_ => (null, ProcessStepStatusId.TODO, false, null)
};
}
Expand All @@ -94,6 +84,7 @@ public IdentityProviderProvisioningProcessTypeExecutor(IPortalRepositories porta
(stepStatusId, processMessage, nextStepTypeIds) = ProcessError(ex, processStepTypeId);
modified = true;
}

return new IProcessTypeExecutor.StepExecutionResult(modified, stepStatusId, nextStepTypeIds, null, processMessage);
}

Expand All @@ -112,9 +103,10 @@ private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerabl
{
return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"IdentityProvider {idpData.IamAlias} is not a shared idp");
}

try
{
await _provisioningManager.DeleteSharedRealmAsync(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None);
await provisioningManager.DeleteSharedRealmAsync(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None);
return ([ProcessStepTypeId.DELETE_IDP_SHARED_SERVICEACCOUNT], ProcessStepStatusId.DONE, false, null);
}
catch (KeycloakEntityNotFoundException)
Expand All @@ -129,9 +121,10 @@ private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerabl
{
return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.SKIPPED, false, $"IdentityProvider {idpData.IamAlias} is not a shared idp");
}

try
{
await _provisioningManager.DeleteIdpSharedServiceAccount(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None);
await provisioningManager.DeleteIdpSharedServiceAccount(idpData.IamAlias).ConfigureAwait(ConfigureAwaitOptions.None);
return ([ProcessStepTypeId.DELETE_CENTRAL_IDENTITY_PROVIDER], ProcessStepStatusId.DONE, false, null);
}
catch (KeycloakEntityNotFoundException)
Expand All @@ -144,7 +137,7 @@ private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerabl
{
try
{
await _provisioningManager.DeleteCentralIdentityProviderAsync(alias).ConfigureAwait(ConfigureAwaitOptions.None);
await provisioningManager.DeleteCentralIdentityProviderAsync(alias).ConfigureAwait(ConfigureAwaitOptions.None);
return ([ProcessStepTypeId.DELETE_IDENTITY_PROVIDER], ProcessStepStatusId.DONE, false, null);
}
catch (KeycloakEntityNotFoundException)
Expand All @@ -153,9 +146,15 @@ private static (ProcessStepStatusId StatusId, string? ProcessMessage, IEnumerabl
}
}

private (IEnumerable<ProcessStepTypeId>? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage) DeleteIdentityProvider(Guid identityProviderId)
private async Task<(IEnumerable<ProcessStepTypeId>? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> DeleteIdentityProvider(Guid identityProviderId)
{
var identityProviderRepository = _portalRepositories.GetInstance<IIdentityProviderRepository>();
var identityProviderRepository = portalRepositories.GetInstance<IIdentityProviderRepository>();
var alias = await identityProviderRepository.GetIamIdentityProviderForIdp(identityProviderId).ConfigureAwait(ConfigureAwaitOptions.None);
if (alias != null)
{
identityProviderRepository.DeleteIamIdentityProvider(alias);
}

identityProviderRepository.DeleteIdentityProvider(identityProviderId);
return (null, ProcessStepStatusId.DONE, true, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,36 @@ public async Task DeleteCompanyIdentityProviderRange_ReturnsExpected()

#endregion

#region GetIamIdentityProviderForIdp

[Fact]
public async Task GetIamIdentityProviderForIdp_WithExisting_ReturnsAlias()
{
// Arrange
var sut = await CreateSut();

// Act
var result = await sut.GetIamIdentityProviderForIdp(new Guid("38f56465-ce26-4f25-9745-1791620dc203"));

// Assert
result.Should().Be("to-decline-alias");
}

[Fact]
public async Task GetIamIdentityProviderForIdp_WithNotExisting_ReturnsNull()
{
// Arrange
var sut = await CreateSut();

// Act
var result = await sut.GetIamIdentityProviderForIdp(Guid.NewGuid());

// Assert
result.Should().BeNull();
}

#endregion

#region Setup

private async Task<(IdentityProviderRepository, PortalDbContext)> CreateSutWithContext()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ public class IdentityProviderProvisioningProcessTypeExecutorTests
private readonly Guid _ownProcessId = Guid.NewGuid();
private readonly IdpData _sharedIdpData;
private readonly IdpData _ownIdpData;
private readonly IPortalRepositories _portalRepositories;
private readonly IProvisioningManager _provisioningManager;
private readonly IIdentityProviderRepository _identityProviderRepository;
private readonly IFixture _fixture;
private readonly IdentityProviderProvisioningProcessTypeExecutor _executor;
Expand All @@ -44,18 +42,18 @@ public IdentityProviderProvisioningProcessTypeExecutorTests()
.ForEach(b => _fixture.Behaviors.Remove(b));
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());

_portalRepositories = A.Fake<IPortalRepositories>();
_provisioningManager = A.Fake<IProvisioningManager>();
var portalRepositories = A.Fake<IPortalRepositories>();
var provisioningManager = A.Fake<IProvisioningManager>();
_identityProviderRepository = A.Fake<IIdentityProviderRepository>();

_sharedIdpData = new IdpData(Guid.NewGuid(), "sharedIdp", IdentityProviderTypeId.SHARED);

_ownIdpData = new IdpData(Guid.NewGuid(), "ownIdp", IdentityProviderTypeId.OWN);

A.CallTo(() => _portalRepositories.GetInstance<IIdentityProviderRepository>())
A.CallTo(() => portalRepositories.GetInstance<IIdentityProviderRepository>())
.Returns(_identityProviderRepository);

_executor = new IdentityProviderProvisioningProcessTypeExecutor(_portalRepositories, _provisioningManager);
_executor = new IdentityProviderProvisioningProcessTypeExecutor(portalRepositories, provisioningManager);
SetupFakes();
}

Expand Down Expand Up @@ -184,14 +182,16 @@ public async Task ExecuteProcessStep_WithValidTriggerData_CallsExpected(bool sha
result.ScheduleStepTypeIds.Should().ContainSingle()
.Which.Should().Be(nextprocessStepTypeId);
}

result.ProcessStepStatusId.Should().Be(stepStatus);
result.ProcessMessage.Should().Be(message);
result.SkipStepTypeIds.Should().BeNull();
}

#endregion

#region SetUp
#region SetUp

private void SetupFakes()
{
A.CallTo(() => _identityProviderRepository.GetIdentityProviderDataForProcessIdAsync(_sharedProcessId))
Expand All @@ -201,5 +201,4 @@ private void SetupFakes()
}

#endregion

}

0 comments on commit 3b1a8d5

Please sign in to comment.