Skip to content

Commit

Permalink
feat(ssi): merge create and sign credential into one
Browse files Browse the repository at this point in the history
Refs: #232
  • Loading branch information
Phil91 committed Aug 14, 2024
1 parent a1dd326 commit b8a8b24
Show file tree
Hide file tree
Showing 23 changed files with 1,853 additions and 359 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;
public enum ProcessStepTypeId
{
// CREATE CREDENTIAL PROCESS
CREATE_CREDENTIAL = 1,
SIGN_CREDENTIAL = 2,
CREATE_SIGNED_CREDENTIAL = 1,
SAVE_CREDENTIAL_DOCUMENT = 3,
CREATE_CREDENTIAL_FOR_HOLDER = 4,
TRIGGER_CALLBACK = 5,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/********************************************************************************
* 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 Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Migrations.Migrations
{
/// <inheritdoc />
public partial class _232MergeCreateAndSignProcessStep : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
schema: "issuer",
table: "process_step_types",
keyColumn: "id",
keyValue: 2);

migrationBuilder.UpdateData(
schema: "issuer",
table: "process_step_types",
keyColumn: "id",
keyValue: 1,
column: "label",
value: "CREATE_SIGNED_CREDENTIAL");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
schema: "issuer",
table: "process_step_types",
keyColumn: "id",
keyValue: 1,
column: "label",
value: "CREATE_CREDENTIAL");

migrationBuilder.InsertData(
schema: "issuer",
table: "process_step_types",
columns: new[] { "id", "label" },
values: new object[] { 2, "SIGN_CREDENTIAL" });
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
modelBuilder
.HasDefaultSchema("issuer")
.UseCollation("en_US.utf8")
.HasAnnotation("ProductVersion", "8.0.5")
.HasAnnotation("ProductVersion", "8.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 63);

NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
Expand Down Expand Up @@ -947,12 +947,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
new
{
Id = 1,
Label = "CREATE_CREDENTIAL"
},
new
{
Id = 2,
Label = "SIGN_CREDENTIAL"
Label = "CREATE_SIGNED_CREDENTIAL"
},
new
{
Expand Down
16 changes: 6 additions & 10 deletions src/externalservices/Callback.Service/Services/CallbackService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,22 @@

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Callback.Service.Services;

public class CallbackService : ICallbackService
public class CallbackService(
ITokenService tokenService,
IOptions<CallbackSettings> options)
: ICallbackService
{
private static readonly JsonSerializerOptions Options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter(allowIntegerValues: false) }
};

private readonly ITokenService _tokenService;
private readonly CallbackSettings _settings;

public CallbackService(ITokenService tokenService, IOptions<CallbackSettings> options)
{
_tokenService = tokenService;
_settings = options.Value;
}
private readonly CallbackSettings _settings = options.Value;

public async Task TriggerCallback(string callbackUrl, IssuerResponseData responseData, CancellationToken cancellationToken)
{
var client = await _tokenService.GetAuthorizedClient<CallbackService>(_settings, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
var client = await tokenService.GetAuthorizedClient<CallbackService>(_settings, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
await client.PostAsJsonAsync($"{callbackUrl}", responseData, Options, cancellationToken)
.CatchingIntoServiceExceptionFor("callback", HttpAsyncResponseMessageExtension.RecoverOptions.REQUEST_EXCEPTION)
.ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Wallet.Service.BusinessLogic;

public interface IWalletBusinessLogic
{
Task CreateCredential(Guid companySsiDetailId, JsonDocument schema, CancellationToken cancellationToken);
Task SignCredential(Guid companySsiDetailId, Guid credentialId, CancellationToken cancellationToken);
Task CreateSignedCredential(Guid companySsiDetailId, JsonDocument schema, CancellationToken cancellationToken);
Task CreateCredentialForHolder(Guid companySsiDetailId, string holderWalletUrl, string clientId, EncryptionInformation encryptionInformation, string credential, CancellationToken cancellationToken);
Task GetCredential(Guid credentialId, Guid externalCredentialId, VerifiedCredentialTypeKindId kindId, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,18 @@ public class WalletBusinessLogic(
{
private readonly WalletSettings _settings = options.Value;

public async Task CreateCredential(Guid companySsiDetailId, JsonDocument schema, CancellationToken cancellationToken)
public async Task CreateSignedCredential(Guid companySsiDetailId, JsonDocument schema, CancellationToken cancellationToken)
{
var credentialId = await walletService.CreateCredential(schema, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
repositories.GetInstance<ICompanySsiDetailsRepository>().AttachAndModifyCompanySsiDetails(companySsiDetailId, c => c.ExternalCredentialId = null, c => c.ExternalCredentialId = credentialId);
}

public async Task SignCredential(Guid companySsiDetailId, Guid credentialId, CancellationToken cancellationToken)
{
var credential = await walletService.SignCredential(credentialId, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
repositories.GetInstance<ICompanySsiDetailsRepository>().AttachAndModifyCompanySsiDetails(companySsiDetailId, c => c.Credential = null, c => c.Credential = credential);
var credential = await walletService.CreateSignedCredential(schema, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
repositories.GetInstance<ICompanySsiDetailsRepository>().AttachAndModifyCompanySsiDetails(companySsiDetailId, c =>
{
c.ExternalCredentialId = null;
c.Credential = null;
}, c =>
{
c.ExternalCredentialId = credential.Id;
c.Credential = credential.Jwt;
});
}

public async Task GetCredential(Guid credentialId, Guid externalCredentialId, VerifiedCredentialTypeKindId kindId, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Wallet.Service.Models;

public record CreateSignedCredentialRequest(
[property: JsonPropertyName("application")] string Application,
[property: JsonPropertyName("payload")] CreateSignedPayload Payload
);

public record CreateSignedPayload(
[property: JsonPropertyName("content")] JsonDocument Issue,
[property: JsonPropertyName("signature")] SignData Signature
);

public record SignData(
[property: JsonPropertyName("proofMechanism")] string ProofMechanism,
[property: JsonPropertyName("proofType")] string ProofType,
[property: JsonPropertyName("keyName")] string? KeyName
);

public record CreateCredentialRequest(
[property: JsonPropertyName("application")] string Application,
[property: JsonPropertyName("payload")] CredentialPayload Payload
Expand All @@ -31,6 +47,11 @@ public record CredentialPayload(
[property: JsonPropertyName("issue")] JsonDocument Issue
);

public record CreateSignedCredentialResponse(
[property: JsonPropertyName("id")] Guid Id,
[property: JsonPropertyName("jwt")] string Jwt
);

public record CreateCredentialResponse(
[property: JsonPropertyName("id")] Guid Id
);

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using Org.Eclipse.TractusX.SsiCredentialIssuer.Wallet.Service.Models;
using System.Text.Json;

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Wallet.Service.Services;

public interface IWalletService
{
Task<Guid> CreateCredential(JsonDocument payload, CancellationToken cancellationToken);
Task<string> SignCredential(Guid credentialId, CancellationToken cancellationToken);
Task<CreateSignedCredentialResponse> CreateSignedCredential(JsonDocument payload, CancellationToken cancellationToken);
Task<Guid> CreateCredentialForHolder(string holderWalletUrl, string clientId, string clientSecret, string credential, CancellationToken cancellationToken);
Task<JsonDocument> GetCredential(Guid externalCredentialId, CancellationToken cancellationToken);
Task RevokeCredentialForIssuer(Guid externalCredentialId, CancellationToken cancellationToken);
Expand Down
47 changes: 13 additions & 34 deletions src/externalservices/Wallet.Service/Services/WalletService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,57 +28,36 @@

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Wallet.Service.Services;

public class WalletService : IWalletService
public class WalletService(
IBasicAuthTokenService basicAuthTokenService,
IOptions<WalletSettings> options)
: IWalletService
{
private const string NoIdErrorMessage = "Response must contain a valid id";
private static readonly JsonSerializerOptions Options = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

private readonly IBasicAuthTokenService _basicAuthTokenService;
private readonly WalletSettings _settings;
private readonly WalletSettings _settings = options.Value;

public WalletService(IBasicAuthTokenService basicAuthTokenService, IOptions<WalletSettings> options)
public async Task<CreateSignedCredentialResponse> CreateSignedCredential(JsonDocument payload, CancellationToken cancellationToken)
{
_basicAuthTokenService = basicAuthTokenService;
_settings = options.Value;
}

public async Task<Guid> CreateCredential(JsonDocument payload, CancellationToken cancellationToken)
{
using var client = await _basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
var data = new CreateCredentialRequest("catena-x-portal", new CredentialPayload(payload));
using var client = await basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
var data = new CreateSignedCredentialRequest("catena-x-portal", new CreateSignedPayload(payload, new SignData("external", "jwt", null)));
var result = await client.PostAsJsonAsync("api/v2.0.0/credentials", data, Options, cancellationToken)
.CatchingIntoServiceExceptionFor("create-credential", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
async x => (false, await x.Content.ReadAsStringAsync().ConfigureAwait(ConfigureAwaitOptions.None)))
.ConfigureAwait(false);
var response = await result.Content.ReadFromJsonAsync<CreateCredentialResponse>(Options, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
var response = await result.Content.ReadFromJsonAsync<CreateSignedCredentialResponse>(Options, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
if (response == null)
{
throw new ConflictException(NoIdErrorMessage);
}

return response.Id;
}

public async Task<string> SignCredential(Guid credentialId, CancellationToken cancellationToken)
{
using var client = await _basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
var data = new SignCredentialRequest(new SignPayload(new SignUpdate("external", "jwt")));
var result = await client.PatchAsJsonAsync($"/api/v2.0.0/credentials/{credentialId}", data, Options, cancellationToken)
.CatchingIntoServiceExceptionFor("sign-credential", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
async x => (false, await x.Content.ReadAsStringAsync().ConfigureAwait(ConfigureAwaitOptions.None)))
.ConfigureAwait(false);
var response = await result.Content.ReadFromJsonAsync<SignCredentialResponse>(Options, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
if (response is null)
{
throw new ServiceException(NoIdErrorMessage, true);
}

return response.Jwt;
return response;
}

public async Task<JsonDocument> GetCredential(Guid externalCredentialId, CancellationToken cancellationToken)
{
using var client = await _basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
using var client = await basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
var result = await client.GetAsync($"/api/v2.0.0/credentials/{externalCredentialId}", cancellationToken)
.CatchingIntoServiceExceptionFor("get-credential", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
async x => (false, await x.Content.ReadAsStringAsync().ConfigureAwait(ConfigureAwaitOptions.None)))
Expand All @@ -100,7 +79,7 @@ public async Task<Guid> CreateCredentialForHolder(string holderWalletUrl, string
ClientSecret = clientSecret,
TokenAddress = $"{holderWalletUrl}/oauth/token"
};
using var client = await _basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(authSettings, cancellationToken);
using var client = await basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(authSettings, cancellationToken);
var data = new DeriveCredentialData("catena-x-portal", new DeriveCredentialPayload(new DeriveCredential(credential)));
var result = await client.PostAsJsonAsync("/api/v2.0.0/credentials", data, Options, cancellationToken)
.CatchingIntoServiceExceptionFor("create-holder-credential", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
Expand All @@ -117,7 +96,7 @@ public async Task<Guid> CreateCredentialForHolder(string holderWalletUrl, string

public async Task RevokeCredentialForIssuer(Guid externalCredentialId, CancellationToken cancellationToken)
{
using var client = await _basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
using var client = await basicAuthTokenService.GetBasicAuthorizedClient<WalletService>(_settings, cancellationToken);
var data = new RevokeCredentialRequest(new RevokePayload(true));
await client.PatchAsJsonAsync($"/api/v2.0.0/credentials/{externalCredentialId}", data, Options, cancellationToken)
.CatchingIntoServiceExceptionFor("revoke-credential", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,14 @@

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Service.BusinessLogic;

public class CredentialBusinessLogic : ICredentialBusinessLogic
public class CredentialBusinessLogic(IIssuerRepositories repositories, IIdentityService identityService)
: ICredentialBusinessLogic
{
private readonly IIssuerRepositories _repositories;
private readonly IIdentityData _identityData;

public CredentialBusinessLogic(IIssuerRepositories repositories, IIdentityService identityService)
{
_repositories = repositories;
_identityData = identityService.IdentityData;
}
private readonly IIdentityData _identityData = identityService.IdentityData;

public async Task<JsonDocument> GetCredentialDocument(Guid credentialId)
{
var (exists, isSameCompany, documents) = await _repositories.GetInstance<ICredentialRepository>().GetSignedCredentialForCredentialId(credentialId, _identityData.Bpnl).ConfigureAwait(ConfigureAwaitOptions.None);
var (exists, isSameCompany, documents) = await repositories.GetInstance<ICredentialRepository>().GetSignedCredentialForCredentialId(credentialId, _identityData.Bpnl).ConfigureAwait(ConfigureAwaitOptions.None);
if (!exists)
{
throw NotFoundException.Create(CredentialErrors.CREDENTIAL_NOT_FOUND, new[] { new ErrorParameter("credentialId", credentialId.ToString()) });
Expand All @@ -64,7 +58,7 @@ public async Task<JsonDocument> GetCredentialDocument(Guid credentialId)

public async Task<(string FileName, byte[] Content, string MediaType)> GetCredentialDocumentById(Guid documentId)
{
var (exists, isSameCompany, fileName, documentStatusId, content, mediaTypeId) = await _repositories.GetInstance<ICredentialRepository>().GetDocumentById(documentId, _identityData.Bpnl).ConfigureAwait(ConfigureAwaitOptions.None);
var (exists, isSameCompany, fileName, documentStatusId, content, mediaTypeId) = await repositories.GetInstance<ICredentialRepository>().GetDocumentById(documentId, _identityData.Bpnl).ConfigureAwait(ConfigureAwaitOptions.None);
if (!exists)
{
throw NotFoundException.Create(CredentialErrors.DOCUMENT_NOT_FOUND, new[] { new ErrorParameter("documentId", documentId.ToString()) });
Expand Down
Loading

0 comments on commit b8a8b24

Please sign in to comment.