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

fix(technicalUser): adjust deletion process #956

Merged
merged 2 commits into from
Aug 29, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Identities;
using Org.Eclipse.TractusX.Portal.Backend.Processes.Library;
Expand Down Expand Up @@ -98,8 +99,14 @@ public async Task<int> DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId
{
var serviceAccountRepository = portalRepositories.GetInstance<IServiceAccountRepository>();
var companyId = _identityData.CompanyId;
var result = await serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(serviceAccountId, companyId).ConfigureAwait(ConfigureAwaitOptions.None)
?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
var technicalUserCreationSteps = new[]
{
ProcessStepTypeId.CREATE_DIM_TECHNICAL_USER, ProcessStepTypeId.RETRIGGER_CREATE_DIM_TECHNICAL_USER,
ProcessStepTypeId.AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE,
ProcessStepTypeId.RETRIGGER_AWAIT_CREATE_DIM_TECHNICAL_USER_RESPONSE
};
var result = await serviceAccountRepository.GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(serviceAccountId, companyId, technicalUserCreationSteps).ConfigureAwait(ConfigureAwaitOptions.None)
?? throw NotFoundException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_FOUND, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);

if (result.StatusId is ConnectorStatusId.ACTIVE or ConnectorStatusId.PENDING)
{
Expand All @@ -112,41 +119,41 @@ public async Task<int> DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId
}

// serviceAccount
if (result.IsDimServiceAccount)
var userStatus = UserStatusId.DELETED;
switch (result)
{
var processId = result.ProcessId ?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]);

var processData = await portalRepositories.GetInstance<IProcessStepRepository>()
.GetProcessDataForServiceAccountDeletionCallback(processId, null)
.ConfigureAwait(ConfigureAwaitOptions.None);

var context = processData.ProcessData.CreateManualProcessData(null,
portalRepositories, () => $"externalId {processId}");
case { IsDimServiceAccount: true, CreationProcessInProgress: false }:
userStatus = await CreateDeletionProcess(serviceAccountId, result).ConfigureAwait(ConfigureAwaitOptions.None);
break;
case { IsDimServiceAccount: true, CreationProcessInProgress: true }:
throw ConflictException.Create(AdministrationServiceAccountErrors.TECHNICAL_USER_CREATION_IN_PROGRESS);
default:
if (!string.IsNullOrWhiteSpace(result.ClientClientId))
{
await provisioningManager.DeleteCentralClientAsync(result.ClientClientId).ConfigureAwait(ConfigureAwaitOptions.None);
}

context.ProcessSteps.Where(step => step.ProcessStepTypeId != ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER).IfAny(pending =>
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, [new("serviceAccountId", serviceAccountId.ToString()), new("processStepTypeIds", string.Join(",", pending))]));
break;
}

if (!context.ProcessSteps.Any(step => step.ProcessStepTypeId == ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER))
portalRepositories.GetInstance<IUserRepository>().AttachAndModifyIdentity(
serviceAccountId,
i =>
{
portalRepositories.GetInstance<IUserRepository>().AttachAndModifyIdentity(serviceAccountId, null, i =>
{
i.UserStatusId = UserStatusId.PENDING_DELETION;
});
context.ScheduleProcessSteps([ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER]);
context.FinalizeProcessStep();
}
}
else if (!string.IsNullOrWhiteSpace(result.ClientClientId))
{
await provisioningManager.DeleteCentralClientAsync(result.ClientClientId).ConfigureAwait(ConfigureAwaitOptions.None);
portalRepositories.GetInstance<IUserRepository>().AttachAndModifyIdentity(serviceAccountId, null, i =>
i.UserStatusId = UserStatusId.PENDING;
},
i =>
{
i.UserStatusId = UserStatusId.DELETED;
i.UserStatusId = userStatus;
});
}

portalRepositories.GetInstance<IUserRolesRepository>().DeleteCompanyUserAssignedRoles(result.UserRoleIds.Select(userRoleId => (serviceAccountId, userRoleId)));
ModifyConnectorForDeleteServiceAccount(serviceAccountId, result);

return await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
}

private void ModifyConnectorForDeleteServiceAccount(Guid serviceAccountId, OwnServiceAccountData result)
{
if (result.ConnectorId != null)
{
portalRepositories.GetInstance<IConnectorsRepository>().AttachAndModifyConnector(result.ConnectorId.Value,
Expand All @@ -159,8 +166,28 @@ public async Task<int> DeleteOwnCompanyServiceAccountAsync(Guid serviceAccountId
connector.CompanyServiceAccountId = null;
});
}
}

return await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
private async Task<UserStatusId> CreateDeletionProcess(Guid serviceAccountId, OwnServiceAccountData result)
{
var processId = result.ProcessId ?? throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, [new("serviceAccountId", serviceAccountId.ToString())]);

var processData = await portalRepositories.GetInstance<IProcessStepRepository>()
.GetProcessDataForServiceAccountDeletionCallback(processId, null)
.ConfigureAwait(ConfigureAwaitOptions.None);

var context = processData.ProcessData.CreateManualProcessData(null,
portalRepositories, () => $"externalId {processId}");

context.ProcessSteps.Where(step => step.ProcessStepTypeId != ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER).IfAny(pending =>
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, [new("serviceAccountId", serviceAccountId.ToString()), new("processStepTypeIds", string.Join(",", pending))]));

if (context.ProcessSteps.Any(step => step.ProcessStepTypeId == ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER))
return UserStatusId.DELETED;

context.ScheduleProcessSteps([ProcessStepTypeId.DELETE_DIM_TECHNICAL_USER]);
context.FinalizeProcessStep();
return UserStatusId.PENDING_DELETION;
}

public async Task<ServiceAccountConnectorOfferData> GetOwnCompanyServiceAccountDetailsAsync(Guid serviceAccountId)
Expand All @@ -170,7 +197,7 @@ public async Task<ServiceAccountConnectorOfferData> GetOwnCompanyServiceAccountD

if (result == null)
{
throw NotFoundException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
throw NotFoundException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_FOUND, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
}

IamClientAuthMethod? iamClientAuthMethod;
Expand Down Expand Up @@ -220,7 +247,7 @@ public async Task<ServiceAccountDetails> ResetOwnCompanyServiceAccountSecretAsyn
var result = await portalRepositories.GetInstance<IServiceAccountRepository>().GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(serviceAccountId, companyId);
if (result == null)
{
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_FOUND, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
}

if (result.ClientClientId == null)
Expand Down Expand Up @@ -259,7 +286,7 @@ public async Task<ServiceAccountDetails> UpdateOwnCompanyServiceAccountDetailsAs
var result = await serviceAccountRepository.GetOwnCompanyServiceAccountWithIamClientIdAsync(serviceAccountId, companyId).ConfigureAwait(ConfigureAwaitOptions.None);
if (result == null)
{
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
throw ConflictException.Create(AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_FOUND, [new("serviceAccountId", serviceAccountId.ToString()), new(CompanyId, companyId.ToString())]);
}

if (result.UserStatusId == UserStatusId.INACTIVE)
Expand Down Expand Up @@ -398,7 +425,7 @@ public async Task HandleServiceAccountDeletionCallback(Guid processId)
null,
i =>
{
i.UserStatusId = UserStatusId.INACTIVE;
i.UserStatusId = UserStatusId.DELETED;
});

context.FinalizeProcessStep();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public IdentityProviderController(IIdentityProviderBusinessLogic identityProvide
}

/// <summary>
///
/// Gets the details of the own company identity provider
/// </summary>
/// <returns>Returns the details of the own company identity provider</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ public Task<IEnumerable<ServiceAccountDetails>> ExecuteCompanyUserCreation([From
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status409Conflict)]
public Task<int> DeleteServiceAccount([FromRoute] Guid serviceAccountId) =>
_logic.DeleteOwnCompanyServiceAccountAsync(serviceAccountId);
public async Task<NoContentResult> DeleteServiceAccount([FromRoute] Guid serviceAccountId)
{
await _logic.DeleteOwnCompanyServiceAccountAsync(serviceAccountId).ConfigureAwait(ConfigureAwaitOptions.None);
return NoContent();
}

/// <summary>
/// Gets the service account details for the given id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ public class AdministrationServiceAccountErrorMessageContainer : IErrorMessageCo
{ AdministrationServiceAccountErrors.SERVICE_COMPANY_NOT_EXIST_CONFLICT, "company {companyId} does not exist"},
{ AdministrationServiceAccountErrors.SERVICE_BPN_NOT_SET_CONFLICT, "bpn not set for company {companyId}"},
{ AdministrationServiceAccountErrors.SERVICE_ROLES_NOT_ASSIGN_ARGUMENT, "The roles {unassignable} are not assignable to a service account, {userRoleIds}"},
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_CONFLICT, "serviceAccount {serviceAccountId} not found for company {companyId}"},
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_FOUND, "serviceAccount {serviceAccountId} not found for company {companyId}"},
{ AdministrationServiceAccountErrors.SERVICE_USERID_ACTIVATION_PENDING_CONFLICT, "Technical User is linked to an active connector. Change the link or deactivate the connector to delete the technical user."},
{ AdministrationServiceAccountErrors.SERVICE_USERID_ACTIVATION_ACTIVE_CONFLICT, "Technical User is linked to an active subscription. Deactivate the subscription to delete the technical user."},
{ AdministrationServiceAccountErrors.SERVICE_UNDEFINED_CLIENTID_CONFLICT, "undefined clientId for serviceAccount {serviceAccountId}"},
{ AdministrationServiceAccountErrors.SERVICE_ID_PATH_NOT_MATCH_ARGUMENT, "serviceAccountId {serviceAccountId} from path does not match the one in body {serviceAccountDetailsServiceAccountId}"},
{ AdministrationServiceAccountErrors.SERVICE_INACTIVE_CONFLICT, "serviceAccount {serviceAccountId} is already INACTIVE"},
{ AdministrationServiceAccountErrors.SERVICE_CLIENTID_NOT_NULL_CONFLICT, "clientClientId of serviceAccount {serviceAccountId} should not be null"},
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS, "Service Account {serviceAccountId} is not linked to a process" },
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, "Service Account {serviceAccountId} has pending process steps {processStepTypeIds}"}
{ AdministrationServiceAccountErrors.SERVICE_ACCOUNT_PENDING_PROCESS_STEPS, "Service Account {serviceAccountId} has pending process steps {processStepTypeIds}"},
{ AdministrationServiceAccountErrors.TECHNICAL_USER_CREATION_IN_PROGRESS, "Technical user can't be deleted because the creation progress is still running"}
}.ToImmutableDictionary(x => (int)x.Key, x => x.Value);

public Type Type { get => typeof(AdministrationServiceAccountErrors); }
Expand All @@ -52,13 +53,14 @@ public enum AdministrationServiceAccountErrors
SERVICE_COMPANY_NOT_EXIST_CONFLICT,
SERVICE_BPN_NOT_SET_CONFLICT,
SERVICE_ROLES_NOT_ASSIGN_ARGUMENT,
SERVICE_ACCOUNT_NOT_CONFLICT,
SERVICE_ACCOUNT_NOT_FOUND,
SERVICE_USERID_ACTIVATION_PENDING_CONFLICT,
SERVICE_USERID_ACTIVATION_ACTIVE_CONFLICT,
SERVICE_UNDEFINED_CLIENTID_CONFLICT,
SERVICE_ID_PATH_NOT_MATCH_ARGUMENT,
SERVICE_INACTIVE_CONFLICT,
SERVICE_CLIENTID_NOT_NULL_CONFLICT,
SERVICE_ACCOUNT_NOT_LINKED_TO_PROCESS,
SERVICE_ACCOUNT_PENDING_PROCESS_STEPS
SERVICE_ACCOUNT_PENDING_PROCESS_STEPS,
TECHNICAL_USER_CREATION_IN_PROGRESS
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,8 @@ public record OwnServiceAccountData(
ConnectorStatusId? StatusId,
OfferSubscriptionStatusId? OfferStatusId,
bool IsDimServiceAccount,
bool CreationProcessInProgress,
Guid? ProcessId
);

public record ProcessData(Guid ProcessId, IEnumerable<Guid> ProcessStepIds);
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ CompanyServiceAccount CreateCompanyServiceAccount(Guid identityId,

void AttachAndModifyCompanyServiceAccount(Guid id, Guid version, Action<CompanyServiceAccount>? initialize, Action<CompanyServiceAccount> modify);
Task<CompanyServiceAccountWithRoleDataClientId?> GetOwnCompanyServiceAccountWithIamClientIdAsync(Guid serviceAccountId, Guid userCompanyId);
Task<OwnServiceAccountData?> GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId);
Task<OwnServiceAccountData?> GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId, IEnumerable<ProcessStepTypeId> processStepsToFilter);
Task<CompanyServiceAccountDetailedData?> GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId);
Func<int, int, Task<Pagination.Source<CompanyServiceAccountData>?>> GetOwnCompanyServiceAccountsUntracked(Guid userCompanyId, string? clientId, bool? isOwner, IEnumerable<UserStatusId> userStatusIds);
Task<bool> CheckActiveServiceAccountExistsForCompanyAsync(Guid technicalUserId, Guid companyId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void AttachAndModifyCompanyServiceAccount(
userRole.UserRoleText))))
.SingleOrDefaultAsync();

public Task<OwnServiceAccountData?> GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId) =>
public Task<OwnServiceAccountData?> GetOwnCompanyServiceAccountWithIamServiceAccountRolesAsync(Guid serviceAccountId, Guid companyId, IEnumerable<ProcessStepTypeId> processStepsToFilter) =>
portalDbContext.CompanyServiceAccounts
.Where(serviceAccount =>
serviceAccount.Id == serviceAccountId &&
Expand All @@ -108,8 +108,12 @@ public void AttachAndModifyCompanyServiceAccount(
sa.ClientClientId,
sa.Connector!.StatusId,
sa.OfferSubscription!.OfferSubscriptionStatusId,
sa.DimCompanyServiceAccount != null,
sa.DimUserCreationData!.ProcessId))
sa.CompanyServiceAccountKindId == CompanyServiceAccountKindId.EXTERNAL,
sa.DimUserCreationData!.Process!.ProcessSteps
.Any(ps =>
ps.ProcessStepStatusId == ProcessStepStatusId.TODO &&
processStepsToFilter.Contains(ps.ProcessStepTypeId)),
sa.DimUserCreationData == null ? null : sa.DimUserCreationData!.ProcessId))
.SingleOrDefaultAsync();

public Task<CompanyServiceAccountDetailedData?> GetOwnCompanyServiceAccountDetailedDataUntrackedAsync(Guid serviceAccountId, Guid companyId) =>
Expand Down
Loading
Loading