Skip to content

Commit

Permalink
Delete one time use credentials (#225)
Browse files Browse the repository at this point in the history
* Delete one time use credentials

Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id>

* fix unit test

Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id>

* increase batch size

Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de>

---------

Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id>
Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de>
Co-authored-by: kenkosmowski <ken.kosmowski@gmx.de>
  • Loading branch information
JoTiTu and kenkosmowski authored Nov 21, 2024
1 parent a517cba commit 0566029
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 27 deletions.
25 changes: 18 additions & 7 deletions src/WalletFramework.MdocVc/MdocRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ public CredentialId CredentialId

public CredentialState CredentialState { get; }

//TODO: Must be set when batch issuance is implemented
// public bool OneTimeUse { get; }
/// <summary>
/// Tracks whether it's a one-time use Mdoc.
/// </summary>
public bool OneTimeUse { get; set; }

public Option<DateTime> ExpiresAt { get; }

Expand All @@ -56,7 +58,8 @@ public MdocRecord(
KeyId keyId,
CredentialSetId credentialSetId,
CredentialState credentialState,
Option<DateTime> expiresAt)
Option<DateTime> expiresAt,
bool isOneTimeUse = false)
{
CredentialId = CredentialId.CreateCredentialId();
Mdoc = mdoc;
Expand All @@ -65,6 +68,7 @@ public MdocRecord(
CredentialSetId = credentialSetId;
CredentialState = credentialState;
ExpiresAt = expiresAt;
OneTimeUse = isOneTimeUse;
}

#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
Expand Down Expand Up @@ -108,6 +112,7 @@ public static class MdocRecordFun
private const string CredentialSetIdJsonKey = "credentialSetId";
private const string CredentialStateJsonKey = "credentialState";
private const string ExpiresAtJsonKey = "expiresAt";
private const string OneTimeUseJsonKey = "oneTimeUse";

public static MdocRecord DecodeFromJson(JObject json)
{
Expand Down Expand Up @@ -136,7 +141,12 @@ from expires in json.GetByKey(ExpiresAtJsonKey).ToOption()

var credentialState = Enum.Parse<CredentialState>(json[CredentialStateJsonKey]!.ToString());

var result = new MdocRecord(mdoc, displays, keyId, credentialSetId, credentialState, expiresAt)
var oneTimeUse = json.GetByKey(OneTimeUseJsonKey).ToOption().Match(
Some: value => value.ToObject<bool>(),
None: () => false
);

var result = new MdocRecord(mdoc, displays, keyId, credentialSetId, credentialState, expiresAt, oneTimeUse)
{
Id = id
};
Expand All @@ -152,7 +162,8 @@ public static JObject EncodeToJson(this MdocRecord record)
{ MdocJsonKey, record.Mdoc.Encode() },
{ KeyIdJsonKey, record.KeyId.ToString() },
{ CredentialSetIdJsonKey, record.CredentialSetId.ToString() },
{ CredentialStateJsonKey, record.CredentialState.ToString() }
{ CredentialStateJsonKey, record.CredentialState.ToString() },
{ OneTimeUseJsonKey, record.OneTimeUse }
};

record.ExpiresAt.IfSome(expires => result.Add(ExpiresAtJsonKey, expires));
Expand All @@ -171,6 +182,6 @@ public static JObject EncodeToJson(this MdocRecord record)
return result;
}

public static MdocRecord ToRecord(this Mdoc mdoc, Option<List<MdocDisplay>> displays, KeyId keyId, CredentialSetId credentialSetId) =>
new(mdoc, displays, keyId, credentialSetId, CredentialState.Active, Option<DateTime>.None);
public static MdocRecord ToRecord(this Mdoc mdoc, Option<List<MdocDisplay>> displays, KeyId keyId, CredentialSetId credentialSetId, bool isOneTimeUse) =>
new(mdoc, displays, keyId, credentialSetId, CredentialState.Active, Option<DateTime>.None, isOneTimeUse);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Implementations;

public class CredentialRequestService : ICredentialRequestService
{
private const int MaxBatchSize = 10;
private const int MaxBatchSize = 20;

public CredentialRequestService(
HttpClient httpClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ await credential.Value.Match(
async sdJwt =>
{
var record = sdJwt.Decoded.ToRecord(configuration.AsT0, response.KeyId,
credentialSet.GetCredentialSetId());
credentialSet.GetCredentialSetId(), creds.Count > 1);
var context = await _agentProvider.GetContextAsync();
await _sdJwtService.AddAsync(context, record);
Expand All @@ -300,7 +300,7 @@ await credential.Value.Match(
{
var displays = MdocFun.CreateMdocDisplays(configuration.AsT1);
var record = mdoc.Decoded.ToRecord(displays, response.KeyId,
credentialSet.GetCredentialSetId());
credentialSet.GetCredentialSetId(), creds.Count > 1);
await _mdocStorage.Add(record);
credentialSet.AddMDocData(record);
Expand Down Expand Up @@ -394,7 +394,7 @@ await credential.Value.Match(
dPop => dPop with { Token = dPop.Token with { CNonce = cNonce.ToNullable() } });
var record = sdJwt.Decoded.ToRecord(configuration.AsT0, response.KeyId,
credentialSet.GetCredentialSetId());
credentialSet.GetCredentialSetId(), creds.Count > 1);
await _sdJwtService.AddAsync(context, record);
credentialSet.AddSdJwtData(record);
Expand All @@ -407,7 +407,7 @@ await credential.Value.Match(
var displays = MdocFun.CreateMdocDisplays(configuration.AsT1);
var record = mdoc.Decoded.ToRecord(displays, response.KeyId,
credentialSet.GetCredentialSetId());
credentialSet.GetCredentialSetId(), creds.Count > 1);
await _mdocStorage.Add(record);
credentialSet.AddMDocData(record);
Expand Down Expand Up @@ -499,7 +499,7 @@ select credentialsOrTransactionId.Match<OneOf<List<ICredential>, TransactionId>>
sdJwt =>
{
var record = sdJwt.Decoded.ToRecord(configuration.AsT0, response.KeyId,
credentialSetRecord.GetCredentialSetId());
credentialSetRecord.GetCredentialSetId(), creds.Count > 1);
credentialSetRecord.AddSdJwtData(record);
Expand Down Expand Up @@ -527,7 +527,7 @@ select credentialsOrTransactionId.Match<OneOf<List<ICredential>, TransactionId>>
{
var displays = MdocFun.CreateMdocDisplays(configuration.AsT1);
var record = mdoc.Decoded.ToRecord(displays, response.KeyId,
credentialSetRecord.GetCredentialSetId());
credentialSetRecord.GetCredentialSetId(), creds.Count > 1);
credentialSetRecord.AddMDocData(record);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public static SdJwtRecord ToRecord(
this SdJwtDoc sdJwtDoc,
SdJwtConfiguration configuration,
KeyId keyId,
CredentialSetId credentialSetId)
CredentialSetId credentialSetId,
bool isOneTimeUse)
{
var claims = configuration
.Claims?
Expand Down Expand Up @@ -62,7 +63,8 @@ select displays.Select(credentialDisplay =>
claims!,
display.Fallback(new List<SdJwtDisplay>()),
keyId,
credentialSetId);
credentialSetId,
isOneTimeUse);

return record;
}
Expand Down
22 changes: 20 additions & 2 deletions src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using WalletFramework.MdocLib.Security;
using WalletFramework.MdocLib.Security.Cose;
using WalletFramework.MdocVc;
using WalletFramework.Oid4Vc.Oid4Vci.Abstractions;
using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Abstractions;
using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models;
using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models;
Expand Down Expand Up @@ -52,13 +53,15 @@ public class Oid4VpClientService : IOid4VpClientService
/// <param name="logger">The ILogger.</param>
/// <param name="authFlowSessionStorage">The Auth Flow Session Storage.</param>
/// <param name="oid4VpRecordService">The service responsible for OidPresentationRecord related operations.</param>
/// <param name="mDocStorage">The service responsible for mDOc storage operations.</param>
public Oid4VpClientService(
IAgentProvider agentProvider,
IHttpClientFactory httpClientFactory,
ILogger<Oid4VpClientService> logger,
IMdocAuthenticationService mdocAuthenticationService,
IOid4VpHaipClient oid4VpHaipClient,
IOid4VpRecordService oid4VpRecordService,
IMdocStorage mDocStorage,
IPexService pexService,
IAuthFlowSessionStorage authFlowSessionStorage,
ISdJwtVcHolderService sdJwtVcHolderService)
Expand All @@ -69,6 +72,7 @@ public Oid4VpClientService(
_mdocAuthenticationService = mdocAuthenticationService;
_oid4VpHaipClient = oid4VpHaipClient;
_oid4VpRecordService = oid4VpRecordService;
_mDocStorage = mDocStorage;
_pexService = pexService;
_authFlowSessionStorage = authFlowSessionStorage;
_sdJwtVcHolderService = sdJwtVcHolderService;
Expand All @@ -80,6 +84,7 @@ public Oid4VpClientService(
private readonly IMdocAuthenticationService _mdocAuthenticationService;
private readonly IOid4VpHaipClient _oid4VpHaipClient;
private readonly IOid4VpRecordService _oid4VpRecordService;
private readonly IMdocStorage _mDocStorage;
private readonly IPexService _pexService;
private readonly IAuthFlowSessionStorage _authFlowSessionStorage;
private readonly ISdJwtVcHolderService _sdJwtVcHolderService;
Expand Down Expand Up @@ -218,6 +223,21 @@ from path in field.Path.Select(path => path.TrimStart('$', '.'))
if (clientAttestation != null)
httpClient.AddClientAttestationPopHeader(clientAttestation);

// ToDo: when to delete these records?
var context = await _agentProvider.GetContextAsync();
foreach (var credential in credentials)
{
switch (credential.Credential)
{
case SdJwtRecord sdJwtRecord when sdJwtRecord.OneTimeUse:
await _sdJwtVcHolderService.DeleteAsync(context, sdJwtRecord.GetId());
break;
case MdocRecord mDocRecord when mDocRecord.OneTimeUse:
await _mDocStorage.Delete(mDocRecord);
break;
}
}

var responseMessage = await httpClient.SendAsync(message);
if (!responseMessage.IsSuccessStatusCode)
{
Expand Down Expand Up @@ -277,8 +297,6 @@ from claim in sdJwtRecord.Claims
return result;
});

var context = await _agentProvider.GetContextAsync();

await _oid4VpRecordService.StoreAsync(
context,
authorizationRequest.ClientId,
Expand Down
27 changes: 18 additions & 9 deletions src/WalletFramework.SdJwtVc/Models/Records/SdJwtRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ public sealed class SdJwtRecord : RecordBase, ICredential
/// </summary>
public CredentialState CredentialState { get; set; }

//TODO: Must be set when batch issuance is implemented
// public bool OneTimeUse { get; set; }
/// <summary>
/// Tracks whether it's a one-time use SD-JWT.
/// </summary>
public bool OneTimeUse { get; set; }

/// <summary>
/// Tracks the Expiration Date of the Sd-JWT
Expand Down Expand Up @@ -138,12 +140,13 @@ public SdJwtRecord()
/// <param name="claims">The claims made.</param>
/// <param name="disclosures">The disclosures.</param>
/// <param name="display">The display of the credential.</param>
/// <param name="issuerId"></param>
/// <param name="issuerId">The Id of the issuer</param>
/// <param name="encodedIssuerSignedJwt">The Issuer-signed JWT part of the SD-JWT.</param>
/// <param name="credentialSetId">The CredentialSetId.</param>
/// <param name="expiresAt">The CredentialSetId.</param>
/// <param name="issuedAt">The CredentialSetId.</param>
/// <param name="notBefore">The CredentialSetId.</param>
/// <param name="expiresAt">The Expiration Date.</param>
/// <param name="issuedAt">The Issued at date.</param>
/// <param name="notBefore">The valid after date.</param>
/// <param name="isOneTimeUse">Indicator whether the credential should be sued only once.</param>
[JsonConstructor]
public SdJwtRecord(
Dictionary<string, ClaimMetadata> displayedAttributes,
Expand All @@ -155,7 +158,8 @@ public SdJwtRecord(
string credentialSetId,
DateTime? expiresAt,
DateTime? issuedAt,
DateTime? notBefore)
DateTime? notBefore,
bool isOneTimeUse = false)
{
Claims = claims;
Disclosures = disclosures;
Expand All @@ -170,14 +174,16 @@ public SdJwtRecord(
NotBefore = notBefore;
IssuerId = issuerId;
CredentialSetId = credentialSetId;
OneTimeUse = isOneTimeUse;
}

public SdJwtRecord(
string serializedSdJwtWithDisclosures,
Dictionary<string, ClaimMetadata> displayedAttributes,
List<SdJwtDisplay> display,
KeyId keyId,
CredentialSetId credentialSetId)
CredentialSetId credentialSetId,
bool isOneTimeUse = false)
{
Id = Guid.NewGuid().ToString();

Expand All @@ -190,6 +196,7 @@ public SdJwtRecord(

CredentialSetId = credentialSetId;
CredentialState = CredentialState.Active;
OneTimeUse = isOneTimeUse;

KeyId = keyId;
ExpiresAt = sdJwtDoc.UnsecuredPayload.SelectToken("exp")?.Value<long>() is not null
Expand All @@ -212,7 +219,8 @@ public SdJwtRecord(
Dictionary<string, ClaimMetadata> displayedAttributes,
List<SdJwtDisplay> display,
KeyId keyId,
CredentialSetId credentialSetId)
CredentialSetId credentialSetId,
bool isOneTimeUse = false)
{
Id = Guid.NewGuid().ToString();

Expand All @@ -224,6 +232,7 @@ public SdJwtRecord(

CredentialSetId = credentialSetId;
CredentialState = CredentialState.Active;
OneTimeUse = isOneTimeUse;

KeyId = keyId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public Oid4VpClientServiceTests()
_mdocAuthenticationService.Object,
oid4VpHaipClient,
_oid4VpRecordService,
_mdocStorageMock.Object,
pexService,
_authFlowSessionStorageMock.Object,
_sdJwtVcHolderService);
Expand Down

0 comments on commit 0566029

Please sign in to comment.