Skip to content

Commit c5e8be4

Browse files
JoTiTuDindexx
andauthored
Refactor auth flow session handling (#129)
* use state paramter in PAR for Auth Code Flow session handling Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * remove scheme check to allow verified deeplinks Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * mdoc oid4vci Signed-off-by: Kevin <kevin.dinh@lissi.id> * separate integration tests Signed-off-by: Kevin <kevin.dinh@lissi.id> * move away from json converters Signed-off-by: Kevin <kevin.dinh@lissi.id> * fix credential request json Signed-off-by: Kevin <kevin.dinh@lissi.id> * align with framework Refactoring Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * remove JsonSettings Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * rename VciSessionState -> AuthCodeSessionState Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> --------- Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> Signed-off-by: Kevin <kevin.dinh@lissi.id> Co-authored-by: Kevin <kevin.dinh@lissi.id>
1 parent f2d4506 commit c5e8be4

File tree

14 files changed

+108
-107
lines changed

14 files changed

+108
-107
lines changed

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Abstractions/IAuthFlowSessionStorage.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ public interface IAuthFlowSessionStorage
1414
/// Deletes the authorization session record by the session identifier.
1515
/// </summary>
1616
/// <param name="context">Agent Context</param>
17-
/// <param name="sessionId">Session Identifier of a Authorization Code Flow session</param>
17+
/// <param name="authFlowSessionState">Session State Identifier of a Authorization Code Flow session</param>
1818
/// <returns></returns>
19-
Task<bool> DeleteAsync(IAgentContext context, VciSessionId sessionId);
19+
Task<bool> DeleteAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState);
2020

2121
/// <summary>
2222
/// Retrieves the authorization session record by the session identifier.
2323
/// </summary>
2424
/// <param name="context">Agent Context</param>
25-
/// <param name="sessionId">Session Identifier of a Authorization Code Flow session</param>
25+
/// <param name="authFlowSessionState">Session State Identifier of a Authorization Code Flow session</param>
2626
/// <returns></returns>
27-
Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, VciSessionId sessionId);
27+
Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState);
2828

2929
/// <summary>
3030
/// Stores the authorization session record.
@@ -35,11 +35,11 @@ public interface IAuthFlowSessionStorage
3535
/// Parameters required for the authorization during the VCI authorization code
3636
/// flow.
3737
/// </param>
38-
/// <param name="sessionId"></param>
38+
/// <param name="authFlowSessionState">Session State Identifier of a Authorization Code Flow session</param>
3939
/// <returns></returns>
4040
Task<string> StoreAsync(
4141
IAgentContext agentContext,
4242
AuthorizationData authorizationData,
4343
AuthorizationCodeParameters authorizationCodeParameters,
44-
VciSessionId sessionId);
44+
AuthFlowSessionState authFlowSessionState);
4545
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using WalletFramework.Core.Functional;
2+
3+
namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Errors;
4+
5+
public record AuthFlowSessionStateError(string Value) : Error($"Invalid AuthFlowSessionState: {Value}");

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Errors/VciSessionIdError.cs

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Implementations/AuthFlowSessionStorage.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,26 @@ public async Task<string> StoreAsync(
2626
IAgentContext agentContext,
2727
AuthorizationData authorizationData,
2828
AuthorizationCodeParameters authorizationCodeParameters,
29-
VciSessionId sessionId)
29+
AuthFlowSessionState authFlowSessionState)
3030
{
3131
var record = new AuthFlowSessionRecord(
3232
authorizationData,
3333
authorizationCodeParameters,
34-
sessionId);
34+
authFlowSessionState);
3535

3636
await _recordService.AddAsync(agentContext.Wallet, record, AuthFlowSessionRecordFun.EncodeToJson);
3737

3838
return record.Id;
3939
}
4040

4141
/// <inheritdoc />
42-
public async Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, VciSessionId sessionId)
42+
public async Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState)
4343
{
44-
var record = await _recordService.GetAsync(context.Wallet, sessionId, AuthFlowSessionRecordFun.DecodeFromJson);
44+
var record = await _recordService.GetAsync(context.Wallet, authFlowSessionState, AuthFlowSessionRecordFun.DecodeFromJson);
4545
return record!;
4646
}
4747

4848
/// <inheritdoc />
49-
public async Task<bool> DeleteAsync(IAgentContext context, VciSessionId sessionId) =>
50-
await _recordService.DeleteAsync<AuthFlowSessionRecord>(context.Wallet, sessionId);
49+
public async Task<bool> DeleteAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState) =>
50+
await _recordService.DeleteAsync<AuthFlowSessionRecord>(context.Wallet, authFlowSessionState);
5151
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System.Globalization;
2+
using Newtonsoft.Json.Linq;
3+
using WalletFramework.Core.Functional;
4+
using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Errors;
5+
6+
namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models;
7+
8+
/// <summary>
9+
/// Identifier of the authorization state during the VCI Authorization Code Flow.
10+
/// </summary>
11+
public struct AuthFlowSessionState
12+
{
13+
/// <summary>
14+
/// Gets the value of the state identifier.
15+
/// </summary>
16+
private string Value { get; }
17+
18+
private AuthFlowSessionState(string value) => Value = value;
19+
20+
/// <summary>
21+
/// Returns the value of the state identifier.
22+
/// </summary>
23+
/// <param name="authFlowSessionState"></param>
24+
/// <returns></returns>
25+
public static implicit operator string(AuthFlowSessionState authFlowSessionState) => authFlowSessionState.Value;
26+
27+
public static Validation<AuthFlowSessionState> ValidAuthFlowSessionState(string authFlowSessionState)
28+
{
29+
if (!Guid.TryParse(authFlowSessionState, out _))
30+
{
31+
return new AuthFlowSessionStateError(authFlowSessionState);
32+
}
33+
34+
return new AuthFlowSessionState(authFlowSessionState);
35+
}
36+
37+
public static AuthFlowSessionState CreateAuthFlowSessionState()
38+
{
39+
var guid = Guid.NewGuid().ToString();
40+
return new AuthFlowSessionState(guid);
41+
}
42+
}
43+
44+
public static class AuthFlowSessionStateFun
45+
{
46+
public static AuthFlowSessionState DecodeFromJson(JValue json) => AuthFlowSessionState
47+
.ValidAuthFlowSessionState(json.ToString(CultureInfo.InvariantCulture))
48+
.UnwrapOrThrow(new InvalidOperationException("AuthFlowSessionState is corrupt"));
49+
}

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/IssuanceSession.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ public record IssuanceSession
1111
/// <summary>
1212
/// Gets the session identifier.
1313
/// </summary>
14-
public VciSessionId SessionId { get; }
14+
public AuthFlowSessionState AuthFlowSessionState { get; }
1515

1616
/// <summary>
1717
/// Gets the actual authorization code that is received from the authorization server upon successful authorization.
1818
/// </summary>
1919
public string Code { get; }
2020

21-
private IssuanceSession(VciSessionId sessionId, string code) => (SessionId, Code) = (sessionId, code);
21+
private IssuanceSession(AuthFlowSessionState authFlowSessionState, string code) => (AuthFlowSessionState, Code) = (authFlowSessionState, code);
2222

2323
/// <summary>
2424
/// Creates a new instance of <see cref="IssuanceSession"/> from the given <see cref="Uri"/>.
@@ -36,9 +36,9 @@ public static IssuanceSession FromUri(Uri uri)
3636
throw new InvalidOperationException("Query parameter 'code' is missing");
3737
}
3838

39-
var sessionIdParam = queryParams.Get("session");
40-
var sessionId = VciSessionId.ValidSessionId(sessionIdParam).Fallback(VciSessionId.CreateSessionId());
39+
var sessionStateParam = queryParams.Get("state");
40+
var authFlowSessionState = AuthFlowSessionState.ValidAuthFlowSessionState(sessionStateParam).Fallback(AuthFlowSessionState.CreateAuthFlowSessionState());
4141

42-
return new IssuanceSession(sessionId, code);
42+
return new IssuanceSession(authFlowSessionState, code);
4343
}
4444
}

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/PushedAuthorizationRequest.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ internal record PushedAuthorizationRequest
1919

2020
[JsonProperty("code_challenge_method")]
2121
public string CodeChallengeMethod { get; }
22+
23+
[JsonProperty("state", NullValueHandling = NullValueHandling.Ignore)]
24+
public string AuthFlowSessionState { get; }
2225

2326
[JsonProperty("authorization_details", NullValueHandling = NullValueHandling.Ignore)]
2427
public AuthorizationDetails[]? AuthorizationDetails { get; }
@@ -39,7 +42,7 @@ internal record PushedAuthorizationRequest
3942
public string? Resource { get; }
4043

4144
public PushedAuthorizationRequest(
42-
VciSessionId sessionId,
45+
AuthFlowSessionState authFlowSessionState,
4346
ClientOptions clientOptions,
4447
AuthorizationCodeParameters authorizationCodeParameters,
4548
AuthorizationDetails[]? authorizationDetails,
@@ -49,10 +52,11 @@ public PushedAuthorizationRequest(
4952
string? resource)
5053
{
5154
ClientId = clientOptions.ClientId;
52-
RedirectUri = clientOptions.RedirectUri + "?session=" + sessionId;
55+
RedirectUri = clientOptions.RedirectUri;
5356
WalletIssuer = clientOptions.WalletIssuer;
5457
CodeChallenge = authorizationCodeParameters.Challenge;
5558
CodeChallengeMethod = authorizationCodeParameters.CodeChallengeMethod;
59+
AuthFlowSessionState = authFlowSessionState;
5660
AuthorizationDetails = authorizationDetails;
5761
IssuerState = issuerState;
5862
UserHint = userHint;
@@ -79,6 +83,9 @@ public FormUrlEncodedContent ToFormUrlEncoded()
7983
if (!string.IsNullOrEmpty(CodeChallengeMethod))
8084
keyValuePairs.Add(new KeyValuePair<string, string>("code_challenge_method", CodeChallengeMethod));
8185

86+
if (!string.IsNullOrEmpty(AuthFlowSessionState))
87+
keyValuePairs.Add(new KeyValuePair<string, string>("state", AuthFlowSessionState));
88+
8289
if (AuthorizationDetails != null)
8390
keyValuePairs.Add(new KeyValuePair<string, string>("authorization_details", SerializeObject(AuthorizationDetails)));
8491

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/VciSessionId.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Records/AuthFlowSessionRecord.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ namespace WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Records;
1212
public sealed class AuthFlowSessionRecord : RecordBase
1313
{
1414
/// <summary>
15-
/// The session specific id.
15+
/// The session specific state id.
1616
/// </summary>
1717
[JsonIgnore]
18-
public VciSessionId SessionId
18+
public AuthFlowSessionState AuthFlowSessionState
1919
{
20-
get => VciSessionId
21-
.ValidSessionId(Id)
22-
.UnwrapOrThrow(new InvalidOperationException("SessionId is corrupt"));
20+
get => AuthFlowSessionState
21+
.ValidAuthFlowSessionState(Id)
22+
.UnwrapOrThrow(new InvalidOperationException("AuthFlowSessionState is corrupt"));
2323
set
2424
{
2525
string str = value;
@@ -56,13 +56,13 @@ public AuthFlowSessionRecord()
5656
/// </summary>
5757
/// <param name="authorizationData"></param>
5858
/// <param name="authorizationCodeParameters"></param>
59-
/// <param name="sessionId"></param>
59+
/// <param name="authFlowSessionState"></param>
6060
public AuthFlowSessionRecord(
6161
AuthorizationData authorizationData,
6262
AuthorizationCodeParameters authorizationCodeParameters,
63-
VciSessionId sessionId)
63+
AuthFlowSessionState authFlowSessionState)
6464
{
65-
SessionId = sessionId;
65+
AuthFlowSessionState = authFlowSessionState;
6666
RecordVersion = 1;
6767
AuthorizationCodeParameters = authorizationCodeParameters;
6868
AuthorizationData = authorizationData;
@@ -90,7 +90,7 @@ public static JObject EncodeToJson(this AuthFlowSessionRecord record)
9090
public static AuthFlowSessionRecord DecodeFromJson(JObject json)
9191
{
9292
var idJson = json[nameof(RecordBase.Id)]!.ToObject<JValue>()!;
93-
var id = VciSessionIdFun.DecodeFromJson(idJson);
93+
var id = AuthFlowSessionStateFun.DecodeFromJson(idJson);
9494

9595
var authCodeParameters = JsonConvert.DeserializeObject<AuthorizationCodeParameters>(
9696
json[AuthorizationCodeParametersJsonKey]!.ToString()

src/WalletFramework.Oid4Vc/Oid4Vci/CredOffer/GrantTypes/AuthorizationCode.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ public static Option<AuthorizationCode> OptionalAuthorizationCode(JToken authori
4646
.GetByKey("authorization_server")
4747
.OnSuccess(token => token.ToString())
4848
.ToOption();
49-
50-
if (issuerState.IsNone && authServer.IsNone)
51-
return Option<AuthorizationCode>.None;
5249

5350
return new AuthorizationCode(issuerState, authServer);
5451
}

0 commit comments

Comments
 (0)