From adefd97de1986eb9c1a93df08619cb415949a49c Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Thu, 29 Aug 2024 13:22:52 +0200 Subject: [PATCH] feat(invite): create application and company on invite Refs: #700 --- .../BusinessLogic/InvitationBusinessLogic.cs | 17 ++++-- .../CompanyInvitationRepository.cs | 51 +++++++++------- .../ICompanyInvitationRepository.cs | 3 +- .../InvitationProcessService.cs | 39 +++++------- .../InvitationBusinessLogicTests.cs | 16 ++++- .../CompanyInvitationRepositoryTests.cs | 38 +++++++++++- .../Seeder/Data/company_invitations.test.json | 3 +- .../InvitationProcessServiceTests.cs | 61 +++++++------------ 8 files changed, 133 insertions(+), 95 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/InvitationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/InvitationBusinessLogic.cs index 49bb0bca7d..eb0d52d477 100644 --- a/src/administration/Administration.Service/BusinessLogic/InvitationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/InvitationBusinessLogic.cs @@ -62,13 +62,20 @@ private async Task ExecuteInvitationInternalAsync(CompanyInvitationData invitati var processStepRepository = _portalRepositories.GetInstance(); var processId = processStepRepository.CreateProcess(ProcessTypeId.INVITATION).Id; processStepRepository.CreateProcessStep(ProcessStepTypeId.INVITATION_CREATE_CENTRAL_IDP, ProcessStepStatusId.TODO, processId); + + var company = _portalRepositories.GetInstance().CreateCompany(organisationName); + + var applicationRepository = _portalRepositories.GetInstance(); + var applicationId = applicationRepository.CreateCompanyApplication(company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL).Id; _portalRepositories.GetInstance().CreateCompanyInvitation(firstName, lastName, email, organisationName, processId, ci => + { + ci.ApplicationId = applicationId; + if (!string.IsNullOrWhiteSpace(userName)) { - if (!string.IsNullOrWhiteSpace(userName)) - { - ci.UserName = userName; - } - }); + ci.UserName = userName; + } + }); + await _portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None); } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs index 8c23f7ab12..215883a9dd 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyInvitationRepository.cs @@ -1,21 +1,21 @@ /******************************************************************************** - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ +* Copyright (c) 2024 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +* +* SPDX-License-Identifier: Apache-2.0 +********************************************************************************/ using Microsoft.EntityFrameworkCore; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; @@ -73,6 +73,16 @@ public Task GetCompanyInvitationForProcessId(Guid processId) => )) .SingleOrDefaultAsync(); + public Task<(bool Exists, Guid CompanyId, string? IdpName)> GetIdpAndCompanyId(Guid invitationId) => + _context.CompanyInvitations + .Where(x => x.Id == invitationId) + .Select(x => new ValueTuple( + true, + x.Application!.CompanyId, + x.IdpName + )) + .SingleOrDefaultAsync(); + public void AttachAndModifyCompanyInvitation(Guid invitationId, Action? initialize, Action modify) { var entity = new CompanyInvitation(invitationId, null!, null!, null!, null!, Guid.Empty); @@ -87,16 +97,15 @@ public void AttachAndModifyCompanyInvitation(Guid invitationId, Action x.IdpName) .SingleOrDefaultAsync(); - public Task<(string OrgName, string? IdpName, string? ClientId, byte[]? ClientSecret, byte[]? InitializationVector, int? EncryptionMode)> GetUpdateCentralIdpUrlData(Guid invitationId) => + public Task<(string OrgName, string? IdpName, string? ClientId, byte[]? ClientSecret, byte[]? InitializationVector)> GetUpdateCentralIdpUrlData(Guid invitationId) => _context.CompanyInvitations .Where(x => x.Id == invitationId) - .Select(x => new ValueTuple( + .Select(x => new ValueTuple( x.OrganisationName, x.IdpName, x.ClientId, x.ClientSecret, - x.InitializationVector, - x.EncryptionMode)) + x.InitializationVector)) .SingleOrDefaultAsync(); public Task GetServiceAccountUserIdForInvitation(Guid invitationId) => diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyInvitationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyInvitationRepository.cs index 839fd47cfe..f275da30c2 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyInvitationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyInvitationRepository.cs @@ -29,8 +29,9 @@ public interface ICompanyInvitationRepository Task GetOrganisationNameForInvitation(Guid invitationId); Task<(bool Exists, Guid? ApplicationId, Guid? CompanyId, string CompanyName, IEnumerable<(Guid IdpId, string IdpName)> IdpInformation, UserInvitationInformation UserInformation)> GetInvitationUserData(Guid companyInvitationId); Task<(bool Exists, string OrgName, string? IdpName)> GetIdpAndOrgName(Guid invitationId); + Task<(bool Exists, Guid CompanyId, string? IdpName)> GetIdpAndCompanyId(Guid invitationId); void AttachAndModifyCompanyInvitation(Guid invitationId, Action? initialize, Action modify); Task GetIdpNameForInvitationId(Guid invitationId); - Task<(string OrgName, string? IdpName, string? ClientId, byte[]? ClientSecret, byte[]? InitializationVector, int? EncryptionMode)> GetUpdateCentralIdpUrlData(Guid invitationId); + Task<(string OrgName, string? IdpName, string? ClientId, byte[]? ClientSecret, byte[]? InitializationVector)> GetUpdateCentralIdpUrlData(Guid invitationId); Task GetServiceAccountUserIdForInvitation(Guid invitationId); } diff --git a/src/processes/Invitation.Executor/InvitationProcessService.cs b/src/processes/Invitation.Executor/InvitationProcessService.cs index 4a88d14e0f..2b91aada08 100644 --- a/src/processes/Invitation.Executor/InvitationProcessService.cs +++ b/src/processes/Invitation.Executor/InvitationProcessService.cs @@ -25,6 +25,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.Processes.Invitation.Executor.DependencyInjection; using Org.Eclipse.TractusX.Portal.Backend.Processes.Mailing.Library; @@ -136,7 +137,7 @@ public InvitationProcessService( public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> UpdateCentralIdpUrl(Guid invitationId) { var companyInvitationRepository = _portalRepositories.GetInstance(); - var (orgName, idpName, clientId, clientSecret, initializationVector, encryptionMode) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); + var (orgName, idpName, clientId, clientSecret, initializationVector) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); if (string.IsNullOrWhiteSpace(idpName)) { @@ -148,28 +149,23 @@ public InvitationProcessService( throw new ConflictException("ClientId must not be null"); } - var secret = Decrypt(clientSecret, initializationVector, encryptionMode); + var secret = Decrypt(clientSecret, initializationVector); await _idpManagement.UpdateCentralIdentityProviderUrlsAsync(idpName, orgName, _settings.InitialLoginTheme, clientId, secret).ConfigureAwait(false); return (Enumerable.Repeat(ProcessStepTypeId.INVITATION_CREATE_SHARED_CLIENT, 1), ProcessStepStatusId.DONE, true, null); } - private string Decrypt(byte[]? clientSecret, byte[]? initializationVector, int? encryptionMode) + private string Decrypt(byte[]? clientSecret, byte[]? initializationVector) { + var cryptoHelper = _settings.EncryptionConfigs.GetCryptoHelper(_settings.EncryptionConfigIndex); + if (clientSecret == null) { throw new ConflictException("ClientSecret must not be null"); } - if (encryptionMode == null) - { - throw new ConflictException("EncryptionMode must not be null"); - } - - var cryptoConfig = _settings.EncryptionConfigs.SingleOrDefault(x => x.Index == encryptionMode) ?? throw new ConfigurationException($"EncryptionModeIndex {encryptionMode} is not configured"); - - return CryptoHelper.Decrypt(clientSecret, initializationVector, Convert.FromHexString(cryptoConfig.EncryptionKey), cryptoConfig.CipherMode, cryptoConfig.PaddingMode); + return cryptoHelper.Decrypt(clientSecret, initializationVector); } public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateCentralIdpOrgMapper(Guid invitationId) @@ -181,6 +177,7 @@ private string Decrypt(byte[]? clientSecret, byte[]? initializationVector, int? { throw new ConflictException($"Invitation {invitationId} does not exist"); } + if (string.IsNullOrWhiteSpace(idpName)) { throw new ConflictException(IdpNotSetErrorMessage); @@ -194,7 +191,7 @@ private string Decrypt(byte[]? clientSecret, byte[]? initializationVector, int? public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateSharedIdpRealm(Guid invitationId) { var companyInvitationRepository = _portalRepositories.GetInstance(); - var (orgName, idpName, clientId, clientSecret, initializationVector, encryptionMode) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); + var (orgName, idpName, clientId, clientSecret, initializationVector) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); if (string.IsNullOrWhiteSpace(idpName)) { @@ -206,7 +203,7 @@ private string Decrypt(byte[]? clientSecret, byte[]? initializationVector, int? throw new ConflictException("ClientId must not be null"); } - var secret = Decrypt(clientSecret, initializationVector, encryptionMode); + var secret = Decrypt(clientSecret, initializationVector); await _idpManagement .CreateSharedRealmIdpClientAsync(idpName, _settings.InitialLoginTheme, orgName, clientId, secret) @@ -218,7 +215,7 @@ await _idpManagement public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateSharedClient(Guid invitationId) { var companyInvitationRepository = _portalRepositories.GetInstance(); - var (_, idpName, clientId, clientSecret, initializationVector, encryptionMode) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); + var (_, idpName, clientId, clientSecret, initializationVector) = await companyInvitationRepository.GetUpdateCentralIdpUrlData(invitationId).ConfigureAwait(ConfigureAwaitOptions.None); if (string.IsNullOrWhiteSpace(idpName)) { @@ -230,7 +227,7 @@ await _idpManagement throw new ConflictException("ClientId must not be null"); } - var secret = Decrypt(clientSecret, initializationVector, encryptionMode); + var secret = Decrypt(clientSecret, initializationVector); await _idpManagement .CreateSharedClientAsync(idpName, clientId, secret) @@ -259,7 +256,7 @@ await _idpManagement public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> CreateIdpDatabase(Guid companyInvitationId) { var companyInvitationRepository = _portalRepositories.GetInstance(); - var (exists, orgName, idpName) = await companyInvitationRepository.GetIdpAndOrgName(companyInvitationId).ConfigureAwait(ConfigureAwaitOptions.None); + var (exists, companyId, idpName) = await companyInvitationRepository.GetIdpAndCompanyId(companyInvitationId).ConfigureAwait(ConfigureAwaitOptions.None); if (!exists) { throw new NotFoundException($"CompanyInvitation {companyInvitationId} does not exist"); @@ -270,17 +267,11 @@ await _idpManagement throw new ConflictException("IdpName must be set for the company invitation"); } - var company = _portalRepositories.GetInstance().CreateCompany(orgName); - var identityProviderRepository = _portalRepositories.GetInstance(); - var identityProvider = identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, company.Id, null); - identityProvider.Companies.Add(company); + var identityProvider = identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, companyId, null); + identityProvider.Companies.Add(new Company(companyId, null!, CompanyStatusId.PENDING, DateTimeOffset.UtcNow)); identityProviderRepository.CreateIamIdentityProvider(identityProvider.Id, idpName); - var applicationRepository = _portalRepositories.GetInstance(); - var applicationId = applicationRepository.CreateCompanyApplication(company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL).Id; - companyInvitationRepository.AttachAndModifyCompanyInvitation(companyInvitationId, x => { x.ApplicationId = null; }, x => { x.ApplicationId = applicationId; }); - return (Enumerable.Repeat(ProcessStepTypeId.INVITATION_CREATE_USER, 1), ProcessStepStatusId.DONE, true, null); } diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs index 43c3c8d195..033f501632 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/InvitationBusinessLogicTests.cs @@ -32,9 +32,13 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Tests.Busin public class InvitationBusinessLogicTests { + private static readonly Guid ApplicationId = Guid.NewGuid(); + private static readonly Guid CompanyId = Guid.NewGuid(); private readonly IFixture _fixture; private readonly IProcessStepRepository _processStepRepository; private readonly ICompanyInvitationRepository _companyInvitationRepository; + private readonly ICompanyRepository _companyRepository; + private readonly IApplicationRepository _applicationRepository; private readonly IPortalRepositories _portalRepositories; private readonly InvitationBusinessLogic _sut; @@ -46,9 +50,13 @@ public InvitationBusinessLogicTests() _portalRepositories = A.Fake(); _processStepRepository = A.Fake(); _companyInvitationRepository = A.Fake(); + _companyRepository = A.Fake(); + _applicationRepository = A.Fake(); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_processStepRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_companyInvitationRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_companyRepository); + A.CallTo(() => _portalRepositories.GetInstance()).Returns(_applicationRepository); _sut = new InvitationBusinessLogic(_portalRepositories); } @@ -93,7 +101,9 @@ public async Task ExecuteInvitation_WithValidData_CreatesExpected() processes.Should().ContainSingle().And.Satisfy(x => x.ProcessTypeId == ProcessTypeId.INVITATION); processSteps.Should().ContainSingle().And.Satisfy(x => x.ProcessStepTypeId == ProcessStepTypeId.INVITATION_CREATE_CENTRAL_IDP && x.ProcessStepStatusId == ProcessStepStatusId.TODO); - invitations.Should().ContainSingle().And.Satisfy(x => x.ProcessId == processes.Single().Id && x.UserName == "testUserName"); + invitations.Should().ContainSingle().And.Satisfy(x => x.ProcessId == processes.Single().Id && x.UserName == "testUserName" && x.ApplicationId == ApplicationId); + A.CallTo(() => _companyRepository.CreateCompany(A._, null)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _applicationRepository.CreateCompanyApplication(CompanyId, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL, null)).MustHaveHappenedOnceExactly(); } [Theory] @@ -504,6 +514,7 @@ public async Task RetriggerInvitationCreateUser_WithNotExistingProcess_ThrowsExc private void SetupFakesForInvite(List processes, List processSteps, List invitations) { + var company = new Company(CompanyId, "testOrg", CompanyStatusId.PENDING, DateTimeOffset.UtcNow); var createdProcessId = Guid.NewGuid(); A.CallTo(() => _processStepRepository.CreateProcess(ProcessTypeId.INVITATION)) .Invokes((ProcessTypeId processTypeId) => @@ -527,6 +538,9 @@ private void SetupFakesForInvite(List processes, List proc setOptionalFields?.Invoke(entity); invitations.Add(entity); }); + A.CallTo(() => _companyRepository.CreateCompany(A._, A>._)).Returns(company); + A.CallTo(() => _applicationRepository.CreateCompanyApplication(company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL, null)) + .Returns(new CompanyApplication(ApplicationId, company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL, DateTimeOffset.UtcNow)); } private void SetupFakesForRetrigger(List processSteps) diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyInvitationRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyInvitationRepositoryTests.cs index a94b6720f9..411763b887 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyInvitationRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/CompanyInvitationRepositoryTests.cs @@ -230,10 +230,10 @@ public async Task GetUpdateCentralIdpUrlData_WithExistingForProcessId_ReturnsExp #endregion - #region GetIdpAndOrgName + #region [Fact] - public async Task GetIdpAndOrgNameAsync_WithExistingForProcessId_ReturnsExpected() + public async Task GetIdpAndOrgName_WithExisting_ReturnsExpected() { // Arrange var sut = await CreateSut(); @@ -248,7 +248,7 @@ public async Task GetIdpAndOrgNameAsync_WithExistingForProcessId_ReturnsExpected } [Fact] - public async Task GetInvitationIdpCreationData_WithoutExistingForProcessId_ReturnsExpected() + public async Task GetIdpAndOrgName_WithoutExisting_ReturnsExpected() { // Arrange var sut = await CreateSut(); @@ -262,6 +262,38 @@ public async Task GetInvitationIdpCreationData_WithoutExistingForProcessId_Retur #endregion + #region GetIdpAndCompanyId + + [Fact] + public async Task GetIdpAndCompanyId_WithExisting_ReturnsExpected() + { + // Arrange + var sut = await CreateSut(); + + // Act + var data = await sut.GetIdpAndCompanyId(_invitationId); + + // Assert + data.Exists.Should().BeTrue(); + data.CompanyId.Should().Be("ac861325-bc54-4583-bcdc-9e9f2a38ff84"); + data.IdpName.Should().Be("test idp"); + } + + [Fact] + public async Task GetIdpAndCompanyId_WithoutExisting_ReturnsExpected() + { + // Arrange + var sut = await CreateSut(); + + // Act + var data = await sut.GetIdpAndCompanyId(Guid.NewGuid()); + + // Assert + data.Exists.Should().BeFalse(); + } + + #endregion + #region Setup private async Task<(ICompanyInvitationRepository sut, PortalDbContext context)> CreateSutWithContext() diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_invitations.test.json b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_invitations.test.json index ce92e11f0d..23b6f01e76 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_invitations.test.json +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/Seeder/Data/company_invitations.test.json @@ -11,6 +11,7 @@ "idp_name": "test idp", "password": null, "client_id": "cl1", - "client_secret": null + "client_secret": null, + "application_id": "4f0146c6-32aa-4bb1-b844-df7e8babdcb2" } ] \ No newline at end of file diff --git a/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs b/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs index 5d78193614..932b570ba1 100644 --- a/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs +++ b/tests/processes/Invitation.Executor.Tests/InvitationProcessServiceTests.cs @@ -295,7 +295,7 @@ public async Task UpdateCentralIdpUrl_WithValid_ReturnsExpected() var password = _fixture.Create(); var (secret, initializationVector) = CryptoHelper.Encrypt(password, _encryptionKey, CipherMode.CBC, PaddingMode.PKCS7); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "idp1", "cl1", secret, initializationVector, 0)); + .Returns(("testCorp", "idp1", "cl1", secret, initializationVector)); // Act var result = await _sut.UpdateCentralIdpUrl(companyInvitation.Id); @@ -316,7 +316,7 @@ public async Task UpdateCentralIdpUrl_WithClientSecretNotSet_ThrowsConflictExcep // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", "idp1", null, null, null)); + .Returns(("testCorp", "cl1", "idp1", null, null)); // Act Task Act() => _sut.UpdateCentralIdpUrl(companyInvitation.Id); @@ -332,7 +332,7 @@ public async Task UpdateCentralIdpUrl_WithClientIdNotSet_ThrowsConflictException // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", null, null, null, null)); + .Returns(("testCorp", "cl1", null, null, null)); // Act Task Act() => _sut.UpdateCentralIdpUrl(companyInvitation.Id); @@ -348,7 +348,7 @@ public async Task UpdateCentralIdpUrl_WithIdpNotSet_ThrowsConflictException() // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", null, null, null, null, null)); + .Returns(("testCorp", null, null, null, null)); // Act Task Act() => _sut.UpdateCentralIdpUrl(companyInvitation.Id); @@ -411,7 +411,7 @@ public async Task CreateSharedIdpRealmIdpClient_WithValid_ReturnsExpected() var password = _fixture.Create(); var (secret, initializationVector) = CryptoHelper.Encrypt(password, _encryptionKey, CipherMode.CBC, PaddingMode.PKCS7); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "idp1", "cl1", secret, initializationVector, 0)); + .Returns(("testCorp", "idp1", "cl1", secret, initializationVector)); // Act var result = await _sut.CreateSharedIdpRealm(companyInvitation.Id); @@ -432,7 +432,7 @@ public async Task CreateSharedIdpRealmIdpClient_WithClientSecretNotSet_ThrowsCon // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", "idp1", null, null, null)); + .Returns(("testCorp", "cl1", "idp1", null, null)); // Act Task Act() => _sut.CreateSharedIdpRealm(companyInvitation.Id); @@ -448,7 +448,7 @@ public async Task CreateSharedIdpRealmIdpClient_WithClientIdNotSet_ThrowsConflic // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", null, null, null, null)); + .Returns(("testCorp", "cl1", null, null, null)); // Act Task Act() => _sut.CreateSharedIdpRealm(companyInvitation.Id); @@ -464,7 +464,7 @@ public async Task CreateSharedIdpRealmIdpClient_WithIdpNotSet_ThrowsConflictExce // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", null, null, null, null, null)); + .Returns(("testCorp", null, null, null, null)); // Act Task Act() => _sut.CreateSharedIdpRealm(companyInvitation.Id); @@ -486,7 +486,7 @@ public async Task CreateSharedClient_WithValid_ReturnsExpected() var password = _fixture.Create(); var (secret, initializationVector) = CryptoHelper.Encrypt(password, _encryptionKey, CipherMode.CBC, PaddingMode.PKCS7); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "idp1", "cl1", secret, initializationVector, 0)); + .Returns(("testCorp", "idp1", "cl1", secret, initializationVector)); // Act var result = await _sut.CreateSharedClient(companyInvitation.Id); @@ -507,7 +507,7 @@ public async Task CreateSharedClient_WithClientSecretNotSet_ThrowsConflictExcept // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", "idp1", null, null, null)); + .Returns(("testCorp", "cl1", "idp1", null, null)); // Act Task Act() => _sut.CreateSharedClient(companyInvitation.Id); @@ -523,7 +523,7 @@ public async Task CreateSharedClient_WithClientIdNotSet_ThrowsConflictException( // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", "cl1", null, null, null, null)); + .Returns(("testCorp", "cl1", null, null, null)); // Act Task Act() => _sut.CreateSharedClient(companyInvitation.Id); @@ -539,7 +539,7 @@ public async Task CreateSharedClient_WithIdpNotSet_ThrowsConflictException() // Arrange var companyInvitation = _fixture.Create(); A.CallTo(() => _companyInvitationRepository.GetUpdateCentralIdpUrlData(companyInvitation.Id)) - .Returns(("testCorp", null, null, null, null, null)); + .Returns(("testCorp", null, null, null, null)); // Act Task Act() => _sut.CreateSharedClient(companyInvitation.Id); @@ -600,39 +600,22 @@ public async Task CreateIdpDatabase_WithValid_ReturnsExpected() { // Arrange var companyInvitation = _fixture.Create(); - var company = _fixture.Build().With(x => x.Name, "testCorp").With(x => x.CompanyWalletData, (CompanyWalletData?)null).Create(); - var applicationId = Guid.NewGuid(); + var companyId = Guid.NewGuid(); var idpId = Guid.NewGuid(); - A.CallTo(() => _companyInvitationRepository.GetIdpAndOrgName(companyInvitation.Id)) - .Returns((true, "testCorp", "cl1-testCorp")); - A.CallTo(() => _companyRepository.CreateCompany("testCorp", A>._)).Returns(company); - A.CallTo(() => _companyInvitationRepository.AttachAndModifyCompanyInvitation(companyInvitation.Id, A>._, A>._)) - .Invokes((Guid _, Action? initialize, Action modify) => - { - initialize?.Invoke(companyInvitation); - modify(companyInvitation); - }); - A.CallTo(() => _identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, company.Id, null)) - .Returns(new IdentityProvider(idpId, IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, company.Id, DateTimeOffset.UtcNow)); - A.CallTo(() => _applicationRepository.CreateCompanyApplication(company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL, null)) - .Returns(new CompanyApplication(applicationId, company.Id, CompanyApplicationStatusId.CREATED, CompanyApplicationTypeId.INTERNAL, DateTimeOffset.UtcNow)); - A.CallTo(() => _companyInvitationRepository.AttachAndModifyCompanyInvitation(companyInvitation.Id, A>._, A>._)) - .Invokes((Guid _, Action? initialize, Action modify) => - { - initialize?.Invoke(companyInvitation); - modify(companyInvitation); - }); + A.CallTo(() => _companyInvitationRepository.GetIdpAndCompanyId(companyInvitation.Id)) + .Returns((true, companyId, "cl1-testCorp")); + A.CallTo(() => _identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, companyId, null)) + .Returns(new IdentityProvider(idpId, IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, companyId, DateTimeOffset.UtcNow)); // Act var result = await _sut.CreateIdpDatabase(companyInvitation.Id); // Assert - A.CallTo(() => _identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, company.Id, null)) + A.CallTo(() => _identityProviderRepository.CreateIdentityProvider(IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, companyId, null)) .MustHaveHappenedOnceExactly(); A.CallTo(() => _identityProviderRepository.CreateIamIdentityProvider(idpId, "cl1-testCorp")) .MustHaveHappenedOnceExactly(); - companyInvitation.ApplicationId.Should().Be(applicationId); result.modified.Should().BeTrue(); result.processMessage.Should().BeNull(); result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); @@ -645,8 +628,8 @@ public async Task CreateIdpDatabase_WithNotExisting_ThrowsNotFoundException() { // Arrange var companyInvitation = _fixture.Create(); - A.CallTo(() => _companyInvitationRepository.GetIdpAndOrgName(companyInvitation.Id)) - .Returns((false, "testCorp", (string?)null)); + A.CallTo(() => _companyInvitationRepository.GetIdpAndCompanyId(companyInvitation.Id)) + .Returns((false, Guid.NewGuid(), (string?)null)); // Act Task Act() => _sut.CreateIdpDatabase(companyInvitation.Id); @@ -661,8 +644,8 @@ public async Task CreateIdpDatabase_WithIdpNotSet_ThrowsConflictException() { // Arrange var companyInvitation = _fixture.Create(); - A.CallTo(() => _companyInvitationRepository.GetIdpAndOrgName(companyInvitation.Id)) - .Returns((true, "testCorp", (string?)null)); + A.CallTo(() => _companyInvitationRepository.GetIdpAndCompanyId(companyInvitation.Id)) + .Returns((true, Guid.NewGuid(), (string?)null)); // Act Task Act() => _sut.CreateIdpDatabase(companyInvitation.Id);