Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(revocation): add endpoints to revoke credentials #43

Merged
merged 7 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ nuget/nuget/-/JsonSchema.Net/6.0.3, MIT AND OFL-1.1 AND CC-BY-SA-4.0, approved,
nuget/nuget/-/Laraue.EfCoreTriggers.Common/7.1.0, MIT, approved, #10247
nuget/nuget/-/Laraue.EfCoreTriggers.PostgreSql/7.1.0, MIT, approved, #10248
nuget/nuget/-/Mono.TextTemplating/2.2.1, MIT, approved, clearlydefined
nuget/nuget/-/Newtonsoft.Json/12.0.2, MIT AND BSD-3-Clause, approved, #11114
nuget/nuget/-/Newtonsoft.Json/13.0.1, MIT AND BSD-3-Clause, approved, #3266
nuget/nuget/-/Newtonsoft.Json/13.0.3, MIT AND BSD-3-Clause, approved, #3266
nuget/nuget/-/Npgsql.EntityFrameworkCore.PostgreSQL/7.0.11, PostgreSQL AND MIT AND Apache-2.0, approved, #10081
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,38 @@ spec:
secretKeyRef:
name: "{{ template "issuer.secretName" . }}"
key: "credential-encryption-key0"
- name: "WALLET__BASEADDRESS"
value: "{{ .Values.walletAddress }}"
- name: "WALLET__CLIENTID"
value: "{{ .Values.processesworker.wallet.clientId }}"
- name: "WALLET__CLIENTSECRET"
valueFrom:
secretKeyRef:
name: "{{ template "issuer.secretName" . }}"
key: "wallet-client-secret"
- name: "WALLET__GRANTTYPE"
value: "{{ .Values.processesworker.wallet.grantType }}"
- name: "WALLET__TOKENADDRESS"
value: "{{ .Values.walletTokenAddress }}"
- name: "WALLET__PASSWORD"
value: "empty"
- name: "WALLET__SCOPE"
value: "{{ .Values.processesworker.wallet.scope }}"
- name: "WALLET__USERNAME"
value: "empty"
- name: "WALLET__ENCRYPTIONCONFIG__ENCRYPTIONCONFIGINDEX"
value: "{{ .Values.processesworker.wallet.encryptionConfigIndex }}"
- name: "WALLET__ENCRYPTIONCONFIGS__0__INDEX"
value: "{{ .Values.processesworker.wallet.encryptionConfigs.index0.index}}"
- name: "WALLET__ENCRYPTIONCONFIGS__0__CIPHERMODE"
value: "{{ .Values.processesworker.wallet.encryptionConfigs.index0.cipherMode}}"
- name: "WALLET__ENCRYPTIONCONFIGS__0__PADDINGMODE"
value: "{{ .Values.processesworker.wallet.encryptionConfigs.index0.paddingMode}}"
- name: "WALLET__ENCRYPTIONCONFIGS__0__ENCRYPTIONKEY"
valueFrom:
secretKeyRef:
name: "{{ template "issuer.secretName" . }}"
key: "process-wallet-encryption-key0"
ports:
- name: http
containerPort: {{ .Values.portContainer }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ public async Task ExecuteAsync(CancellationToken stoppingToken)

var now = dateTimeProvider.OffsetNow;
var companySsiDetailsRepository = repositories.GetInstance<ICompanySsiDetailsRepository>();
var processStepRepository = repositories.GetInstance<IProcessStepRepository>();
var inactiveVcsToDelete = now.AddDays(-(_settings.InactiveVcsToDeleteInWeeks * 7));
var expiredVcsToDelete = now.AddMonths(-_settings.ExpiredVcsToDeleteInMonth);

var credentials = outerLoopRepositories.GetInstance<ICompanySsiDetailsRepository>()
.GetExpiryData(now, inactiveVcsToDelete, expiredVcsToDelete);
await foreach (var credential in credentials.WithCancellation(stoppingToken).ConfigureAwait(false))
{
await ProcessCredentials(credential, companySsiDetailsRepository, repositories, portalService,
stoppingToken).ConfigureAwait(false);
await ProcessCredentials(credential, companySsiDetailsRepository, repositories, portalService, processStepRepository, stoppingToken).ConfigureAwait(false);
}
}
catch (Exception ex)
Expand All @@ -104,6 +104,7 @@ private static async Task ProcessCredentials(
ICompanySsiDetailsRepository companySsiDetailsRepository,
IIssuerRepositories repositories,
IPortalService portalService,
IProcessStepRepository processStepRepository,
CancellationToken cancellationToken)
{
if (data.ScheduleData.IsVcToDelete)
Expand All @@ -112,7 +113,7 @@ private static async Task ProcessCredentials(
}
else if (data.ScheduleData.IsVcToDecline)
{
await HandleDecline(data, companySsiDetailsRepository, portalService, cancellationToken).ConfigureAwait(false);
HandleDecline(data.Id, companySsiDetailsRepository, processStepRepository);
}
else
{
Expand All @@ -123,34 +124,21 @@ private static async Task ProcessCredentials(
await repositories.SaveAsync().ConfigureAwait(false);
}

private static async ValueTask HandleDecline(
CredentialExpiryData data,
private static void HandleDecline(
Guid credentialId,
ICompanySsiDetailsRepository companySsiDetailsRepository,
IPortalService portalService,
CancellationToken cancellationToken)
IProcessStepRepository processStepRepository)
{
companySsiDetailsRepository.AttachAndModifyCompanySsiDetails(data.Id, c =>
var processId = processStepRepository.CreateProcess(ProcessTypeId.DECLINE_CREDENTIAL).Id;
processStepRepository.CreateProcessStep(ProcessStepTypeId.REVOKE_CREDENTIAL, ProcessStepStatusId.TODO, processId);
companySsiDetailsRepository.AttachAndModifyCompanySsiDetails(credentialId, c =>
{
c.CompanySsiDetailStatusId = data.CompanySsiDetailStatusId;
c.ProcessId = null;
},
c =>
{
c.CompanySsiDetailStatusId = CompanySsiDetailStatusId.INACTIVE;
c.ProcessId = processId;
});

if (Guid.TryParse(data.RequesterId, out var requesterId))
{
var content = JsonSerializer.Serialize(new { Type = data.VerifiedCredentialTypeId, CredentialId = data.Id }, Options);
await portalService.AddNotification(content, requesterId, NotificationTypeId.CREDENTIAL_REJECTED, cancellationToken).ConfigureAwait(false);

var typeValue = data.VerifiedCredentialTypeId.GetEnumValue() ?? throw new UnexpectedConditionException($"VerifiedCredentialType {data.VerifiedCredentialTypeId} does not exists");
var mailParameters = new Dictionary<string, string>
{
{ "requestName", typeValue },
{ "reason", "The credential is already expired" }
};
await portalService.TriggerMail("CredentialRejected", requesterId, mailParameters, cancellationToken).ConfigureAwait(false);
}
}

private static async ValueTask HandleNotification(
Expand Down Expand Up @@ -189,15 +177,18 @@ private static async ValueTask HandleNotification(

if (Guid.TryParse(data.RequesterId, out var requesterId))
{
await portalService.AddNotification(content, requesterId, NotificationTypeId.CREDENTIAL_EXPIRY, cancellationToken).ConfigureAwait(false);
var typeValue = data.VerifiedCredentialTypeId.GetEnumValue() ?? throw new UnexpectedConditionException($"VerifiedCredentialType {data.VerifiedCredentialTypeId} does not exists");
var mailParameters = new Dictionary<string, string>
await portalService.AddNotification(content, requesterId, NotificationTypeId.CREDENTIAL_EXPIRY,
cancellationToken);
var typeValue = data.VerifiedCredentialTypeId.GetEnumValue() ??
throw new UnexpectedConditionException(
$"VerifiedCredentialType {data.VerifiedCredentialTypeId} does not exists");
var mailParameters = new MailParameter[]
{
{ "typeId", typeValue },
{ "version", data.DetailVersion ?? "no version" },
{ "expiryDate", data.ExpiryDate?.ToString("dd MMMM yyyy") ?? throw new ConflictException("Expiry Date must be set here") }
new("typeId", typeValue), new("version", data.DetailVersion ?? "no version"),
new("expiryDate",
data.ExpiryDate?.ToString("dd MMMM yyyy") ??
throw new ConflictException("Expiry Date must be set here"))
};

await portalService.TriggerMail("CredentialExpiry", requesterId, mailParameters, cancellationToken).ConfigureAwait(false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
********************************************************************************/

using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;
using System.Text.Json;

namespace Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Models;

Expand All @@ -27,6 +28,7 @@ public record SsiApprovalData(
Guid? ProcessId,
VerifiedCredentialTypeKindId? Kind,
string? Bpn,
JsonDocument? Schema,
DetailData? DetailData
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,16 @@ public Task<bool> CheckSsiDetailsExistsForCompany(string bpnl, VerifiedCredentia
(verifiedCredentialExternalTypeUseCaseDetailId == null || x.VerifiedCredentialExternalTypeDetailVersionId == verifiedCredentialExternalTypeUseCaseDetailId));

/// <inheritdoc />
public Task<(bool Exists, string? Version, string? Template, IEnumerable<string> UseCase, DateTimeOffset Expiry)> CheckCredentialTypeIdExistsForExternalTypeDetailVersionId(Guid verifiedCredentialExternalTypeUseCaseDetailId, VerifiedCredentialTypeId verifiedCredentialTypeId) =>
public Task<(bool Exists, string? Version, string? Template, IEnumerable<VerifiedCredentialExternalTypeId> ExternalTypeIds, DateTimeOffset Expiry)> CheckCredentialTypeIdExistsForExternalTypeDetailVersionId(Guid verifiedCredentialExternalTypeUseCaseDetailId, VerifiedCredentialTypeId verifiedCredentialTypeId) =>
_context.VerifiedCredentialExternalTypeDetailVersions
.Where(x =>
x.Id == verifiedCredentialExternalTypeUseCaseDetailId &&
x.VerifiedCredentialExternalType!.VerifiedCredentialTypeAssignedExternalTypes.Any(y => y.VerifiedCredentialTypeId == verifiedCredentialTypeId))
.Select(x => new ValueTuple<bool, string?, string?, IEnumerable<string>, DateTimeOffset>(
.Select(x => new ValueTuple<bool, string?, string?, IEnumerable<VerifiedCredentialExternalTypeId>, DateTimeOffset>(
true,
x.Version,
x.Template,
x.VerifiedCredentialExternalType!.VerifiedCredentialTypeAssignedExternalTypes.Select(y => y.VerifiedCredentialType!.VerifiedCredentialTypeAssignedUseCase!.UseCase!.Shortname),
x.VerifiedCredentialExternalType!.VerifiedCredentialTypeAssignedExternalTypes.Select(y => y.VerifiedCredentialExternalTypeId),
x.Expiry))
.SingleOrDefaultAsync();

Expand Down Expand Up @@ -188,6 +188,7 @@ public IQueryable<CompanySsiDetail> GetAllCredentialDetails(CompanySsiDetailStat
x.ProcessId,
x.VerifiedCredentialType!.VerifiedCredentialTypeAssignedKind == null ? null : x.VerifiedCredentialType!.VerifiedCredentialTypeAssignedKind!.VerifiedCredentialTypeKindId,
x.Bpnl,
x.CompanySsiProcessData!.Schema,
x.VerifiedCredentialExternalTypeDetailVersion == null ?
null :
new DetailData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Microsoft.EntityFrameworkCore;
using Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Models;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Entities;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;
using System.Text.Json;

Expand Down Expand Up @@ -76,4 +77,39 @@ public CredentialRepository(IssuerDbContext dbContext)
.Where(x => x.CompanySsiDetailId == credentialId)
.Select(x => new ValueTuple<string, string?>(x.CompanySsiDetail!.Bpnl, x.CallbackUrl))
.SingleOrDefaultAsync();

public Task<(bool Exists, bool IsSameBpnl, Guid? ExternalCredentialId, CompanySsiDetailStatusId StatusId, IEnumerable<(Guid DocumentId, DocumentStatusId DocumentStatusId)> Documents)> GetRevocationDataById(Guid credentialId, string bpnl) =>
_dbContext.CompanySsiDetails
.Where(x =>
x.Id == credentialId)
.Select(x => new ValueTuple<bool, bool, Guid?, CompanySsiDetailStatusId, IEnumerable<(Guid, DocumentStatusId)>>(
true,
x.Bpnl == bpnl,
x.ExternalCredentialId,
x.CompanySsiDetailStatusId,
x.Documents.Select(d => new ValueTuple<Guid, DocumentStatusId>(d.Id, d.DocumentStatusId))))
.SingleOrDefaultAsync();

public void AttachAndModifyCredential(Guid credentialId, Action<CompanySsiDetail>? initialize, Action<CompanySsiDetail> modify)
{
var entity = new CompanySsiDetail(credentialId, string.Empty, default!, default!, null!, null!, default!);
initialize?.Invoke(entity);
_dbContext.CompanySsiDetails.Attach(entity);
modify(entity);
}

public Task<(VerifiedCredentialTypeId TypeId, string RequesterId)> GetCredentialNotificationData(Guid credentialId) =>
_dbContext.CompanySsiDetails
.Where(x => x.Id == credentialId)
.Select(x => new ValueTuple<VerifiedCredentialTypeId, string>(x.VerifiedCredentialTypeId, x.CreatorUserId))
.SingleOrDefaultAsync();

public Task<(bool Exists, bool IsSameCompany, IEnumerable<(DocumentStatusId StatusId, byte[] Content)> Documents)> GetSignedCredentialForCredentialId(Guid credentialId, string bpnl) =>
_dbContext.CompanySsiDetails
.Where(x => x.Id == credentialId)
.Select(x => new ValueTuple<bool, bool, IEnumerable<ValueTuple<DocumentStatusId, byte[]>>>(
true,
x.Bpnl == bpnl,
x.Documents.Where(d => d.DocumentTypeId == DocumentTypeId.VERIFIED_CREDENTIAL).Select(d => new ValueTuple<DocumentStatusId, byte[]>(d.DocumentStatusId, d.DocumentContent))))
.SingleOrDefaultAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,17 @@ public void AssignDocumentToCompanySsiDetails(Guid documentId, Guid companySsiDe
var document = new CompanySsiDetailAssignedDocument(documentId, companySsiDetailId);
_dbContext.CompanySsiDetailAssignedDocuments.Add(document);
}

public void AttachAndModifyDocuments(IEnumerable<(Guid DocumentId, Action<Document>? Initialize, Action<Document> Modify)> documentData)
{
var initial = documentData.Select(x =>
{
var document = new Document(x.DocumentId, null!, null!, null!, default, default, default, default);
x.Initialize?.Invoke(document);
return (Document: document, x.Modify);
}
).ToList();
_dbContext.AttachRange(initial.Select(x => x.Document));
initial.ForEach(x => x.Modify(x.Document));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public interface ICompanySsiDetailsRepository
/// <param name="verifiedCredentialExternalTypeUseCaseDetailId">Id of vc external type use case detail id</param>
/// <param name="verifiedCredentialTypeId">Id of the vc type</param>
/// <returns>Returns a valueTuple with identifiers if the externalTypeUseCaseDetailId exists and the corresponding credentialTypeId</returns>
Task<(bool Exists, string? Version, string? Template, IEnumerable<string> UseCase, DateTimeOffset Expiry)> CheckCredentialTypeIdExistsForExternalTypeDetailVersionId(Guid verifiedCredentialExternalTypeUseCaseDetailId, VerifiedCredentialTypeId verifiedCredentialTypeId);
Task<(bool Exists, string? Version, string? Template, IEnumerable<VerifiedCredentialExternalTypeId> ExternalTypeIds, DateTimeOffset Expiry)> CheckCredentialTypeIdExistsForExternalTypeDetailVersionId(Guid verifiedCredentialExternalTypeUseCaseDetailId, VerifiedCredentialTypeId verifiedCredentialTypeId);

/// <summary>
/// Checks whether the given credentialTypeId is a <see cref="VerifiedCredentialTypeKindId"/> Certificate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
********************************************************************************/

using Org.Eclipse.TractusX.SsiCredentialIssuer.DBAccess.Models;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Entities;
using Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;
using System.Text.Json;

Expand All @@ -31,4 +32,8 @@ public interface ICredentialRepository
Task<(VerifiedCredentialTypeKindId CredentialTypeKindId, JsonDocument Schema)> GetCredentialStorageInformationById(Guid credentialId);
Task<(Guid? ExternalCredentialId, VerifiedCredentialTypeKindId KindId, bool HasEncryptionInformation, string? CallbackUrl)> GetExternalCredentialAndKindId(Guid credentialId);
Task<(string Bpn, string? CallbackUrl)> GetCallbackUrl(Guid credentialId);
Task<(bool Exists, bool IsSameBpnl, Guid? ExternalCredentialId, CompanySsiDetailStatusId StatusId, IEnumerable<(Guid DocumentId, DocumentStatusId DocumentStatusId)> Documents)> GetRevocationDataById(Guid credentialId, string bpnl);
void AttachAndModifyCredential(Guid credentialId, Action<CompanySsiDetail>? initialize, Action<CompanySsiDetail> modify);
Task<(VerifiedCredentialTypeId TypeId, string RequesterId)> GetCredentialNotificationData(Guid credentialId);
Task<(bool Exists, bool IsSameCompany, IEnumerable<(DocumentStatusId StatusId, byte[] Content)> Documents)> GetSignedCredentialForCredentialId(Guid credentialId, string bpnl);
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ public interface IDocumentRepository
Document CreateDocument(string documentName, byte[] documentContent, byte[] hash, MediaTypeId mediaTypeId, DocumentTypeId documentTypeId, Action<Document>? setupOptionalFields);

void AssignDocumentToCompanySsiDetails(Guid documentId, Guid companySsiDetailId);
void AttachAndModifyDocuments(IEnumerable<(Guid DocumentId, Action<Document>? Initialize, Action<Document> Modify)> documentData);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,15 @@ namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;

public enum ProcessStepTypeId
{
// Issuer Process
// CREATE CREDENTIAL PROCESS
CREATE_CREDENTIAL = 1,
SIGN_CREDENTIAL = 2,
SAVE_CREDENTIAL_DOCUMENT = 3,
CREATE_CREDENTIAL_FOR_HOLDER = 4,
TRIGGER_CALLBACK = 5,

// DECLINE PROCESS
REVOKE_CREDENTIAL = 100,
TRIGGER_NOTIFICATION = 101,
TRIGGER_MAIL = 102
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ namespace Org.Eclipse.TractusX.SsiCredentialIssuer.Entities.Enums;
public enum ProcessTypeId
{
CREATE_CREDENTIAL = 1,
DECLINE_CREDENTIAL = 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,21 @@ public enum VerifiedCredentialExternalTypeId
[EnumMember(Value = "vehicleDismantle")]
VEHICLE_DISMANTLE = 4,

[EnumMember(Value = "SustainabilityCredential")]
SUSTAINABILITY_CREDENTIAL = 5,
[EnumMember(Value = "CircularEconomyCredential")]
CIRCULAR_ECONOMY = 5,

[EnumMember(Value = "QualityCredential")]
QUALITY_CREDENTIAL = 6,

[EnumMember(Value = "BusinessPartnerCredential")]
BUSINESS_PARTNER_NUMBER = 7
BUSINESS_PARTNER_NUMBER = 7,

[EnumMember(Value = "DemandCapacityCredential")]
DEMAND_AND_CAPACITY_MANAGEMENT = 8,

[EnumMember(Value = "DemandCapacityCredential")]
DEMAND_AND_CAPACITY_MANAGEMENT_PURIS = 9,

[EnumMember(Value = "BusinessPartnerCredential")]
BUSINESS_PARTNER_DATA_MANAGEMENT = 10
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,21 @@ public enum VerifiedCredentialTypeId
[EnumMember(Value = "Dismantler Certificate")]
DISMANTLER_CERTIFICATE = 4,

[EnumMember(Value = "Sustainability Framework")]
SUSTAINABILITY_FRAMEWORK = 5,
[EnumMember(Value = "Circular Economy")]
CIRCULAR_ECONOMY = 5,

[EnumMember(Value = "frameworkAgreement.quality")]
FRAMEWORK_AGREEMENT_QUALITY = 6,

[EnumMember(Value = "BusinessPartnerCredential")]
BUSINESS_PARTNER_NUMBER = 7
BUSINESS_PARTNER_NUMBER = 7,

[EnumMember(Value = "Demand and Capacity Management")]
DEMAND_AND_CAPACITY_MANAGEMENT = 8,

[EnumMember(Value = "Demand and Capacity Management")]
DEMAND_AND_CAPACITY_MANAGEMENT_PURIS = 9,

[EnumMember(Value = "Business Partner Data Management")]
BUSINESS_PARTNER_DATA_MANAGEMENT = 10
}
Loading
Loading