Skip to content

Commit e020345

Browse files
authored
feat(osp): send additional information to osp callback (#1457)
#1456
1 parent a22506f commit e020345

File tree

29 files changed

+10855
-79
lines changed

29 files changed

+10855
-79
lines changed

docs/api/administration-service.yaml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3140,6 +3140,68 @@ paths:
31403140
description: Internal Server Error
31413141
'401':
31423142
description: The User is unauthorized
3143+
'/api/administration/registration/Network/{externalId}/retrigger-callback-osp-created':
3144+
post:
3145+
tags:
3146+
- Network
3147+
summary: 'Retriggers the last failed step (Authorization required - Roles: approve_new_partner)'
3148+
parameters:
3149+
- name: externalId
3150+
in: path
3151+
description: Id of the externalId that should be triggered
3152+
required: true
3153+
schema:
3154+
type: string
3155+
responses:
3156+
'204':
3157+
description: Empty response on success.
3158+
'400':
3159+
description: Bad Request
3160+
content:
3161+
application/json:
3162+
schema:
3163+
$ref: '#/components/schemas/ErrorResponse'
3164+
'404':
3165+
description: No registration found for the externalId.
3166+
content:
3167+
application/json:
3168+
schema:
3169+
$ref: '#/components/schemas/ErrorResponse'
3170+
'500':
3171+
description: Internal Server Error
3172+
'401':
3173+
description: The User is unauthorized
3174+
'/api/administration/registration/Network/{externalId}/retrigger-callback-osp-invited':
3175+
post:
3176+
tags:
3177+
- Network
3178+
summary: 'Retriggers the last failed step (Authorization required - Roles: approve_new_partner)'
3179+
parameters:
3180+
- name: externalId
3181+
in: path
3182+
description: Id of the externalId that should be triggered
3183+
required: true
3184+
schema:
3185+
type: string
3186+
responses:
3187+
'204':
3188+
description: Empty response on success.
3189+
'400':
3190+
description: Bad Request
3191+
content:
3192+
application/json:
3193+
schema:
3194+
$ref: '#/components/schemas/ErrorResponse'
3195+
'404':
3196+
description: No registration found for the externalId.
3197+
content:
3198+
application/json:
3199+
schema:
3200+
$ref: '#/components/schemas/ErrorResponse'
3201+
'500':
3202+
description: Internal Server Error
3203+
'401':
3204+
description: The User is unauthorized
31433205
'/api/administration/registration/Network/{externalId}/retrigger-remove-keycloak-user':
31443206
post:
31453207
tags:
@@ -7746,6 +7808,10 @@ components:
77467808
- MANUAL_DECLINE_OSP
77477809
- REMOVE_KEYCLOAK_USERS
77487810
- RETRIGGER_REMOVE_KEYCLOAK_USERS
7811+
- TRIGGER_CALLBACK_OSP_CREATED
7812+
- RETRIGGER_CALLBACK_OSP_CREATED
7813+
- TRIGGER_CALLBACK_OSP_INVITED
7814+
- RETRIGGER_CALLBACK_OSP_INVITED
77497815
- SEND_MAIL
77507816
- RETRIGGER_SEND_MAIL
77517817
- INVITATION_CREATE_CENTRAL_IDP

docs/api/apps-service.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3665,6 +3665,10 @@ components:
36653665
- MANUAL_DECLINE_OSP
36663666
- REMOVE_KEYCLOAK_USERS
36673667
- RETRIGGER_REMOVE_KEYCLOAK_USERS
3668+
- TRIGGER_CALLBACK_OSP_CREATED
3669+
- RETRIGGER_CALLBACK_OSP_CREATED
3670+
- TRIGGER_CALLBACK_OSP_INVITED
3671+
- RETRIGGER_CALLBACK_OSP_INVITED
36683672
- SEND_MAIL
36693673
- RETRIGGER_SEND_MAIL
36703674
- INVITATION_CREATE_CENTRAL_IDP

docs/api/services-service.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,10 @@ components:
22322232
- MANUAL_DECLINE_OSP
22332233
- REMOVE_KEYCLOAK_USERS
22342234
- RETRIGGER_REMOVE_KEYCLOAK_USERS
2235+
- TRIGGER_CALLBACK_OSP_CREATED
2236+
- RETRIGGER_CALLBACK_OSP_CREATED
2237+
- TRIGGER_CALLBACK_OSP_INVITED
2238+
- RETRIGGER_CALLBACK_OSP_INVITED
22352239
- SEND_MAIL
22362240
- RETRIGGER_SEND_MAIL
22372241
- INVITATION_CREATE_CENTRAL_IDP

src/administration/Administration.Service/BusinessLogic/NetworkBusinessLogic.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public async Task HandlePartnerRegistration(PartnerRegistrationData data)
8080
var processId = processStepRepository.CreateProcess(ProcessTypeId.PARTNER_REGISTRATION).Id;
8181
processStepRepository.CreateProcessStepRange(new[]
8282
{
83-
(ProcessStepTypeId.SYNCHRONIZE_USER, ProcessStepStatusId.TODO, processId),
83+
(ProcessStepTypeId.TRIGGER_CALLBACK_OSP_CREATED, ProcessStepStatusId.TODO, processId),
8484
(ProcessStepTypeId.MANUAL_DECLINE_OSP, ProcessStepStatusId.TODO, processId)
8585
});
8686

src/administration/Administration.Service/Controllers/NetworkController.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,48 @@ public async Task<NoContentResult> RetriggerCallbackOspSubmitted([FromRoute] str
137137
return NoContent();
138138
}
139139

140+
/// <summary>
141+
/// Retriggers the last failed step
142+
/// </summary>
143+
/// <param name="externalId" example="">Id of the externalId that should be triggered</param>
144+
/// <returns>NoContent</returns>
145+
/// Example: POST: api/administration/registration/network/{externalId}/retrigger-callback-osp-created
146+
/// <response code="204">Empty response on success.</response>
147+
/// <response code="404">No registration found for the externalId.</response>
148+
[HttpPost]
149+
[Authorize(Roles = "approve_new_partner")]
150+
[Authorize(Policy = PolicyTypes.CompanyUser)]
151+
[Route("{externalId}/retrigger-callback-osp-created")]
152+
[ProducesResponseType(StatusCodes.Status204NoContent)]
153+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
154+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)]
155+
public async Task<NoContentResult> RetriggerCallbackOspCreated([FromRoute] string externalId)
156+
{
157+
await logic.RetriggerProcessStep(externalId, ProcessStepTypeId.RETRIGGER_CALLBACK_OSP_CREATED).ConfigureAwait(ConfigureAwaitOptions.None);
158+
return NoContent();
159+
}
160+
161+
/// <summary>
162+
/// Retriggers the last failed step
163+
/// </summary>
164+
/// <param name="externalId" example="">Id of the externalId that should be triggered</param>
165+
/// <returns>NoContent</returns>
166+
/// Example: POST: api/administration/registration/network/{externalId}/retrigger-callback-osp-invited
167+
/// <response code="204">Empty response on success.</response>
168+
/// <response code="404">No registration found for the externalId.</response>
169+
[HttpPost]
170+
[Authorize(Roles = "approve_new_partner")]
171+
[Authorize(Policy = PolicyTypes.CompanyUser)]
172+
[Route("{externalId}/retrigger-callback-osp-invited")]
173+
[ProducesResponseType(StatusCodes.Status204NoContent)]
174+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
175+
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)]
176+
public async Task<NoContentResult> RetriggerCallbackOspInvited([FromRoute] string externalId)
177+
{
178+
await logic.RetriggerProcessStep(externalId, ProcessStepTypeId.RETRIGGER_CALLBACK_OSP_INVITED).ConfigureAwait(ConfigureAwaitOptions.None);
179+
return NoContent();
180+
}
181+
140182
/// <summary>
141183
/// Retriggers the last failed step
142184
/// </summary>

src/externalsystems/OnboardingServiceProvider.Library/Models/OnboardingServiceProviderCallbackData.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ namespace Org.Eclipse.TractusX.Portal.Backend.OnboardingServiceProvider.Library.
3434
public record OnboardingServiceProviderCallbackData(
3535
[property: JsonPropertyName("externalId")] string ExternalId,
3636
[property: JsonPropertyName("applicationId")] Guid ApplicationId,
37+
[property: JsonPropertyName("companyId")] Guid CompanyId,
3738
[property: JsonPropertyName("bpn")] string? Bpn,
38-
[property: JsonPropertyName("status")] CompanyApplicationStatusId? Status,
39-
[property: JsonPropertyName("message")] string? Message
39+
[property: JsonPropertyName("applicationStatus")] CompanyApplicationStatusId? Status,
40+
[property: JsonPropertyName("message")] string? Message,
41+
[property: JsonPropertyName("applicationDateCreated")] DateTimeOffset ApplicationDateCreated,
42+
[property: JsonPropertyName("dateCreated")] DateTimeOffset DateCreated,
43+
[property: JsonPropertyName("lastChangedDate")] DateTimeOffset? LastChangedDate,
44+
[property: JsonPropertyName("companyName")] string? CompanyName,
45+
[property: JsonPropertyName("companyRoles")] IEnumerable<string>? CompanyRoles
4046
);

src/externalsystems/OnboardingServiceProvider.Library/OnboardingServiceProviderBusinessLogic.cs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,52 +39,76 @@ public class OnboardingServiceProviderBusinessLogic(
3939

4040
public async Task<(IEnumerable<ProcessStepTypeId>? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> TriggerProviderCallback(Guid networkRegistrationId, ProcessStepTypeId processStepTypeId, CancellationToken cancellationToken)
4141
{
42-
var data = await portalRepositories.GetInstance<INetworkRepository>().GetCallbackData(networkRegistrationId, processStepTypeId).ConfigureAwait(ConfigureAwaitOptions.None);
42+
var result = await portalRepositories.GetInstance<INetworkRepository>().GetCallbackData(networkRegistrationId, processStepTypeId).ConfigureAwait(ConfigureAwaitOptions.None);
4343

44-
if (data == default)
44+
if (result == default)
4545
{
4646
throw new UnexpectedConditionException($"data should never be default here (networkRegistrationId: {networkRegistrationId})");
4747
}
4848

49-
if (data.OspDetails == null || string.IsNullOrWhiteSpace(data.OspDetails.CallbackUrl))
49+
if (result.ospCallbackDetails == null || string.IsNullOrWhiteSpace(result.ospCallbackDetails.CallbackUrl))
5050
{
5151
return (Enumerable.Empty<ProcessStepTypeId>(), ProcessStepStatusId.SKIPPED, false, "No callback url set");
5252
}
5353

54-
if (processStepTypeId == ProcessStepTypeId.TRIGGER_CALLBACK_OSP_DECLINED && data.Comments.Count() != 1)
54+
if (processStepTypeId == ProcessStepTypeId.TRIGGER_CALLBACK_OSP_DECLINED && result.ospCallbackData.Comments.Count() != 1)
5555
{
5656
throw new UnexpectedConditionException("Message for decline should be set");
5757
}
5858

5959
string comment;
6060
CompanyApplicationStatusId applicationStatusId;
61+
var applicationId = result.ospCallbackData.ApplicationId;
6162
switch (processStepTypeId)
6263
{
64+
case ProcessStepTypeId.TRIGGER_CALLBACK_OSP_CREATED:
65+
comment = $"Application {applicationId} has been created for further processing";
66+
applicationStatusId = CompanyApplicationStatusId.CREATED;
67+
break;
68+
case ProcessStepTypeId.TRIGGER_CALLBACK_OSP_INVITED:
69+
comment = $"Application {applicationId} has been invited for further processing";
70+
applicationStatusId = CompanyApplicationStatusId.INVITE_USER;
71+
break;
6372
case ProcessStepTypeId.TRIGGER_CALLBACK_OSP_SUBMITTED:
64-
comment = $"Application {data.ApplicationId} has been submitted for further processing";
73+
comment = $"Application {applicationId} has been submitted for further processing";
6574
applicationStatusId = CompanyApplicationStatusId.SUBMITTED;
6675
break;
6776
case ProcessStepTypeId.TRIGGER_CALLBACK_OSP_APPROVED:
68-
comment = $"Application {data.ApplicationId} has been approved";
77+
comment = $"Application {applicationId} has been approved";
6978
applicationStatusId = CompanyApplicationStatusId.CONFIRMED;
7079
break;
7180
case ProcessStepTypeId.TRIGGER_CALLBACK_OSP_DECLINED:
72-
comment = $"Application {data.ApplicationId} has been declined with reason: {data.Comments.Single()}";
81+
comment = $"Application {applicationId} has been declined with reason: {result.ospCallbackData.Comments.Single()}";
7382
applicationStatusId = CompanyApplicationStatusId.DECLINED;
7483
break;
7584
default:
7685
throw new ArgumentException($"{processStepTypeId} is not supported");
7786
}
7887

79-
var cryptoConfig = _settings.EncryptionConfigs.SingleOrDefault(x => x.Index == data.OspDetails.EncryptionMode) ?? throw new ConfigurationException($"EncryptionModeIndex {data.OspDetails.EncryptionMode} is not configured");
80-
var secret = CryptoHelper.Decrypt(data.OspDetails.ClientSecret, data.OspDetails.InitializationVector, Convert.FromHexString(cryptoConfig.EncryptionKey), cryptoConfig.CipherMode, cryptoConfig.PaddingMode);
88+
var cryptoConfig = _settings.EncryptionConfigs.SingleOrDefault(x => x.Index == result.ospCallbackDetails.EncryptionMode) ?? throw new ConfigurationException($"EncryptionModeIndex {result.ospCallbackDetails.EncryptionMode} is not configured");
89+
var secret = CryptoHelper.Decrypt(result.ospCallbackDetails.ClientSecret, result.ospCallbackDetails.InitializationVector, Convert.FromHexString(cryptoConfig.EncryptionKey), cryptoConfig.CipherMode, cryptoConfig.PaddingMode);
8190

8291
await onboardingServiceProviderService.TriggerProviderCallback(
83-
new OspTriggerDetails(data.OspDetails.CallbackUrl, data.OspDetails.AuthUrl, data.OspDetails.ClientId, secret),
84-
new OnboardingServiceProviderCallbackData(data.ExternalId, data.ApplicationId, data.Bpn, applicationStatusId, comment),
92+
new OspTriggerDetails(
93+
result.ospCallbackDetails.CallbackUrl,
94+
result.ospCallbackDetails.AuthUrl,
95+
result.ospCallbackDetails.ClientId, secret),
96+
new OnboardingServiceProviderCallbackData(
97+
result.ospCallbackData.ExternalId,
98+
result.ospCallbackData.ApplicationId,
99+
result.ospCallbackData.CompanyId,
100+
result.ospCallbackData.BusinessPartnerNumber,
101+
applicationStatusId,
102+
comment,
103+
result.ospCallbackData.ApplicationDateCreated,
104+
result.ospCallbackData.DateCreated,
105+
result.ospCallbackData.ApplicationDateLastChanged,
106+
result.ospCallbackData.CompanyName,
107+
result.ospCallbackData.CompanyAssignedRoles),
85108
cancellationToken)
86109
.ConfigureAwait(ConfigureAwaitOptions.None);
87110

88-
return (Enumerable.Empty<ProcessStepTypeId>(), ProcessStepStatusId.DONE, false, null);
111+
var nextStep = processStepTypeId == ProcessStepTypeId.TRIGGER_CALLBACK_OSP_CREATED ? [ProcessStepTypeId.SYNCHRONIZE_USER] : Enumerable.Empty<ProcessStepTypeId>();
112+
return (nextStep, ProcessStepStatusId.DONE, false, null);
89113
}
90114
}

src/portalbackend/PortalBackend.DBAccess/Models/OspDetails.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models;
2121

22-
public record OspDetails
22+
public record OspCallbackDetails
2323
(
2424
string CallbackUrl,
2525
string AuthUrl,
@@ -28,3 +28,17 @@ public record OspDetails
2828
byte[]? InitializationVector,
2929
int EncryptionMode
3030
);
31+
32+
public record OspCallbackData
33+
(
34+
string ExternalId,
35+
string BusinessPartnerNumber,
36+
Guid ApplicationId,
37+
IEnumerable<string> Comments,
38+
Guid CompanyId,
39+
DateTimeOffset ApplicationDateCreated,
40+
DateTimeOffset DateCreated,
41+
DateTimeOffset? ApplicationDateLastChanged,
42+
string CompanyName,
43+
IEnumerable<string> CompanyAssignedRoles
44+
);

src/portalbackend/PortalBackend.DBAccess/Repositories/CompanyRepository.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,14 @@ public Task<OnboardingServiceProviderCallbackResponseData> GetCallbackData(Guid
334334
))
335335
.SingleAsync();
336336

337-
public Task<(bool HasCompanyRole, Guid? OnboardingServiceProviderDetailId, OspDetails? OspDetails)> GetCallbackEditData(Guid companyId, CompanyRoleId companyRoleId) =>
337+
public Task<(bool HasCompanyRole, Guid? OnboardingServiceProviderDetailId, OspCallbackDetails? OspDetails)> GetCallbackEditData(Guid companyId, CompanyRoleId companyRoleId) =>
338338
context.Companies.Where(c => c.Id == companyId)
339-
.Select(c => new ValueTuple<bool, Guid?, OspDetails?>(
339+
.Select(c => new ValueTuple<bool, Guid?, OspCallbackDetails?>(
340340
c.CompanyAssignedRoles.Any(role => role.CompanyRoleId == companyRoleId),
341341
c.OnboardingServiceProviderDetail!.Id,
342342
c.OnboardingServiceProviderDetail == null
343343
? null
344-
: new OspDetails(
344+
: new OspCallbackDetails(
345345
c.OnboardingServiceProviderDetail.CallbackUrl,
346346
c.OnboardingServiceProviderDetail.AuthUrl,
347347
c.OnboardingServiceProviderDetail.ClientId,

src/portalbackend/PortalBackend.DBAccess/Repositories/ICompanyRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public interface ICompanyRepository
170170

171171
Task<(bool IsValidCompany, string CompanyName, bool IsAllowed)> CheckCompanyAndCompanyRolesAsync(Guid companyId, IEnumerable<CompanyRoleId> companyRoles);
172172
Task<OnboardingServiceProviderCallbackResponseData> GetCallbackData(Guid companyId);
173-
Task<(bool HasCompanyRole, Guid? OnboardingServiceProviderDetailId, OspDetails? OspDetails)> GetCallbackEditData(Guid companyId, CompanyRoleId companyRoleId);
173+
Task<(bool HasCompanyRole, Guid? OnboardingServiceProviderDetailId, OspCallbackDetails? OspDetails)> GetCallbackEditData(Guid companyId, CompanyRoleId companyRoleId);
174174
void AttachAndModifyOnboardingServiceProvider(Guid onboardingServiceProviderDetailId, Action<OnboardingServiceProviderDetail>? initialize, Action<OnboardingServiceProviderDetail> setOptionalFields);
175175
OnboardingServiceProviderDetail CreateOnboardingServiceProviderDetails(Guid companyId, string callbackUrl, string authUrl, string clientId, byte[] clientSecret, byte[]? initializationVector, int encryptionMode);
176176
Task<bool> CheckBpnExists(string bpn);

0 commit comments

Comments
 (0)