Skip to content

Commit

Permalink
build: merge main to dev #474
Browse files Browse the repository at this point in the history
Reviewed-By: Evelyn Gurschler <[email protected]>
  • Loading branch information
Phil91 authored Jan 31, 2024
2 parents b5587dc + f143f34 commit 98e51c2
Show file tree
Hide file tree
Showing 38 changed files with 1,068 additions and 249 deletions.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Link to Github issue.

Please delete options that are not relevant.

- [ ] I have followed the [contributing guidelines](https://github.com/eclipse-tractusx/portal-assets/blob/main/developer/Technical%20Documentation/Dev%20Process/How%20to%20contribute.md#commit-and-pr-guidelines)
- [ ] I have followed the [contributing guidelines](https://github.com/eclipse-tractusx/portal-assets/blob/main/docs/developer/Technical%20Documentation/Dev%20Process/How%20to%20contribute.md#commit-and-pr-guidelines)
- [ ] I have performed [IP checks](https://eclipse-tractusx.github.io/docs/release/trg-7/trg-7-04#checking-libraries-using-the-eclipse-dash-license-tool) for added or updated 3rd party libraries
- [ ] I have created and linked IP issues or requested their creation by a committer
- [ ] I have performed a self-review of my own code
Expand Down
68 changes: 54 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,69 @@

New features, fixed bugs, known defects and other noteworthy changes to each release of the Catena-X Portal Backend.

## 1.8.0-RC4

### Change
* updated response body of the GET: /api/administration/user/owncompany/users endpoint by changing the "role" section to an array to include role client information ![Tag](https://img.shields.io/static/v1?label=&message=BreakingChange&color=yellow&style=flat)
* pattern harmonization of 'company name' insert endpoints
* POST: api/administration/invitation
* POST: api/administration/registration/network/partnerRegistration
* POST: api/registration/application/{applicationId}/companyDetailsWithAddress
* PUT: /api/apps/appreleaseprocess/{appID}
* POST: /api/apps/appreleaseprocess/createapp
* pattern harmonization of 'company name' search endpoints
* GET: api/administration/registration/applicationsWithStatus
* GET: api/administration/registration/applications
* adjusted business logic of post/put BPN endpoints to allow the post/put of lowercase BPNs and ensure the transition to all uppercase by the backend logic (connector controller, registration controller, user controller)

### Feature
* Administration Service
* API endpoints for user account creation backend logic updated to set the providerID (unique username on the IdP which holds the user identity) is getting stored inside the portal db
* POST: /api/administration/identityprovider/owncompany/usersfile
* POST: /api/administration/registration/network/{externalId}/partnerRegistration
* POST: /api/administration/invitation
* POST: /api/administration/user/owncompany/users
* POST: /api/administration/user/owncompany/identityprovider/{identityProviderId}/users
* POST: /api/administration/user/owncompany/identityprovider/{identityProviderId}/usersfile
* POST: /api/administration/user/owncompany/usersfile
* POST: /api/registration/application/{applicationId}/inviteNewUser
* added additional user identity provider attributes (such as idpDisplayName and providerID) for all GET user account data
* GET: /api/administration/user/owncompany/users?page=0&size=5
* GET: /api/administration/user/owncompany/users/{userId}
* GET: /api/administration/user/ownUser

### Technical Support
* fixed sonar cloud finding to use correct pagination params

### Bugfix
* changed claimTypes static class of clientId claim to client_id

### Known Knowns
n/a

## 1.8.0-RC3

### Change
- External Interface Details
- BPDM interface refactored - bpdm push process was updated to support the new interface spec of the bpdm gate service
- Clearinghouse interface updated - possible generated clearinghouse service error content is getting saved inside the application comment level
- Email Template "cx_admin_invitation" enhanced by adding the section and link of the decline url (portal-frontend implementation)
* External Interface Details
* BPDM interface refactored - bpdm push process was updated to support the new interface spec of the bpdm gate service
* Clearinghouse interface updated - possible generated clearinghouse service error content is getting saved inside the application comment level
* Email Template "cx_admin_invitation" enhanced by adding the section and link of the decline url (portal-frontend implementation)

### Feature
- Onboarding Service Provider Function
- enabled deactivation of managed idps (administration service) via the existing idp status update endpoint
- enabled deletion of managed idps (administration service) via the existing idp delete endpoint
- added new endpoint to enable customer to decline their own company application which was created by an osp
* Onboarding Service Provider Function
* enabled deactivation of managed idps (administration service) via the existing idp status update endpoint
* enabled deletion of managed idps (administration service) via the existing idp delete endpoint
* added new endpoint to enable customer to decline their own company application which was created by an osp

### Technical Support
- Release workflow updated by adding additional image tag of type semver
- Upgraded external packages with security vulnerabilities
* Release workflow updated by adding additional image tag of type semver
* Upgraded external packages with security vulnerabilities

### Bugfix
- Endpoint authorization on valid companyId added for
- POST: /api/apps/appreleaseprocess/consent/{appId}/agreementConsents
- POST: /api/services/servicerelease/consent/{serviceId}/agreementConsents
- Adjusted endpoint GET: api/administration/serviceaccount/owncompany/serviceaccounts to filter for active service accounts by default if no parameter is submitted
* Endpoint authorization on valid companyId added for
* POST: /api/apps/appreleaseprocess/consent/{appId}/agreementConsents
* POST: /api/services/servicerelease/consent/{serviceId}/agreementConsents
* Adjusted endpoint GET: api/administration/serviceaccount/owncompany/serviceaccounts to filter for active service accounts by default if no parameter is submitted

## 1.8.0-RC2

Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>1.8.0</VersionPrefix>
<VersionSuffix>RC3</VersionSuffix>
<VersionSuffix>RC4</VersionSuffix>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ public IAsyncEnumerable<ConnectorEndPointData> GetCompanyConnectorEndPointAsync(
}

return _portalRepositories.GetInstance<IConnectorsRepository>()
.GetConnectorEndPointDataAsync(bpns)
.GetConnectorEndPointDataAsync(bpns.Select(x => x.ToUpper()))
.PreSortedGroupBy(data => data.BusinessPartnerNumber)
.Select(group =>
new ConnectorEndPointData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface IUserBusinessLogic
Task<Pagination.Response<CompanyUserData>> GetOwnCompanyUserDatasAsync(int page, int size, GetOwnCompanyUsersFilter filter);
[Obsolete("to be replaced by UserRolesBusinessLogic.GetAppRolesAsync. Remove as soon frontend is adjusted")]
IAsyncEnumerable<ClientRoles> GetClientRolesAsync(Guid appId, string? languageShortName = null);
Task<CompanyUserDetails> GetOwnCompanyUserDetailsAsync(Guid userId);
Task<CompanyUserDetailData> GetOwnCompanyUserDetailsAsync(Guid userId);
Task<int> AddOwnCompanyUsersBusinessPartnerNumbersAsync(Guid userId, IEnumerable<string> businessPartnerNumbers);
Task<int> AddOwnCompanyUsersBusinessPartnerNumberAsync(Guid userId, string businessPartnerNumber);
Task<CompanyOwnUserDetails> GetOwnUserDetails();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,6 @@ public async ValueTask DeleteCompanyIdentityProviderAsync(Guid identityProviderI
}

identityProviderRepository.DeleteIdentityProvider(identityProviderId);

await _portalRepositories.SaveAsync().ConfigureAwait(false);
}

Expand Down Expand Up @@ -743,7 +742,7 @@ private async ValueTask<IdentityProviderUpdateStats> UploadOwnCompanyUsersIdenti
{
var userRepository = _portalRepositories.GetInstance<IUserRepository>();
var companyId = _identityData.CompanyId;
var (sharedIdpAlias, existingAliase) = await GetCompanyAliasDataAsync(companyId).ConfigureAwait(false);
var (sharedIdp, existingAliase) = await GetCompanyAliasDataAsync(companyId).ConfigureAwait(false);

using var stream = document.OpenReadStream();

Expand All @@ -755,8 +754,8 @@ private async ValueTask<IdentityProviderUpdateStats> UploadOwnCompanyUsersIdenti
{
numIdps = ParseCSVFirstLineReturningNumIdps(line);
},
line => ParseCSVLine(line, numIdps, existingAliase),
lines => ProcessOwnCompanyUsersIdentityProviderLinkDataInternalAsync(lines, userRepository, companyId, sharedIdpAlias, cancellationToken),
line => ParseCSVLine(line, numIdps, existingAliase.Select(x => x.Alias)),
lines => ProcessOwnCompanyUsersIdentityProviderLinkDataInternalAsync(lines, userRepository, companyId, sharedIdp, existingAliase, cancellationToken),
cancellationToken
).ConfigureAwait(false);

Expand All @@ -782,7 +781,8 @@ private UserUpdateError CreateUserUpdateError(int line, Exception error) =>
IAsyncEnumerable<(Guid CompanyUserId, UserProfile UserProfile, IEnumerable<IdentityProviderLink> IdentityProviderLinks)> userProfileLinkDatas,
IUserRepository userRepository,
Guid companyId,
string? sharedIdpAlias,
(Guid IdentityProviderId, string Alias) sharedIdp,
IEnumerable<(Guid IdentityProviderId, string Alias)> existingIdps,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var (companyUserId, profile, identityProviderLinks) in userProfileLinkDatas)
Expand All @@ -799,12 +799,12 @@ private UserUpdateError CreateUserUpdateError(int line, Exception error) =>

foreach (var identityProviderLink in identityProviderLinks)
{
updated |= await UpdateIdentityProviderLinksAsync(iamUserId, companyUserId, identityProviderLink, existingLinks, sharedIdpAlias).ConfigureAwait(false);
updated |= await UpdateIdentityProviderLinksAsync(iamUserId, companyUserId, identityProviderLink, existingLinks, sharedIdp, existingIdps).ConfigureAwait(false);
}

if (existingProfile != profile)
{
await UpdateUserProfileAsync(userRepository, iamUserId, companyUserId, profile, existingLinks, sharedIdpAlias).ConfigureAwait(false);
await UpdateUserProfileAsync(userRepository, iamUserId, companyUserId, profile, existingLinks, sharedIdp).ConfigureAwait(false);
updated = true;
}
success = updated;
Expand All @@ -821,15 +821,15 @@ private UserUpdateError CreateUserUpdateError(int line, Exception error) =>
}
}

private async ValueTask<(string? SharedIdpAlias, IEnumerable<string> ValidAliase)> GetCompanyAliasDataAsync(Guid companyId)
private async ValueTask<((Guid IdentityProviderId, string Alias) SharedIdp, IEnumerable<(Guid IdentityProviderId, string Alias)> ValidAliase)> GetCompanyAliasDataAsync(Guid companyId)
{
var identityProviderCategoryData = await _portalRepositories.GetInstance<IIdentityProviderRepository>()
.GetCompanyIdentityProviderCategoryDataUntracked(companyId)
.Where(data => data.Alias != null)
.Select(data => (data.TypeId, Alias: data.Alias!))
.Select(data => (data.IdentityProviderId, 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();
var sharedIdpAlias = identityProviderCategoryData.Where(data => data.TypeId == IdentityProviderTypeId.SHARED).Select(data => (data.IdentityProviderId, data.Alias)).SingleOrDefault();
var validAliase = identityProviderCategoryData.Select(data => (data.IdentityProviderId, data.Alias)).ToList();
return (sharedIdpAlias, validAliase);
}

Expand All @@ -851,7 +851,13 @@ private UserUpdateError CreateUserUpdateError(int line, Exception error) =>
);
}

private async ValueTask<bool> UpdateIdentityProviderLinksAsync(string iamUserId, Guid companyUserId, IdentityProviderLink identityProviderLink, IEnumerable<IdentityProviderLink> existingLinks, string? sharedIdpAlias)
private async ValueTask<bool> UpdateIdentityProviderLinksAsync(
string iamUserId,
Guid companyUserId,
IdentityProviderLink identityProviderLink,
IEnumerable<IdentityProviderLink> existingLinks,
(Guid IdentityProviderId, string Alias) sharedIdp,
IEnumerable<(Guid IdentityProviderId, string Alias)> existingIdps)
{
var (alias, userId, userName) = identityProviderLink;

Expand All @@ -863,7 +869,7 @@ private async ValueTask<bool> UpdateIdentityProviderLinksAsync(string iamUserId,
return false;
}

if (alias == sharedIdpAlias)
if (alias == sharedIdp.Alias)
{
throw new ControllerArgumentException($"unexpected update of shared identityProviderLink, alias '{alias}', companyUser '{companyUserId}', providerUserId: '{userId}', providerUserName: '{userName}'");
}
Expand All @@ -873,23 +879,49 @@ private async ValueTask<bool> UpdateIdentityProviderLinksAsync(string iamUserId,
await _provisioningManager.DeleteProviderUserLinkToCentralUserAsync(iamUserId, alias).ConfigureAwait(false);
}
await _provisioningManager.AddProviderUserLinkToCentralUserAsync(iamUserId, identityProviderLink).ConfigureAwait(false);
await InsertUpdateCompanyUserAssignedIdentityProvider(companyUserId, existingIdps.Single(x => x.Alias == alias).IdentityProviderId, identityProviderLink).ConfigureAwait(false);
return true;
}

private async ValueTask UpdateUserProfileAsync(IUserRepository userRepository, string iamUserId, Guid companyUserId, UserProfile profile, IEnumerable<IdentityProviderLink> existingLinks, string? sharedIdpAlias)
private async Task InsertUpdateCompanyUserAssignedIdentityProvider(Guid companyUserId, Guid identityProviderId, IdentityProviderLink providerLink)
{
var userRepository = _portalRepositories.GetInstance<IUserRepository>();
var data = await userRepository.GetCompanyUserAssignedIdentityProvider(companyUserId, identityProviderId).ConfigureAwait(false);
if (data == default)
{
userRepository.AddCompanyUserAssignedIdentityProvider(companyUserId, identityProviderId, providerLink.UserId, providerLink.UserName);
}
else
{
userRepository.AttachAndModifyUserAssignedIdentityProvider(companyUserId, identityProviderId,
uaip =>
{
uaip.ProviderId = data.ProviderId;
uaip.UserName = data.Username;
},
uaip =>
{
uaip.ProviderId = providerLink.UserId;
uaip.UserName = providerLink.UserName;
});
}
}

private async ValueTask UpdateUserProfileAsync(IUserRepository userRepository, string iamUserId, Guid companyUserId, UserProfile profile, IEnumerable<IdentityProviderLink> existingLinks, (Guid IdentityProviderId, string Alias) sharedIdp)
{
var (firstName, lastName, email) = (profile.FirstName ?? "", profile.LastName ?? "", profile.Email ?? "");

await _provisioningManager.UpdateCentralUserAsync(iamUserId, firstName, lastName, email).ConfigureAwait(false);

if (sharedIdpAlias != null)
if (sharedIdp != default)
{
var sharedIdpLink = existingLinks.FirstOrDefault(link => link.Alias == sharedIdpAlias);
var sharedIdpLink = existingLinks.FirstOrDefault(link => link.Alias == sharedIdp.Alias);
if (sharedIdpLink != default)
{
await _provisioningManager.UpdateSharedRealmUserAsync(sharedIdpAlias, sharedIdpLink.UserId, firstName, lastName, email).ConfigureAwait(false);
await _provisioningManager.UpdateSharedRealmUserAsync(sharedIdp.Alias, sharedIdpLink.UserId, firstName, lastName, email).ConfigureAwait(false);
}
}

userRepository.AttachAndModifyCompanyUser(companyUserId, null, companyUser =>
{
companyUser.Firstname = profile.FirstName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Microsoft.Extensions.Options;
using Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
Expand All @@ -29,11 +30,13 @@
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Models;
using Org.Eclipse.TractusX.Portal.Backend.Provisioning.Library.Service;
using System.Text.RegularExpressions;

namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.BusinessLogic;

public class InvitationBusinessLogic : IInvitationBusinessLogic
{
private static readonly Regex Company = new(ValidationExpressions.Company, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private readonly IProvisioningManager _provisioningManager;
private readonly IUserProvisioningService _userProvisioningService;
private readonly IPortalRepositories _portalRepositories;
Expand Down Expand Up @@ -72,6 +75,10 @@ public Task ExecuteInvitation(CompanyInvitationData invitationData)
{
throw new ControllerArgumentException("organisationName must not be empty", "organisationName");
}
if (!string.IsNullOrEmpty(invitationData.organisationName) && !Company.IsMatch(invitationData.organisationName))
{
throw new ControllerArgumentException("OrganisationName length must be 3-40 characters and *+=#%\\s not used as one of the first three characters in the Organisation name", "organisationName");
}
return ExecuteInvitationInternalAsync(invitationData);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class NetworkBusinessLogic : INetworkBusinessLogic
{
private static readonly Regex Name = new(ValidationExpressions.Name, RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex ExternalID = new("^[A-Za-z0-9\\-+_/,.]{6,36}$", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
private static readonly Regex Company = new(ValidationExpressions.Company, RegexOptions.Compiled, TimeSpan.FromSeconds(1));

private readonly IPortalRepositories _portalRepositories;
private readonly IIdentityData _identityData;
Expand All @@ -59,6 +60,10 @@ public NetworkBusinessLogic(IPortalRepositories portalRepositories, IIdentitySer

public async Task HandlePartnerRegistration(PartnerRegistrationData data)
{
if (!string.IsNullOrEmpty(data.Name) && !Company.IsMatch(data.Name))
{
throw new ControllerArgumentException("OrganisationName length must be 3-40 characters and *+=#%\\s not used as one of the first three characters in the Organisation name", "organisationName");
}
var ownerCompanyId = _identityData.CompanyId;
var networkRepository = _portalRepositories.GetInstance<INetworkRepository>();
var companyRepository = _portalRepositories.GetInstance<ICompanyRepository>();
Expand Down
Loading

0 comments on commit 98e51c2

Please sign in to comment.