Skip to content

Commit

Permalink
Improve auth code flow (#224)
Browse files Browse the repository at this point in the history
* fix AuthServer retrieval

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

* fix credential state updating

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

* fix batch issuance count

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

* allow auth code without PAR

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

* small improvements

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 0566029 commit 05a671e
Show file tree
Hide file tree
Showing 13 changed files with 312 additions and 257 deletions.
13 changes: 6 additions & 7 deletions src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,23 @@ public virtual async Task UpdateAsync(CredentialSetRecord credentialSetRecord)

public async Task<CredentialSetRecord> RefreshCredentialSetState(CredentialSetRecord credentialSetRecord)
{
var oldState = credentialSetRecord.State;

if (credentialSetRecord.IsDeleted())
return credentialSetRecord;

await credentialSetRecord.ExpiresAt.IfSomeAsync(async expiresAt =>
credentialSetRecord.ExpiresAt.IfSome(expiresAt =>
{
if (expiresAt < DateTime.UtcNow)
{
credentialSetRecord.State = CredentialState.Expired;
await UpdateAsync(credentialSetRecord);
}
});

//TODO: Implement revocation check (status List) -> Currently IsRevoked always returns false
if (credentialSetRecord.IsRevoked())
{
credentialSetRecord.State = CredentialState.Revoked;

if (oldState != credentialSetRecord.State)
await UpdateAsync(credentialSetRecord);
}

return credentialSetRecord;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,10 @@ public record AuthorizationDetails
public string[]? Locations { get; }

internal AuthorizationDetails(
string? format,
string? vct,
string? credentialConfigurationId,
string[]? locations,
string? docType)
string credentialConfigurationId,
string[]? locations)
{
if (!string.IsNullOrWhiteSpace(format) && !string.IsNullOrWhiteSpace(credentialConfigurationId))
{
throw new ArgumentException("Both format and credentialConfigurationId cannot be present at the same time.");
}

Format = format;
Vct = vct;
CredentialConfigurationId = credentialConfigurationId;
Locations = locations;
DocType = docType;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System.Web;
using Newtonsoft.Json;
using static Newtonsoft.Json.JsonConvert;

namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models;

internal record VciAuthorizationRequest
{
[JsonProperty("client_id")]
public string ClientId { get; }

[JsonProperty("response_type")]
public string ResponseType { get; } = "code";

[JsonProperty("redirect_uri")]
public string RedirectUri { get; }

[JsonProperty("code_challenge")]
public string CodeChallenge { get; }

[JsonProperty("code_challenge_method")]
public string CodeChallengeMethod { get; }

[JsonProperty("state", NullValueHandling = NullValueHandling.Ignore)]
public string AuthFlowSessionState { get; }

[JsonProperty("authorization_details", NullValueHandling = NullValueHandling.Ignore)]
public AuthorizationDetails[]? AuthorizationDetails { get; }

[JsonProperty("issuer_state", NullValueHandling = NullValueHandling.Ignore)]
public string? IssuerState { get; }

[JsonProperty("wallet_issuer", NullValueHandling = NullValueHandling.Ignore)]
public string? WalletIssuer { get; }

[JsonProperty("user_hint", NullValueHandling = NullValueHandling.Ignore)]
public string? UserHint { get; }

[JsonProperty("scope", NullValueHandling = NullValueHandling.Ignore)]
public string? Scope { get; }

[JsonProperty("resource", NullValueHandling = NullValueHandling.Ignore)]
public string? Resource { get; }

public VciAuthorizationRequest(
AuthFlowSessionState authFlowSessionState,
ClientOptions clientOptions,
AuthorizationCodeParameters authorizationCodeParameters,
AuthorizationDetails[]? authorizationDetails,
string? scope,
string? issuerState,
string? userHint,
string? resource)
{
ClientId = clientOptions.ClientId;
RedirectUri = clientOptions.RedirectUri;
WalletIssuer = clientOptions.WalletIssuer;
CodeChallenge = authorizationCodeParameters.Challenge;
CodeChallengeMethod = authorizationCodeParameters.CodeChallengeMethod;
AuthFlowSessionState = authFlowSessionState;
AuthorizationDetails = authorizationDetails;
IssuerState = issuerState;
UserHint = userHint;
Scope = scope;
Resource = resource;
}
}

internal static class VciAuthorizationRequestExtensions
{
internal static FormUrlEncodedContent ToFormUrlEncoded(this VciAuthorizationRequest authorizationRequest)
{
var keyValuePairs = new List<KeyValuePair<string, string>>();

if (!string.IsNullOrEmpty(authorizationRequest.ClientId))
keyValuePairs.Add(new KeyValuePair<string, string>("client_id", authorizationRequest.ClientId));

if (!string.IsNullOrEmpty(authorizationRequest.ResponseType))
keyValuePairs.Add(new KeyValuePair<string, string>("response_type", authorizationRequest.ResponseType));

if (!string.IsNullOrEmpty(authorizationRequest.RedirectUri))
keyValuePairs.Add(new KeyValuePair<string, string>("redirect_uri", authorizationRequest.RedirectUri));

if (!string.IsNullOrEmpty(authorizationRequest.CodeChallenge))
keyValuePairs.Add(new KeyValuePair<string, string>("code_challenge", authorizationRequest.CodeChallenge));

if (!string.IsNullOrEmpty(authorizationRequest.CodeChallengeMethod))
keyValuePairs.Add(new KeyValuePair<string, string>("code_challenge_method", authorizationRequest.CodeChallengeMethod));

if (!string.IsNullOrEmpty(authorizationRequest.AuthFlowSessionState))
keyValuePairs.Add(new KeyValuePair<string, string>("state", authorizationRequest.AuthFlowSessionState));

if (authorizationRequest.AuthorizationDetails != null)
keyValuePairs.Add(new KeyValuePair<string, string>("authorization_details", SerializeObject(authorizationRequest.AuthorizationDetails)));

if (!string.IsNullOrEmpty(authorizationRequest.IssuerState))
keyValuePairs.Add(new KeyValuePair<string, string>("issuer_state", authorizationRequest.IssuerState));

if (!string.IsNullOrEmpty(authorizationRequest.WalletIssuer))
keyValuePairs.Add(new KeyValuePair<string, string>("wallet_issuer", authorizationRequest.WalletIssuer));

if (!string.IsNullOrEmpty(authorizationRequest.UserHint))
keyValuePairs.Add(new KeyValuePair<string, string>("user_hint", authorizationRequest.UserHint));

if (!string.IsNullOrEmpty(authorizationRequest.Scope))
keyValuePairs.Add(new KeyValuePair<string, string>("scope", authorizationRequest.Scope));

return new FormUrlEncodedContent(keyValuePairs);
}

internal static string ToQueryString(this VciAuthorizationRequest authorizationRequest)
{
var queryString = "?";

if (!string.IsNullOrEmpty(authorizationRequest.ClientId))
queryString = queryString + "client_id=" + authorizationRequest.ClientId + "&";

if (!string.IsNullOrEmpty(authorizationRequest.ResponseType))
queryString = queryString + "response_type=" + authorizationRequest.ResponseType + "&";

if (!string.IsNullOrEmpty(authorizationRequest.RedirectUri))
queryString = queryString + "redirect_uri=" + HttpUtility.UrlEncode(authorizationRequest.RedirectUri) + "&";

if (!string.IsNullOrEmpty(authorizationRequest.CodeChallenge))
queryString = queryString + "code_challenge=" + authorizationRequest.CodeChallenge + "&";

if (!string.IsNullOrEmpty(authorizationRequest.CodeChallengeMethod))
queryString = queryString + "code_challenge_method=" + authorizationRequest.CodeChallengeMethod + "&";

if (!string.IsNullOrEmpty(authorizationRequest.AuthFlowSessionState))
queryString = queryString + "state=" + authorizationRequest.AuthFlowSessionState + "&";

if (authorizationRequest.AuthorizationDetails != null)
queryString = queryString + "authorization_details=" + HttpUtility.UrlEncode(SerializeObject(authorizationRequest.AuthorizationDetails)) + "&";

if (!string.IsNullOrEmpty(authorizationRequest.IssuerState))
queryString = queryString + "issuer_state=" + authorizationRequest.IssuerState + "&";

if (!string.IsNullOrEmpty(authorizationRequest.WalletIssuer))
queryString = queryString + "wallet_issuer=" + HttpUtility.UrlEncode(authorizationRequest.WalletIssuer) + "&";

if (!string.IsNullOrEmpty(authorizationRequest.UserHint))
queryString = queryString + "user_hint=" + authorizationRequest.UserHint + "&";

if (!string.IsNullOrEmpty(authorizationRequest.Scope))
queryString = queryString + "scope=" + authorizationRequest.Scope + "&";

return queryString.TrimEnd('&');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ public class AuthorizationServerMetadata
/// </summary>
[JsonProperty("require_pushed_authorization_requests")]
public bool? RequirePushedAuthorizationRequests { get; set; }

/// <summary>
/// Gets or sets a value indicating which grant types the Authorization Server supports.
/// </summary>
[JsonProperty("grant_types_supported")]
public string[]? GrantTypesSupported { get; set; }

internal bool IsDPoPSupported => DPopSigningAlgValuesSupported != null && DPopSigningAlgValuesSupported.Contains("ES256");

internal bool SupportsPreAuthFlow => GrantTypesSupported != null && GrantTypesSupported.Contains("urn:ietf:params:oauth:grant-type:pre-authorized_code");

internal bool SupportsAuthCodeFlow => GrantTypesSupported != null && GrantTypesSupported.Contains("authorization_code");
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,23 +118,4 @@ public static JObject EncodeToJson(this CredentialDisplay display)

return result;
}

// TODO: Unpure
public static SdJwtDisplay ToSdJwtDisplay(this CredentialDisplay credentialDisplay)
{
var logo = new SdJwtDisplay.SdJwtLogo
{
Uri = credentialDisplay.Logo.ToNullable()?.Uri.ToNullable()!,
AltText = credentialDisplay.Logo.ToNullable()?.AltText.ToNullable()
};

return new SdJwtDisplay
{
Logo = logo,
Name = credentialDisplay.Name.ToNullable(),
BackgroundColor = credentialDisplay.BackgroundColor.ToNullable(),
Locale = credentialDisplay.Locale.ToNullable()?.ToString(),
TextColor = credentialDisplay.TextColor.ToNullable()
};
}
}
Loading

0 comments on commit 05a671e

Please sign in to comment.