Skip to content

Commit

Permalink
fix(registration): fixed the company name change in IDP (#1010)
Browse files Browse the repository at this point in the history
* in registration, if company-name is changed rename
the displayname in shared idp and update the
idp's organisation-mapper accordingly.
* added the unit test and updated the existing one
---------
Co-authored-by: Norbert Truchsess <[email protected]>
  • Loading branch information
dhiren-singh-007 authored Nov 5, 2024
1 parent 6103bde commit af32ca4
Show file tree
Hide file tree
Showing 12 changed files with 377 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLog
public class UserBusinessLogic(
IProvisioningManager provisioningManager,
IUserProvisioningService userProvisioningService,
IIdentityProviderProvisioningService identityProviderProvisioningService,
IProvisioningDBAccess provisioningDbAccess,
IPortalRepositories portalRepositories,
IIdentityService identityService,
Expand Down Expand Up @@ -96,7 +97,7 @@ private async IAsyncEnumerable<string> CreateOwnCompanyUsersInternalAsync(IEnume
user => user.userName ?? user.eMail,
user => user.eMail);

var companyDisplayName = await userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
var companyDisplayName = await identityProviderProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

await foreach (var (companyUserId, userName, password, error) in userProvisioningService.CreateOwnCompanyIdpUsersAsync(companyNameIdpAliasData, userCreationInfoIdps).ConfigureAwait(false))
{
Expand Down Expand Up @@ -137,7 +138,7 @@ private Task<IEnumerable<UserRoleData>> GetOwnCompanyUserRoleData(IEnumerable<st
public async Task<Guid> CreateOwnCompanyIdpUserAsync(Guid identityProviderId, UserCreationInfoIdp userCreationInfo)
{
var (companyNameIdpAliasData, nameCreatedBy) = await userProvisioningService.GetCompanyNameIdpAliasData(identityProviderId, _identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None);
var displayName = await userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
var displayName = await identityProviderProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

if (!userCreationInfo.Roles.Any())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLog
public class UserUploadBusinessLogic : IUserUploadBusinessLogic
{
private readonly IUserProvisioningService _userProvisioningService;
private readonly IIdentityProviderProvisioningService _identityProviderProvisioningServcie;
private readonly IMailingProcessCreation _mailingProcessCreation;
private readonly UserSettings _settings;
private readonly IIdentityData _identityData;
Expand All @@ -45,18 +46,21 @@ public class UserUploadBusinessLogic : IUserUploadBusinessLogic
/// Constructor.
/// </summary>
/// <param name="userProvisioningService">User Provisioning Service</param>
/// <param name="identityProviderProvisioningService">IdentityProvider Provisioning Service</param>
/// <param name="mailingProcessCreation">The mailingProcessCreation</param>
/// <param name="identityService">Access to the identity Service</param>
/// <param name="errorMessageService">ErrorMessage Service</param>
/// <param name="settings">Settings</param>
public UserUploadBusinessLogic(
IUserProvisioningService userProvisioningService,
IIdentityProviderProvisioningService identityProviderProvisioningService,
IMailingProcessCreation mailingProcessCreation,
IIdentityService identityService,
IErrorMessageService errorMessageService,
IOptions<UserSettings> settings)
{
_userProvisioningService = userProvisioningService;
_identityProviderProvisioningServcie = identityProviderProvisioningService;
_mailingProcessCreation = mailingProcessCreation;
_identityData = identityService.IdentityData;
_errorMessageService = errorMessageService;
Expand All @@ -79,7 +83,7 @@ private async ValueTask<UserCreationStats> UploadOwnCompanyIdpUsersInternalAsync

var displayName = companyNameIdpAliasData.IsSharedIdp
? null
: await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
: await _identityProviderProvisioningServcie.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

var (numCreated, numLines, errors) = await CsvParser.ProcessCsvAsync(
stream,
Expand Down Expand Up @@ -162,7 +166,7 @@ private async ValueTask<UserCreationStats> UploadOwnCompanySharedIdpUsersInterna
using var stream = document.OpenReadStream();

var (companyNameIdpAliasData, nameCreatedBy) = await _userProvisioningService.GetCompanyNameSharedIdpAliasData(_identityData.IdentityId).ConfigureAwait(ConfigureAwaitOptions.None);
var displayName = await _userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
var displayName = await _identityProviderProvisioningServcie.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;

var validRoleData = new List<UserRoleData>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,39 @@ public async IAsyncEnumerable<IdentityProviderMapperModel> GetIdentityProviderMa
public async Task<string?> GetIdentityProviderDisplayName(string alias) =>
(await GetCentralIdentityProviderAsync(alias).ConfigureAwait(ConfigureAwaitOptions.None)).DisplayName;

public async Task UpdateOrCreateCentralIdentityProviderOrganisationMapperAsync(string idpAlias, string organisationName)
{
var mapperName = _settings.MappedCompanyAttribute + "-mapper";
IdentityProviderMapper? mapper;
try
{
mapper = (await _centralIdp.GetIdentityProviderMappersAsync(_settings.CentralRealm, idpAlias).ConfigureAwait(ConfigureAwaitOptions.None))
.SingleOrDefault(z => z.Name == mapperName);
}
catch (InvalidOperationException)
{
throw new KeycloakEntityConflictException($"idp {idpAlias} attribute-mapper {mapperName} is ambigous in keycloak");
}
if (mapper is null)
{
await CreateCentralIdentityProviderOrganisationMapperAsync(idpAlias, organisationName);
}
else
{
mapper.Config ??= new Dictionary<string, string>
{
["syncMode"] = "INHERIT",
["attribute"] = _settings.MappedCompanyAttribute,
};
mapper.Config["attribute.value"] = organisationName;
await _centralIdp.UpdateIdentityProviderMapperAsync(
_settings.CentralRealm,
idpAlias,
mapper.Id ?? throw new KeycloakEntityConflictException($"idp {idpAlias} attribute-mapper {mapperName} has no Id"),
mapper).ConfigureAwait(ConfigureAwaitOptions.None);
}
}

private async ValueTask<string> GetCentralBrokerEndpointOIDCAsync(string alias)
{
var openidconfig = await _centralIdp.GetOpenIDConfigurationAsync(_settings.CentralRealm).ConfigureAwait(ConfigureAwaitOptions.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ public interface IProvisioningManager
Task<string?> GetIdentityProviderDisplayName(string alias);
Task DeleteSharedRealmAsync(string alias);
Task DeleteIdpSharedServiceAccount(string alias);
Task UpdateOrCreateCentralIdentityProviderOrganisationMapperAsync(string idpAlias, string organisationName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/********************************************************************************
* 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
********************************************************************************/

namespace Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service;

public interface IIdentityProviderProvisioningService
{
Task<string?> GetIdentityProviderDisplayName(string idpAlias);
Task UpdateCompanyNameInSharedIdentityProvider(Guid companyId, string companyName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public interface IUserProvisioningService
Task HandleCentralKeycloakCreation(UserCreationRoleDataIdpInfo user, Guid companyUserId, string companyName, string? businessPartnerNumber, Identity? identity, IEnumerable<IdentityProviderLink> identityProviderLinks, IUserRepository userRepository, IUserRolesRepository userRolesRepository);
Task<(CompanyNameIdpAliasData IdpAliasData, string NameCreatedBy)> GetCompanyNameIdpAliasData(Guid identityProviderId, Guid companyUserId);
Task<(CompanyNameIdpAliasData IdpAliasData, string NameCreatedBy)> GetCompanyNameSharedIdpAliasData(Guid companyUserId, Guid? applicationId = null);
Task<string?> GetIdentityProviderDisplayName(string idpAlias);
IAsyncEnumerable<UserRoleData> GetRoleDatas(IEnumerable<UserRoleConfig> clientRoles);
Task<IEnumerable<UserRoleData>> GetOwnCompanyPortalRoleDatas(string clientId, IEnumerable<string> roles, Guid companyId);
Task<(Identity? Identity, Guid CompanyUserId)> GetOrCreateCompanyUser(IUserRepository userRepository, string alias, UserCreationRoleDataIdpInfo user, Guid companyId, Guid identityProviderId, string? businessPartnerNumber);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/********************************************************************************
* 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 Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;

namespace Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service;

public class IdentityProviderProvisioningService(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager) : IIdentityProviderProvisioningService
{
public Task<string?> GetIdentityProviderDisplayName(string idpAlias) =>
provisioningManager.GetCentralIdentityProviderDisplayName(idpAlias);

public async Task UpdateCompanyNameInSharedIdentityProvider(Guid companyId, string companyName)
{
var idpAlias = await portalRepositories.GetInstance<IIdentityProviderRepository>().GetSharedIdentityProviderIamAliasDataUntrackedAsync(companyId).ConfigureAwait(false) ?? throw new ConflictException($"company {companyId} is not associated with any shared idp");
await provisioningManager.UpdateSharedIdentityProviderAsync(idpAlias, companyName).ConfigureAwait(false);
await provisioningManager.UpdateOrCreateCentralIdentityProviderOrganisationMapperAsync(idpAlias, companyName).ConfigureAwait(ConfigureAwaitOptions.None);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,6 @@ private Task<string> CreateSharedIdpUserOrReturnUserId(UserCreationRoleDataIdpIn
return (new CompanyNameIdpAliasData(company.CompanyId, company.CompanyName, company.BusinessPartnerNumber, idpAlias.Alias, idpAlias.IdentityProviderId, true), createdByName);
}

public Task<string?> GetIdentityProviderDisplayName(string idpAlias) =>
_provisioningManager.GetCentralIdentityProviderDisplayName(idpAlias);

private async Task<Guid> ValidateDuplicateIdpUsersAsync(IUserRepository userRepository, string alias, UserCreationRoleDataIdpInfo user, Guid companyId)
{
var existingCompanyUserId = Guid.Empty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class RegistrationBusinessLogic(
IOptions<RegistrationSettings> settings,
IBpnAccess bpnAccess,
IUserProvisioningService userProvisioningService,
IIdentityProviderProvisioningService identityProviderProvisioningService,
ILogger<RegistrationBusinessLogic> logger,
IPortalRepositories portalRepositories,
IApplicationChecklistCreationService checklistService,
Expand Down Expand Up @@ -254,15 +255,18 @@ await companyDetails.ValidateDatabaseData(
var companyRepository = portalRepositories.GetInstance<ICompanyRepository>();

var companyApplicationData = await GetAndValidateApplicationData(applicationId, companyDetails, applicationRepository).ConfigureAwait(ConfigureAwaitOptions.None);

var existingCompanyName = companyApplicationData.Name;
var addressId = CreateOrModifyAddress(companyApplicationData, companyDetails, companyRepository);

ModifyCompany(addressId, companyApplicationData, companyDetails, companyRepository);

companyRepository.CreateUpdateDeleteIdentifiers(companyDetails.CompanyId, companyApplicationData.UniqueIds, companyDetails.UniqueIds.Select(x => (x.UniqueIdentifierId, x.Value)));

UpdateApplicationStatus(applicationId, companyApplicationData.ApplicationStatusId, UpdateApplicationSteps.CompanyWithAddress, applicationRepository, dateTimeProvider);

if (existingCompanyName != companyDetails.Name)
{
await identityProviderProvisioningService.UpdateCompanyNameInSharedIdentityProvider(_identityData.CompanyId, companyDetails.Name).ConfigureAwait(ConfigureAwaitOptions.None);
}
await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);
}

Expand Down Expand Up @@ -409,7 +413,7 @@ private async Task<int> InviteNewUserInternalAsync(Guid applicationId, UserCreat

var modified = await portalRepositories.SaveAsync().ConfigureAwait(ConfigureAwaitOptions.None);

var companyDisplayName = await userProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
var companyDisplayName = await identityProviderProvisioningService.GetIdentityProviderDisplayName(companyNameIdpAliasData.IdpAlias).ConfigureAwait(ConfigureAwaitOptions.None) ?? companyNameIdpAliasData.IdpAlias;
var mailParameters = ImmutableDictionary.CreateRange(new[]
{
KeyValuePair.Create("password", password),
Expand Down
Loading

0 comments on commit af32ca4

Please sign in to comment.