Skip to content

Commit

Permalink
fix(idp): adjust get idps endpoints (#267)
Browse files Browse the repository at this point in the history
* fix GET: api/administration/identityprovider/owncompany/identityproviders
* fix GET: api/administration/identityprovider/owncompany/identityproviders/{identityTypeId}
Refs: CPLP-3247
---------
Co-authored-by: Norbert Truchsess <[email protected]>
Reviewed-By: Norbert Truchsess <[email protected]>
  • Loading branch information
Phil91 authored Sep 14, 2023
1 parent 43b8f36 commit c45b436
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,46 +42,31 @@ public class IdentityProviderBusinessLogic : IIdentityProviderBusinessLogic
private readonly IPortalRepositories _portalRepositories;
private readonly IProvisioningManager _provisioningManager;
private readonly IIdentityService _identityService;
private readonly ILogger<IdentityProviderBusinessLogic> _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<IdentityProviderSettings> options)
public IdentityProviderBusinessLogic(IPortalRepositories portalRepositories, IProvisioningManager provisioningManager, IIdentityService identityService, IOptions<IdentityProviderSettings> options, ILogger<IdentityProviderBusinessLogic> logger)
{
_portalRepositories = portalRepositories;
_provisioningManager = provisioningManager;
_identityService = identityService;
_settings = options.Value;
_logger = logger;
}

public async IAsyncEnumerable<IdentityProviderDetails> GetOwnCompanyIdentityProvidersAsync()
{
var companyId = _identityService.IdentityData.CompanyId;
await foreach (var identityProviderData in _portalRepositories.GetInstance<IIdentityProviderRepository>().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}'")
};
}
}

Expand All @@ -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!?@&#'\"()_-=/*.,;: '");
}
Expand Down Expand Up @@ -392,45 +377,96 @@ public async ValueTask DeleteCompanyIdentityProviderAsync(Guid identityProviderI
return (alias, typeId);
}

private async ValueTask<IdentityProviderDetails> GetIdentityProviderDetailsOidc(Guid identityProviderId, string alias, IdentityProviderCategoryId categoryId, IdentityProviderTypeId typeId)
private async ValueTask<IdentityProviderDetails> GetIdentityProviderDetailsOidc(Guid identityProviderId, string? alias, IdentityProviderCategoryId categoryId, IdentityProviderTypeId typeId)
{
var identityProviderDataOIDC = await _provisioningManager.GetCentralIdentityProviderDataOIDCAsync(alias).ConfigureAwait(false);
IdentityProviderConfigOidc? identityProviderDataOidc = null;
IEnumerable<IdentityProviderMapperModel>? 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<IdentityProviderDetails> GetIdentityProviderDetailsSaml(Guid identityProviderId, string alias, IdentityProviderTypeId typeId)
private async ValueTask<IdentityProviderDetails> GetIdentityProviderDetailsSaml(Guid identityProviderId, string? alias, IdentityProviderTypeId typeId)
{
var identityProviderDataSAML = await _provisioningManager.GetCentralIdentityProviderDataSAMLAsync(alias).ConfigureAwait(false);

IdentityProviderConfigSaml? identityProviderDataSaml = null;
IEnumerable<IdentityProviderMapperModel>? 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)
};
}

Expand Down Expand Up @@ -627,8 +663,12 @@ private async ValueTask<IdentityProviderUpdateStats> UploadOwnCompanyUsersIdenti

private async ValueTask<(string? SharedIdpAlias, IEnumerable<string> ValidAliase)> GetCompanyAliasDataAsync(Guid companyId)
{
var identityProviderCategoryData = await _portalRepositories.GetInstance<IIdentityProviderRepository>().GetCompanyIdentityProviderCategoryDataUntracked(companyId).ToListAsync().ConfigureAwait(false);
var sharedIdpAlias = identityProviderCategoryData.Where(data => data.TypeId == IdentityProviderTypeId.SHARED).Select(data => data.Alias).SingleOrDefault();
var identityProviderCategoryData = await _portalRepositories.GetInstance<IIdentityProviderRepository>()
.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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IdentityProviderMapperModel> mappers)
public record IdentityProviderDetails(Guid identityProviderId, string? alias, IdentityProviderCategoryId identityProviderCategoryId, IdentityProviderTypeId IdentityProviderTypeId, string? displayName, string? redirectUrl, bool? enabled, IEnumerable<IdentityProviderMapperModel>? mappers)
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IdentityProviderDetailsOidc? oidc { get; init; } = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface IIdentityProviderRepository
Task<IdpUser?> 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<string> 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<Guid> identityProviderIds);
Task<(string? UserEntityId, string? Alias, bool IsSameCompany)> GetIamUserIsOwnCompanyIdentityProviderAliasAsync(Guid companyUserId, Guid identityProviderId, Guid companyId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Guid, IdentityProviderCategoryId, string, IdentityProviderTypeId>(
.Select(identityProvider => new ValueTuple<Guid, IdentityProviderCategoryId, string?, IdentityProviderTypeId>(
identityProvider.Id,
identityProvider.IdentityProviderCategoryId,
identityProvider.IamIdentityProvider!.IamIdpAlias,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
]
Loading

0 comments on commit c45b436

Please sign in to comment.