From c45b4360458f800741a989903aa6476d8dadc692 Mon Sep 17 00:00:00 2001 From: Phil Schneider Date: Thu, 14 Sep 2023 16:05:46 +0200 Subject: [PATCH] fix(idp): adjust get idps endpoints (#267) * fix GET: api/administration/identityprovider/owncompany/identityproviders * fix GET: api/administration/identityprovider/owncompany/identityproviders/{identityTypeId} Refs: CPLP-3247 --------- Co-authored-by: Norbert Truchsess Reviewed-By: Norbert Truchsess --- .../IdentityProviderBusinessLogic.cs | 142 +++++--- .../Models/IdentityProviderDetails.cs | 2 +- .../IIdentityProviderRepository.cs | 2 +- .../IdentityProviderRepository.cs | 4 +- .../iam_identity_providers.consortia.json | 4 - .../Data/identity_providers.consortia.json | 14 - .../IdentityProviderBusinessLogicTests.cs | 323 ++++++++++++------ 7 files changed, 315 insertions(+), 176 deletions(-) diff --git a/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs index 37ca1ccbb0..6fc40e3efe 100644 --- a/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IdentityProviderBusinessLogic.cs @@ -42,16 +42,18 @@ public class IdentityProviderBusinessLogic : IIdentityProviderBusinessLogic private readonly IPortalRepositories _portalRepositories; private readonly IProvisioningManager _provisioningManager; private readonly IIdentityService _identityService; + private readonly ILogger _logger; private readonly IdentityProviderSettings _settings; - private static readonly Regex _displayNameValidationExpression = new Regex(@"^[a-zA-Z0-9\!\?\@\&\#\'\x22\(\)_\-\=\/\*\.\,\;\: ]+$", RegexOptions.None, TimeSpan.FromSeconds(1)); + private static readonly Regex DisplayNameValidationExpression = new(@"^[a-zA-Z0-9\!\?\@\&\#\'\x22\(\)_\-\=\/\*\.\,\;\: ]+$", RegexOptions.None, TimeSpan.FromSeconds(1)); - public IdentityProviderBusinessLogic(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager, IIdentityService identityService, IOptions options) + public IdentityProviderBusinessLogic(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager, IIdentityService identityService, IOptions options, ILogger logger) { _portalRepositories = portalRepositories; _provisioningManager = provisioningManager; _identityService = identityService; _settings = options.Value; + _logger = logger; } public async IAsyncEnumerable GetOwnCompanyIdentityProvidersAsync() @@ -59,29 +61,12 @@ public async IAsyncEnumerable GetOwnCompanyIdentityProv var companyId = _identityService.IdentityData.CompanyId; await foreach (var identityProviderData in _portalRepositories.GetInstance().GetCompanyIdentityProviderCategoryDataUntracked(companyId).ConfigureAwait(false)) { - switch (identityProviderData.CategoryId) + yield return identityProviderData.CategoryId switch { - case IdentityProviderCategoryId.KEYCLOAK_OIDC: - yield return await GetIdentityProviderDetailsOidc(identityProviderData.IdentityProviderId, identityProviderData.Alias, identityProviderData.CategoryId, identityProviderData.TypeId).ConfigureAwait(false); - break; - case IdentityProviderCategoryId.KEYCLOAK_SAML: - var identityProviderDataSAML = await _provisioningManager.GetCentralIdentityProviderDataSAMLAsync(identityProviderData.Alias).ConfigureAwait(false); - yield return new IdentityProviderDetails( - identityProviderData.IdentityProviderId, - identityProviderData.Alias, - identityProviderData.CategoryId, - identityProviderData.TypeId, - identityProviderDataSAML.DisplayName, - identityProviderDataSAML.RedirectUrl, - identityProviderDataSAML.Enabled, - await _provisioningManager.GetIdentityProviderMappers(identityProviderData.Alias).ToListAsync().ConfigureAwait(false)) - { - saml = new IdentityProviderDetailsSaml( - identityProviderDataSAML.EntityId, - identityProviderDataSAML.SingleSignOnServiceUrl) - }; - break; - } + IdentityProviderCategoryId.KEYCLOAK_OIDC => await GetIdentityProviderDetailsOidc(identityProviderData.IdentityProviderId, identityProviderData.Alias, identityProviderData.CategoryId, identityProviderData.TypeId).ConfigureAwait(false), + IdentityProviderCategoryId.KEYCLOAK_SAML => await GetIdentityProviderDetailsSaml(identityProviderData.IdentityProviderId, identityProviderData.Alias, identityProviderData.TypeId), + _ => throw new ControllerArgumentException($"unexpected value for category '{identityProviderData.CategoryId}'") + }; } } @@ -107,7 +92,7 @@ private static void ValidateDisplayName(string displayName) { throw new ControllerArgumentException("displayName length must be 2-30 characters"); } - if (!_displayNameValidationExpression.IsMatch(displayName)) + if (!DisplayNameValidationExpression.IsMatch(displayName)) { throw new ControllerArgumentException("allowed characters in displayName: 'a-zA-Z0-9!?@&#'\"()_-=/*.,;: '"); } @@ -392,45 +377,96 @@ public async ValueTask DeleteCompanyIdentityProviderAsync(Guid identityProviderI return (alias, typeId); } - private async ValueTask GetIdentityProviderDetailsOidc(Guid identityProviderId, string alias, IdentityProviderCategoryId categoryId, IdentityProviderTypeId typeId) + private async ValueTask GetIdentityProviderDetailsOidc(Guid identityProviderId, string? alias, IdentityProviderCategoryId categoryId, IdentityProviderTypeId typeId) { - var identityProviderDataOIDC = await _provisioningManager.GetCentralIdentityProviderDataOIDCAsync(alias).ConfigureAwait(false); + IdentityProviderConfigOidc? identityProviderDataOidc = null; + IEnumerable? identityProviderMapper = null; + + if (!string.IsNullOrWhiteSpace(alias)) + { + bool aliasExisting; + try + { + identityProviderDataOidc = await _provisioningManager.GetCentralIdentityProviderDataOIDCAsync(alias) + .ConfigureAwait(false); + aliasExisting = true; + } + catch (KeycloakEntityNotFoundException ex) + { + _logger.LogInformation("Can't receive saml data for {Alias} with following exception {Exception}", alias, ex.Message); + aliasExisting = false; + } + + if (aliasExisting) + { + identityProviderMapper = await _provisioningManager.GetIdentityProviderMappers(alias).ToListAsync().ConfigureAwait(false); + } + } + return new IdentityProviderDetails( identityProviderId, alias, categoryId, typeId, - identityProviderDataOIDC.DisplayName, - identityProviderDataOIDC.RedirectUrl, - identityProviderDataOIDC.Enabled, - await _provisioningManager.GetIdentityProviderMappers(alias).ToListAsync().ConfigureAwait(false)) - { - oidc = new IdentityProviderDetailsOidc( - identityProviderDataOIDC.AuthorizationUrl, - identityProviderDataOIDC.ClientId, - identityProviderDataOIDC.ClientAuthMethod) - { - signatureAlgorithm = identityProviderDataOIDC.SignatureAlgorithm - } + identityProviderDataOidc?.DisplayName, + identityProviderDataOidc?.RedirectUrl, + identityProviderDataOidc?.Enabled, + identityProviderMapper) + { + oidc = identityProviderDataOidc == null ? + null : + new IdentityProviderDetailsOidc( + identityProviderDataOidc.AuthorizationUrl, + identityProviderDataOidc.ClientId, + identityProviderDataOidc.ClientAuthMethod) + { + signatureAlgorithm = identityProviderDataOidc.SignatureAlgorithm + } }; } - private async ValueTask GetIdentityProviderDetailsSaml(Guid identityProviderId, string alias, IdentityProviderTypeId typeId) + private async ValueTask GetIdentityProviderDetailsSaml(Guid identityProviderId, string? alias, IdentityProviderTypeId typeId) { - var identityProviderDataSAML = await _provisioningManager.GetCentralIdentityProviderDataSAMLAsync(alias).ConfigureAwait(false); + + IdentityProviderConfigSaml? identityProviderDataSaml = null; + IEnumerable? identityProviderMapper = null; + if (!string.IsNullOrWhiteSpace(alias)) + { + bool aliasExisting; + try + { + identityProviderDataSaml = await _provisioningManager + .GetCentralIdentityProviderDataSAMLAsync(alias).ConfigureAwait(false); + aliasExisting = true; + } + catch (KeycloakEntityNotFoundException ex) + { + _logger.LogInformation("Can't receive saml data for {Alias} with following exception {Exception}", alias, ex.Message); + aliasExisting = false; + } + + if (aliasExisting) + { + identityProviderMapper = await _provisioningManager.GetIdentityProviderMappers(alias).ToListAsync() + .ConfigureAwait(false); + } + } + return new IdentityProviderDetails( identityProviderId, alias, IdentityProviderCategoryId.KEYCLOAK_SAML, typeId, - identityProviderDataSAML.DisplayName, - identityProviderDataSAML.RedirectUrl, - identityProviderDataSAML.Enabled, - await _provisioningManager.GetIdentityProviderMappers(alias).ToListAsync().ConfigureAwait(false)) - { - saml = new IdentityProviderDetailsSaml( - identityProviderDataSAML.EntityId, - identityProviderDataSAML.SingleSignOnServiceUrl) + identityProviderDataSaml?.DisplayName, + identityProviderDataSaml?.RedirectUrl, + identityProviderDataSaml?.Enabled, + identityProviderMapper) + { + saml = identityProviderDataSaml == null ? + null : + new IdentityProviderDetailsSaml( + identityProviderDataSaml.EntityId, + identityProviderDataSaml.SingleSignOnServiceUrl) }; } @@ -627,8 +663,12 @@ private async ValueTask UploadOwnCompanyUsersIdenti private async ValueTask<(string? SharedIdpAlias, IEnumerable ValidAliase)> GetCompanyAliasDataAsync(Guid companyId) { - var identityProviderCategoryData = await _portalRepositories.GetInstance().GetCompanyIdentityProviderCategoryDataUntracked(companyId).ToListAsync().ConfigureAwait(false); - var sharedIdpAlias = identityProviderCategoryData.Where(data => data.TypeId == IdentityProviderTypeId.SHARED).Select(data => data.Alias).SingleOrDefault(); + var identityProviderCategoryData = await _portalRepositories.GetInstance() + .GetCompanyIdentityProviderCategoryDataUntracked(companyId) + .Where(data => data.Alias != null) + .Select(data => (data.TypeId, Alias: data.Alias!)) + .ToListAsync().ConfigureAwait(false); + var sharedIdpAlias = identityProviderCategoryData.SingleOrDefault(data => data.TypeId == IdentityProviderTypeId.SHARED).Alias; var validAliase = identityProviderCategoryData.Select(data => data.Alias).ToList(); return (sharedIdpAlias, validAliase); } diff --git a/src/administration/Administration.Service/Models/IdentityProviderDetails.cs b/src/administration/Administration.Service/Models/IdentityProviderDetails.cs index b6c30a2307..5842f77140 100644 --- a/src/administration/Administration.Service/Models/IdentityProviderDetails.cs +++ b/src/administration/Administration.Service/Models/IdentityProviderDetails.cs @@ -25,7 +25,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; -public record IdentityProviderDetails(Guid identityProviderId, string alias, IdentityProviderCategoryId identityProviderCategoryId, IdentityProviderTypeId IdentityProviderTypeId, string displayName, string redirectUrl, bool enabled, IEnumerable mappers) +public record IdentityProviderDetails(Guid identityProviderId, string? alias, IdentityProviderCategoryId identityProviderCategoryId, IdentityProviderTypeId IdentityProviderTypeId, string? displayName, string? redirectUrl, bool? enabled, IEnumerable? mappers) { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public IdentityProviderDetailsOidc? oidc { get; init; } = null; diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs index b49931dff1..ac81163c0c 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IIdentityProviderRepository.cs @@ -35,7 +35,7 @@ public interface IIdentityProviderRepository Task GetIdpCategoryIdByUserIdAsync(Guid companyUserId, Guid userCompanyId); Task<(string? Alias, IdentityProviderCategoryId IamIdentityProviderCategory, bool IsOwnOrOwnerCompany, IdentityProviderTypeId TypeId)> GetOwnCompanyIdentityProviderAliasUntrackedAsync(Guid identityProviderId, Guid companyId); Task<(bool IsOwner, string? Alias, IdentityProviderCategoryId IdentityProviderCategory, IdentityProviderTypeId IdentityProviderTypeId, IEnumerable<(Guid CompanyId, IEnumerable Aliase)>? CompanyIdAliase)> GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(Guid identityProviderId, Guid companyId, bool queryAliase); - IAsyncEnumerable<(Guid IdentityProviderId, IdentityProviderCategoryId CategoryId, string Alias, IdentityProviderTypeId TypeId)> GetCompanyIdentityProviderCategoryDataUntracked(Guid companyId); + IAsyncEnumerable<(Guid IdentityProviderId, IdentityProviderCategoryId CategoryId, string? Alias, IdentityProviderTypeId TypeId)> GetCompanyIdentityProviderCategoryDataUntracked(Guid companyId); IAsyncEnumerable<(Guid IdentityProviderId, string Alias)> GetOwnCompanyIdentityProviderAliasDataUntracked(Guid companyId, IEnumerable identityProviderIds); Task<(string? UserEntityId, string? Alias, bool IsSameCompany)> GetIamUserIsOwnCompanyIdentityProviderAliasAsync(Guid companyUserId, Guid identityProviderId, Guid companyId); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs index 9e490a93b9..3fb45b0deb 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/IdentityProviderRepository.cs @@ -116,11 +116,11 @@ public IamIdentityProvider CreateIamIdentityProvider(Guid identityProviderId, st )) .SingleOrDefaultAsync(); - public IAsyncEnumerable<(Guid IdentityProviderId, IdentityProviderCategoryId CategoryId, string Alias, IdentityProviderTypeId TypeId)> GetCompanyIdentityProviderCategoryDataUntracked(Guid companyId) => + public IAsyncEnumerable<(Guid IdentityProviderId, IdentityProviderCategoryId CategoryId, string? Alias, IdentityProviderTypeId TypeId)> GetCompanyIdentityProviderCategoryDataUntracked(Guid companyId) => _context.IdentityProviders .AsNoTracking() .Where(identityProvider => identityProvider.OwnerId == companyId || identityProvider.Companies.Any(company => company.Id == companyId)) - .Select(identityProvider => new ValueTuple( + .Select(identityProvider => new ValueTuple( identityProvider.Id, identityProvider.IdentityProviderCategoryId, identityProvider.IamIdentityProvider!.IamIdpAlias, diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/iam_identity_providers.consortia.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/iam_identity_providers.consortia.json index eb3920a4c9..ff6493c84c 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/iam_identity_providers.consortia.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/iam_identity_providers.consortia.json @@ -26,9 +26,5 @@ { "iam_idp_alias": "App-Provider", "identity_provider_id": "ac1cf001-7fbc-1f2f-817f-bce057770018" - }, - { - "iam_idp_alias": "keycloak-oidc", - "identity_provider_id": "e7317720-051d-4f4c-9140-ac23c6330351" } ] \ No newline at end of file diff --git a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/identity_providers.consortia.json b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/identity_providers.consortia.json index 213a02c47b..70e941474f 100644 --- a/src/portalbackend/PortalBackend.Migrations/Seeder/Data/identity_providers.consortia.json +++ b/src/portalbackend/PortalBackend.Migrations/Seeder/Data/identity_providers.consortia.json @@ -27,13 +27,6 @@ "identity_provider_type_id": 3, "owner_id": "41fd2ab8-71cd-4546-9bef-a388d91b2542" }, - { - "id": "ac1cf001-7fbc-1f2f-817f-bce0575a0012", - "date_created": "2022-05-05 00:00:00.000000 +00:00", - "identity_provider_category_id": 2, - "identity_provider_type_id": 3, - "owner_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87" - }, { "id": "ac1cf001-7fbc-1f2f-817f-bce057770016", "date_created": "2022-05-05 00:00:00.000000 +00:00", @@ -54,12 +47,5 @@ "identity_provider_category_id": 2, "identity_provider_type_id": 3, "owner_id": "3390c2d7-75c1-4169-aa27-6ce00e1f3cde" - }, - { - "id": "e7317720-051d-4f4c-9140-ac23c6330351", - "date_created": "2022-11-01 00:00:00.000000 +00:00", - "identity_provider_category_id": 2, - "identity_provider_type_id": 2, - "owner_id": "2dc4249f-b5ca-4d42-bef1-7a7a950a4f87" } ] \ No newline at end of file diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs index 7f531c9ba9..be7f6d971f 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/IdentityProviderBusinessLogicTests.cs @@ -19,6 +19,7 @@ ********************************************************************************/ using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic; using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models; @@ -48,6 +49,7 @@ public class IdentityProviderBusinessLogicTests private readonly IOptions _options; private readonly IdentityProviderCsvSettings _csvSettings; private readonly IIdentityService _identityService; + private readonly ILogger _logger; private readonly IFormFile _document; private readonly Encoding _encoding; private readonly Guid _companyId; @@ -74,6 +76,7 @@ public IdentityProviderBusinessLogicTests() _identityService = A.Fake(); _options = A.Fake>(); _document = A.Fake(); + _logger = A.Fake>(); _companyId = _fixture.Create(); _invalidCompanyId = _fixture.Create(); @@ -124,7 +127,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncAllUncha _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var result = await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -159,7 +163,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncWrongCon _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); async Task Act() => await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -207,7 +212,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncEmailCha _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var result = await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -252,7 +258,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncSharedId _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var result = await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -295,7 +302,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncOtherIdp _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var result = await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -337,7 +345,8 @@ public async Task TestUploadOwnCompanyUsersIdentityProviderLinkDataAsyncUnknownC _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var result = await sut.UploadOwnCompanyUsersIdentityProviderLinkDataAsync(_document, _identity.CompanyId, CancellationToken.None).ConfigureAwait(false); @@ -368,7 +377,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithNotSupportedProtocol _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); // Act async Task Act() => await sut.CreateOwnCompanyIdentityProviderAsync(default, IdentityProviderTypeId.OWN, null).ConfigureAwait(false); @@ -388,7 +398,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithDisplayNameToLong_Th _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); // Act async Task Act() => await sut.CreateOwnCompanyIdentityProviderAsync(IamIdentityProviderProtocol.SAML, IdentityProviderTypeId.OWN, display).ConfigureAwait(false); @@ -406,7 +417,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithInvalidCharacterInDi _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); // Act async Task Act() => await sut.CreateOwnCompanyIdentityProviderAsync(IamIdentityProviderProtocol.SAML, IdentityProviderTypeId.OWN, "$invalid-character").ConfigureAwait(false); @@ -428,7 +440,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithInvalidCompany_Throw _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); // Act async Task Act() => await sut.CreateOwnCompanyIdentityProviderAsync(IamIdentityProviderProtocol.SAML, IdentityProviderTypeId.OWN, null).ConfigureAwait(false); @@ -447,7 +460,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithNotAllowedCompanyFor _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); SetupCreateOwnCompanyIdentityProvider(); A.CallTo(() => _identityService.IdentityData).Returns(_identity with { CompanyId = _invalidCompanyId }); @@ -473,7 +487,8 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithValidData_ExecutesEx _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var idpName = _fixture.Create(); @@ -524,6 +539,7 @@ public async Task CreateOwnCompanyIdentityProviderAsync_WithValidData_ExecutesEx x.IamIdpAlias == idpName); result.Should().Match(x => + x.mappers != null && x.mappers.Count() == 3 && x.enabled == true && x.redirectUrl == "https://redirect.com/*" && @@ -552,7 +568,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithNotExistingProvider_Thr _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns(((bool, string?, IdentityProviderCategoryId, IdentityProviderTypeId, IEnumerable<(Guid, IEnumerable)>?))default); @@ -574,7 +591,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithInvalidCompany_ThrowsCo _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((false, string.Empty, IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -596,7 +614,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithManagedIdp_ThrowsConfli _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, string.Empty, IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.MANAGED, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -618,7 +637,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithDisabledIdp_ThrowsContr _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "test", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled(A._)) @@ -643,7 +663,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithSharedKeycloakValid_Cal _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "test", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, new[] { (_companyId, new[] { "other-alias" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("test")) @@ -675,7 +696,8 @@ public async Task DeleteCompanyIdentityProviderAsync_WithValid_CallsExpected() _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "test", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, new[] { (_companyId, new[] { "other-alias" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("test")) @@ -710,11 +732,12 @@ public async Task GetOwnCompanyIdentityProvidersAsync_WithValidId_ReturnsExpecte _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); var oidcGuid = Guid.NewGuid(); var samlGuid = Guid.NewGuid(); - var oidc = new ValueTuple(oidcGuid, IdentityProviderCategoryId.KEYCLOAK_OIDC, "oidc-alias", IdentityProviderTypeId.OWN); - var saml = new ValueTuple(samlGuid, IdentityProviderCategoryId.KEYCLOAK_SAML, "saml-alias", IdentityProviderTypeId.OWN); + var oidc = (oidcGuid, IdentityProviderCategoryId.KEYCLOAK_OIDC, (string?)"oidc-alias", IdentityProviderTypeId.OWN); + var saml = (samlGuid, IdentityProviderCategoryId.KEYCLOAK_SAML, (string?)"saml-alias", IdentityProviderTypeId.OWN); A.CallTo(() => _identityProviderRepository.GetCompanyIdentityProviderCategoryDataUntracked(A._)) .Returns(new[] { oidc, saml }.ToAsyncEnumerable()); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("oidc-alias")) @@ -732,8 +755,8 @@ public async Task GetOwnCompanyIdentityProvidersAsync_WithValidId_ReturnsExpecte // Assert A.CallTo(() => _identityProviderRepository.GetCompanyIdentityProviderCategoryDataUntracked(_companyId)).MustHaveHappenedOnceExactly(); result.Should().HaveCount(2).And.Satisfy( - x => x.displayName == "dis-oidc" && x.mappers.Count() == 3, - x => x.displayName == "dis-saml" && x.mappers.Count() == 2 + x => x.displayName == "dis-oidc" && x.mappers != null && x.mappers.Count() == 3, + x => x.displayName == "dis-saml" && x.mappers != null && x.mappers.Count() == 2 ); } @@ -750,7 +773,8 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithDifferentCompany_Throws _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) .Returns((string.Empty, IdentityProviderCategoryId.KEYCLOAK_OIDC, false, IdentityProviderTypeId.OWN)); @@ -771,9 +795,10 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithAliasNull_ThrowsNotFoun _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) - .Returns(new ValueTuple(null, IdentityProviderCategoryId.KEYCLOAK_OIDC, true, IdentityProviderTypeId.OWN)); + .Returns((null, IdentityProviderCategoryId.KEYCLOAK_OIDC, true, IdentityProviderTypeId.OWN)); // Act async Task Act() => await sut.GetOwnCompanyIdentityProviderAsync(identityProviderId).ConfigureAwait(false); @@ -783,6 +808,31 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithAliasNull_ThrowsNotFoun ex.Message.Should().Be($"identityProvider {identityProviderId} does not exist"); } + [Fact] + public async Task GetOwnCompanyIdentityProviderAsync_WithOidcWithoutExistingKeycloakClient_CallsExpected() + { + // Arrange + var identityProviderId = Guid.NewGuid(); + var sut = new IdentityProviderBusinessLogic( + _portalRepositories, + _provisioningManager, + _identityService, + _options, + _logger); + A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) + .Returns(("cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, true, IdentityProviderTypeId.OWN)); + A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("cl1")) + .Throws(new KeycloakEntityNotFoundException("cl1 not existing")); + + // Act + var result = await sut.GetOwnCompanyIdentityProviderAsync(identityProviderId).ConfigureAwait(false); + + // Assert + result.mappers.Should().BeNull(); + result.displayName.Should().BeNull(); + result.enabled.Should().BeNull(); + } + [Fact] public async Task GetOwnCompanyIdentityProviderAsync_WithValidOidc_CallsExpected() { @@ -792,9 +842,10 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithValidOidc_CallsExpected _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) - .Returns(new ValueTuple("cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, true, IdentityProviderTypeId.OWN)); + .Returns(("cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, true, IdentityProviderTypeId.OWN)); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("cl1")) .Returns(_fixture.Build().With(x => x.Enabled, true).With(x => x.DisplayName, "dis-oidc").Create()); A.CallTo(() => _provisioningManager.GetIdentityProviderMappers("cl1")) @@ -809,6 +860,31 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithValidOidc_CallsExpected result.enabled.Should().BeTrue(); } + [Fact] + public async Task GetOwnCompanyIdentityProviderAsync_WithSamlWithoutExistingKeycloakClient_CallsExpected() + { + // Arrange + var identityProviderId = Guid.NewGuid(); + var sut = new IdentityProviderBusinessLogic( + _portalRepositories, + _provisioningManager, + _identityService, + _options, + _logger); + A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) + .Returns(("saml-alias", IdentityProviderCategoryId.KEYCLOAK_SAML, true, IdentityProviderTypeId.OWN)); + A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataSAMLAsync("saml-alias")) + .Throws(new KeycloakEntityNotFoundException("saml-alias")); + + // Act + var result = await sut.GetOwnCompanyIdentityProviderAsync(identityProviderId).ConfigureAwait(false); + + // Assert + result.mappers.Should().BeNull(); + result.displayName.Should().BeNull(); + result.enabled.Should().BeNull(); + } + [Fact] public async Task GetOwnCompanyIdentityProviderAsync_WithValidSaml_CallsExpected() { @@ -818,9 +894,10 @@ public async Task GetOwnCompanyIdentityProviderAsync_WithValidSaml_CallsExpected _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasUntrackedAsync(identityProviderId, _companyId)) - .Returns(new ValueTuple("saml-alias", IdentityProviderCategoryId.KEYCLOAK_SAML, true, IdentityProviderTypeId.OWN)); + .Returns(("saml-alias", IdentityProviderCategoryId.KEYCLOAK_SAML, true, IdentityProviderTypeId.OWN)); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataSAMLAsync("saml-alias")) .Returns(_fixture.Build().With(x => x.Enabled, true).With(x => x.DisplayName, "dis-saml").Create()); A.CallTo(() => _provisioningManager.GetIdentityProviderMappers("saml-alias")) @@ -848,7 +925,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithDifferentCompany_ _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns(((bool, string?, IdentityProviderCategoryId, IdentityProviderTypeId, IEnumerable<(Guid, IEnumerable)>?))default); @@ -870,7 +948,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithDifferentCompany_ _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((false, string.Empty, IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -892,7 +971,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithNoOtherEnabledIdp _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, new[] { (_companyId, new[] { "alt-cl1" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("alt-cl1")).Returns(false); @@ -916,7 +996,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithNoOtherCompany_Ca _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("cl1")) @@ -944,7 +1025,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithValidOidc_CallsEx _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, new[] { (_companyId, new[] { "alt-cl1" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("alt-cl1")).Returns(true); @@ -974,7 +1056,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithValidSaml_CallsEx _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_SAML, IdentityProviderTypeId.OWN, new[] { (_companyId, new[] { "alt-cl1" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("alt-cl1")).Returns(true); @@ -1002,7 +1085,8 @@ public async Task SetOwnCompanyIdentityProviderStatusAsync_WithValidShared_Calls _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, new[] { (_companyId, new[] { "alt-cl1" }.AsEnumerable()) })); A.CallTo(() => _provisioningManager.IsCentralIdentityProviderEnabled("alt-cl1")).Returns(true); @@ -1041,7 +1125,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_WithInvalidDisplayName_T _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns(((bool, string?, IdentityProviderCategoryId, IdentityProviderTypeId, IEnumerable<(Guid, IEnumerable)>?))default); @@ -1065,7 +1150,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_WithNotExistingIdp_Throw _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns(((bool, string?, IdentityProviderCategoryId, IdentityProviderTypeId, IEnumerable<(Guid, IEnumerable)>?))default); @@ -1089,7 +1175,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_NotOwner_ThrowsForbidden _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((false, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1114,7 +1201,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForOidcWithOidcNull_Thro _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1140,7 +1228,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForOidcWithSamlNotNull_T _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1166,7 +1255,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_WithValidOidc_CallsExpec _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("cl1")) @@ -1198,7 +1288,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForSamlWithSamlNull_Thro _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_SAML, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1224,7 +1315,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForSamlWithOidcNotNull_T _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_SAML, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1250,7 +1342,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_WithValidSaml_CallsExpec _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_SAML, IdentityProviderTypeId.OWN, Enumerable.Empty<(Guid, IEnumerable)>())); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataSAMLAsync("cl1")) @@ -1282,7 +1375,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForSharedWithOidcNotNull _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1308,7 +1402,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_ForSharedWithSamlNotNull _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, Enumerable.Empty<(Guid, IEnumerable)>())); @@ -1334,7 +1429,8 @@ public async Task UpdateOwnCompanyIdentityProviderAsync_WithValidShared_CallsExp _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderUpdateDataUntrackedAsync(A._, A._, A._)) .Returns((true, "cl1", IdentityProviderCategoryId.KEYCLOAK_OIDC, IdentityProviderTypeId.SHARED, Enumerable.Empty<(Guid, IEnumerable)>())); A.CallTo(() => _provisioningManager.GetCentralIdentityProviderDataOIDCAsync("cl1")) @@ -1371,9 +1467,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithoutIamUs _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple()); + .Returns(((string?, string?, bool))default); // Act async Task Act() => await sut.CreateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, data, companyId).ConfigureAwait(false); @@ -1397,9 +1494,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithoutIamUs _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(null, "cl1", false)); + .Returns((null, "cl1", false)); // Act async Task Act() => await sut.CreateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, data, companyId).ConfigureAwait(false); @@ -1424,9 +1522,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithoutAlias _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), null, false)); + .Returns((userEntityId.ToString(), null, false)); // Act async Task Act() => await sut.CreateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, data, companyId).ConfigureAwait(false); @@ -1451,9 +1550,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithoutSameC _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", false)); + .Returns((userEntityId.ToString(), "cl1", false)); // Act async Task Act() => await sut.CreateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, data, companyId).ConfigureAwait(false); @@ -1478,9 +1578,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithKeycloak _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); A.CallTo(() => _provisioningManager.AddProviderUserLinkToCentralUserAsync(userEntityId.ToString(), A._)) .Throws(new KeycloakEntityConflictException("test")); @@ -1508,9 +1609,10 @@ public async Task CreateOwnCompanyUserIdentityProviderLinkDataAsync_WithValid_Ca _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); // Act var result = await sut.CreateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, data, companyId).ConfigureAwait(false); @@ -1539,9 +1641,10 @@ public async Task CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync_With _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple()); + .Returns(((string?, string?, bool))default); // Act async Task Act() => await sut.CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, data, companyId).ConfigureAwait(false); @@ -1565,9 +1668,10 @@ public async Task CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync_With _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(null, "cl1", false)); + .Returns((null, "cl1", false)); // Act async Task Act() => await sut.CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, data, companyId).ConfigureAwait(false); @@ -1592,9 +1696,10 @@ public async Task CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync_With _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), null, false)); + .Returns((userEntityId.ToString(), null, false)); // Act async Task Act() => await sut.CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, data, companyId).ConfigureAwait(false); @@ -1619,9 +1724,10 @@ public async Task CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync_With _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", false)); + .Returns((userEntityId.ToString(), "cl1", false)); // Act async Task Act() => await sut.CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, data, companyId).ConfigureAwait(false); @@ -1646,9 +1752,10 @@ public async Task CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync_With _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); // Act var result = await sut.CreateOrUpdateOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, data, companyId).ConfigureAwait(false); @@ -1676,9 +1783,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithoutIamUserI _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple()); + .Returns(((string?, string?, bool))default); // Act async Task Act() => await sut.GetOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, companyId).ConfigureAwait(false); @@ -1699,9 +1807,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithoutIamUserI _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(null, "cl1", false)); + .Returns((null, "cl1", false)); // Act async Task Act() => await sut.GetOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, companyId).ConfigureAwait(false); @@ -1723,9 +1832,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithoutAlias_Th _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), null, false)); + .Returns((userEntityId.ToString(), null, false)); // Act async Task Act() => await sut.GetOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, companyId).ConfigureAwait(false); @@ -1747,9 +1857,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithoutSameComp _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", false)); + .Returns((userEntityId.ToString(), "cl1", false)); // Act async Task Act() => await sut.GetOwnCompanyUserIdentityProviderLinkDataAsync(companyUserId, identityProviderId, companyId).ConfigureAwait(false); @@ -1771,9 +1882,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithoutExisting _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); A.CallTo(() => _provisioningManager.GetProviderUserLinkDataForCentralUserIdAsync(userEntityId.ToString())) .Returns(Enumerable.Empty().ToAsyncEnumerable()); @@ -1797,9 +1909,10 @@ public async Task GetOwnCompanyUserIdentityProviderLinkDataAsync_WithValid_Calls _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); A.CallTo(() => _provisioningManager.GetProviderUserLinkDataForCentralUserIdAsync(userEntityId.ToString())) .Returns(Enumerable.Repeat(new IdentityProviderLink("cl1", userEntityId.ToString(), "user-name"), 1).ToAsyncEnumerable()); @@ -1826,9 +1939,10 @@ public async Task DeleteOwnCompanyUserIdentityProviderDataAsync_WithKeycloakErro _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); A.CallTo(() => _provisioningManager.DeleteProviderUserLinkToCentralUserAsync(userEntityId.ToString(), "cl1")) .Throws(new KeycloakEntityNotFoundException("just a test")); @@ -1852,9 +1966,10 @@ public async Task DeleteOwnCompanyUserIdentityProviderDataAsync_WithValid_CallsE _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); // Act await sut.DeleteOwnCompanyUserIdentityProviderDataAsync(companyUserId, identityProviderId, companyId).ConfigureAwait(false); @@ -1880,9 +1995,10 @@ public async Task GetOwnCompanyUsersIdentityProviderDataAsync_WithoutIdentityPro _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetIamUserIsOwnCompanyIdentityProviderAliasAsync(companyUserId, identityProviderId, companyId)) - .Returns(new ValueTuple(userEntityId.ToString(), "cl1", true)); + .Returns((userEntityId.ToString(), "cl1", true)); // Act async Task Act() => await sut.GetOwnCompanyUsersIdentityProviderDataAsync(Enumerable.Empty(), companyId, false).ToListAsync().ConfigureAwait(false); @@ -1902,9 +2018,10 @@ public async Task GetOwnCompanyUsersIdentityProviderDataAsync_WithoutMatchingIdp _portalRepositories, _provisioningManager, _identityService, - _options); + _options, + _logger); A.CallTo(() => _identityProviderRepository.GetOwnCompanyIdentityProviderAliasDataUntracked(companyId, A>._)) - .Returns(Enumerable.Empty>().ToAsyncEnumerable()); + .Returns(Enumerable.Empty<(Guid, string)>().ToAsyncEnumerable()); // Act async Task Act() => await sut.GetOwnCompanyUsersIdentityProviderDataAsync(Enumerable.Repeat(identityProviderId, 1), companyId, false).ToListAsync().ConfigureAwait(false); @@ -1921,11 +2038,11 @@ public async Task GetOwnCompanyUsersIdentityProviderDataAsync_WithoutMatchingIdp private void SetupCreateOwnCompanyIdentityProvider(IamIdentityProviderProtocol protocol = IamIdentityProviderProtocol.OIDC, ICollection? idps = null, ICollection? companyIdps = null, ICollection? iamIdps = null) { A.CallTo(() => _companyRepository.CheckCompanyAndCompanyRolesAsync(_identity.CompanyId, A>._)) - .Returns(new ValueTuple(true, "test", true)); + .Returns((true, "test", true)); A.CallTo(() => _companyRepository.CheckCompanyAndCompanyRolesAsync(_invalidCompanyId, A>._)) - .Returns(new ValueTuple(true, "test", false)); + .Returns((true, "test", false)); A.CallTo(() => _companyRepository.CheckCompanyAndCompanyRolesAsync(A.That.Not.Matches(x => x == _identity.CompanyId || x == _invalidCompanyId), A>._)) - .Returns(new ValueTuple()); + .Returns(((bool, string, bool))default); if (idps != null) { @@ -1986,7 +2103,7 @@ private void SetupFakes(IEnumerable userData, IEnumerable A.CallTo(() => _options.Value).Returns(new IdentityProviderSettings { CsvSettings = _csvSettings }); A.CallTo(() => _document.ContentType).Returns(_options.Value.CsvSettings.ContentType); - A.CallTo(() => _document.OpenReadStream()).ReturnsLazily(() => new AsyncEnumerableStringStream(lines.ToAsyncEnumerable(), _encoding)); + A.CallTo(() => _document.OpenReadStream()).Returns(new AsyncEnumerableStringStream(lines.ToAsyncEnumerable(), _encoding)); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_userRepository); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_identityProviderRepository); @@ -1995,18 +2112,18 @@ private void SetupFakes(IEnumerable userData, IEnumerable userData.Where(d => d.CompanyUserId == companyUserId) .Select(d => ( - UserEntityId: d.UserEntityId, - FirstName: d.FirstName, - LastName: d.LastName, - Email: d.Email + d.UserEntityId, + d.FirstName, + d.LastName, + d.Email )).FirstOrDefault()); A.CallTo(() => _identityProviderRepository.GetCompanyIdentityProviderCategoryDataUntracked(A.That.Not.IsEqualTo(_companyId))).Returns( - Enumerable.Empty<(Guid IdentityProviderId, IdentityProviderCategoryId CategoryId, string Alias, IdentityProviderTypeId TypeId)>().ToAsyncEnumerable()); + Enumerable.Empty<(Guid, IdentityProviderCategoryId, string?, IdentityProviderTypeId)>().ToAsyncEnumerable()); A.CallTo(() => _identityProviderRepository.GetCompanyIdentityProviderCategoryDataUntracked(A.That.IsEqualTo(_companyId))).Returns( - new[] { - (IdentityProviderId: _sharedIdentityProviderId, CategoryId: IdentityProviderCategoryId.KEYCLOAK_OIDC, Alias: _sharedIdpAlias, IdentityProviderTypeId.SHARED), - (IdentityProviderId: _otherIdentityProviderId, CategoryId: IdentityProviderCategoryId.KEYCLOAK_OIDC, Alias: _otherIdpAlias, IdentityProviderTypeId.OWN), + new (Guid, IdentityProviderCategoryId, string?, IdentityProviderTypeId)[] { + (_sharedIdentityProviderId, IdentityProviderCategoryId.KEYCLOAK_OIDC, _sharedIdpAlias, IdentityProviderTypeId.SHARED), + (_otherIdentityProviderId, IdentityProviderCategoryId.KEYCLOAK_OIDC, _otherIdpAlias, IdentityProviderTypeId.OWN), }.ToAsyncEnumerable()); A.CallTo(() => _identityProviderRepository.CreateIdentityProvider(A._, A._, A._, A?>._))