Skip to content

Commit 8a49118

Browse files
authored
fix(#479): store uiOptions in cookie (#517)
Store the uiOptions in a cookie, and replace the protectedUiOptions included in the returnUrl sent to BankID with a GUID that references the cookie where the protectedUiOptions are stored.
1 parent 3b342c2 commit 8a49118

18 files changed

Lines changed: 232 additions & 49 deletions

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiApiControllerBase.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using ActiveLogin.Authentication.BankId.Api.Models;
66
using ActiveLogin.Authentication.BankId.Api.UserMessage;
77
using ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Models;
8+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
89
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
910
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
1011
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
@@ -25,6 +26,7 @@ public abstract class BankIdUiApiControllerBase : ControllerBase
2526
protected readonly IBankIdUiOrderRefProtector OrderRefProtector;
2627
protected readonly IBankIdQrStartStateProtector QrStartStateProtector;
2728
protected readonly IBankIdUiOptionsProtector UiOptionsProtector;
29+
protected readonly IBankIdUiOptionsCookieManager UiOptionsCookieManager;
2830

2931
private readonly IBankIdUserMessage _bankIdUserMessage;
3032
private readonly IBankIdUserMessageLocalizer _bankIdUserMessageLocalizer;
@@ -35,6 +37,7 @@ protected BankIdUiApiControllerBase(
3537
IBankIdUiOrderRefProtector orderRefProtector,
3638
IBankIdQrStartStateProtector qrStartStateProtector,
3739
IBankIdUiOptionsProtector uiOptionsProtector,
40+
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
3841

3942
IBankIdUserMessage bankIdUserMessage,
4043
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
@@ -46,6 +49,7 @@ IBankIdUiResultProtector uiAuthResultProtector
4649
OrderRefProtector = orderRefProtector;
4750
QrStartStateProtector = qrStartStateProtector;
4851
UiOptionsProtector = uiOptionsProtector;
52+
UiOptionsCookieManager = uiOptionsCookieManager;
4953

5054
_bankIdUserMessage = bankIdUserMessage;
5155
_bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
@@ -66,7 +70,7 @@ public async Task<ActionResult> Status(BankIdUiApiStatusRequest request)
6670
}
6771

6872
var orderRef = OrderRefProtector.Unprotect(request.OrderRef);
69-
var uiOptions = UiOptionsProtector.Unprotect(request.UiOptions);
73+
var uiOptions = ResolveProtectedUiOptions(request.UiOptions);
7074

7175
BankIdFlowCollectResult result;
7276
try
@@ -88,6 +92,8 @@ public async Task<ActionResult> Status(BankIdUiApiStatusRequest request)
8892
case BankIdFlowCollectResultComplete complete:
8993
{
9094
var uiResult = ConstructProtectedUiResult(orderRef.OrderRef, complete.CompletionData);
95+
UiOptionsCookieManager.Delete(request.UiOptions);
96+
9197
return OkJsonResult(BankIdUiApiStatusResponse.Finished(request.ReturnUrl, uiResult));
9298
}
9399
case BankIdFlowCollectResultRetry retry:
@@ -96,6 +102,8 @@ public async Task<ActionResult> Status(BankIdUiApiStatusRequest request)
96102
}
97103
case BankIdFlowCollectResultFailure failure:
98104
{
105+
UiOptionsCookieManager.Delete(request.UiOptions);
106+
99107
return BadRequestJsonResult(new BankIdUiApiErrorResponse(failure.StatusMessage));
100108
}
101109
default:
@@ -125,7 +133,7 @@ public async Task<ActionResult> Cancel(BankIdUiApiCancelRequest request)
125133
Validators.ThrowIfNullOrWhitespace(request.UiOptions, nameof(request.UiOptions));
126134

127135
var orderRef = OrderRefProtector.Unprotect(request.OrderRef);
128-
var uiOptions = UiOptionsProtector.Unprotect(request.UiOptions);
136+
var uiOptions = ResolveProtectedUiOptions(request.UiOptions);
129137

130138
await BankIdFlowService.Cancel(orderRef.OrderRef, uiOptions.ToBankIdFlowOptions());
131139

@@ -179,4 +187,13 @@ protected static ActionResult BadRequestJsonResult(object model)
179187
Content = JsonSerializer.Serialize(model, JsonSerializerOptions)
180188
};
181189
}
190+
191+
/// <summary>
192+
/// Resolves the UiOptions from either a GUID (stored in cookie) or the direct protected value.
193+
/// </summary>
194+
protected BankIdUiOptions ResolveProtectedUiOptions(string protectedUiOptionsOrGuid)
195+
{
196+
return UiOptionsCookieManager.Retrieve(protectedUiOptionsOrGuid)
197+
?? throw new InvalidOperationException(BankIdConstants.ErrorMessages.InvalidUiOptions);
198+
}
182199
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiAuthApiController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using ActiveLogin.Authentication.BankId.Api;
22
using ActiveLogin.Authentication.BankId.Api.UserMessage;
33
using ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Models;
4+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
45
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
56
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
67
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
@@ -24,10 +25,11 @@ public BankIdUiAuthApiController(
2425
IBankIdUiOrderRefProtector orderRefProtector,
2526
IBankIdQrStartStateProtector qrStartStateProtector,
2627
IBankIdUiOptionsProtector uiOptionsProtector,
28+
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
2729
IBankIdUserMessage bankIdUserMessage,
2830
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
2931
IBankIdUiResultProtector uiAuthResultProtector)
30-
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
32+
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, uiOptionsCookieManager, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
3133
{
3234
}
3335

@@ -38,7 +40,7 @@ public async Task<ActionResult<BankIdUiApiInitializeResponse>> Initialize(BankId
3840
Validators.ThrowIfNullOrWhitespace(request.ReturnUrl, nameof(request.ReturnUrl));
3941
Validators.ThrowIfNullOrWhitespace(request.UiOptions, nameof(request.UiOptions));
4042

41-
var uiOptions = UiOptionsProtector.Unprotect(request.UiOptions);
43+
var uiOptions = ResolveProtectedUiOptions(request.UiOptions);
4244

4345
BankIdFlowInitializeResult bankIdFlowInitializeResult;
4446
try

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiAuthController.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
12
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
23
using ActiveLogin.Authentication.BankId.AspNetCore.StateHandling;
34
using ActiveLogin.Authentication.BankId.Core.UserMessage;
@@ -20,17 +21,18 @@ public BankIdUiAuthController(
2021
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
2122
IBankIdUiOptionsProtector uiOptionsProtector,
2223
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
23-
IBankIdUiStateProtector bankIdUiStateProtector
24+
IBankIdUiStateProtector bankIdUiStateProtector,
25+
IBankIdUiOptionsCookieManager uiOptionsCookieManager
2426
)
25-
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector)
27+
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector, uiOptionsCookieManager)
2628
{
2729

2830
}
2931

3032
[HttpGet]
3133
[Route($"/[area]/{BankIdConstants.Routes.BankIdPathName}/{BankIdConstants.Routes.BankIdAuthControllerPath}")]
32-
public Task<ActionResult> Init(string returnUrl, [FromQuery(Name = BankIdConstants.QueryStringParameters.UiOptions)] string protectedUiOptions)
34+
public Task<ActionResult> Init(string returnUrl, [FromQuery(Name = BankIdConstants.QueryStringParameters.UiOptions)] string uiOptionsGuid)
3335
{
34-
return Initialize(returnUrl, BankIdConstants.Routes.BankIdAuthApiControllerName, protectedUiOptions, "Init");
36+
return Initialize(returnUrl, BankIdConstants.Routes.BankIdAuthApiControllerName, uiOptionsGuid, "Init");
3537
}
3638
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiControllerBase.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ActiveLogin.Authentication.BankId.Api.UserMessage;
22
using ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Models;
3+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
34
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
45
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
56
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
@@ -23,34 +24,37 @@ public abstract class BankIdUiControllerBase : Controller
2324
private readonly IBankIdUiOptionsProtector _uiOptionsProtector;
2425
private readonly IBankIdInvalidStateHandler _bankIdInvalidStateHandler;
2526
private readonly IBankIdUiStateProtector _bankIdUiStateProtector;
27+
private readonly IBankIdUiOptionsCookieManager _uiOptionsCookieManager;
2628

2729
protected BankIdUiControllerBase(
2830
IAntiforgery antiforgery,
2931
IStringLocalizer<ActiveLoginResources> localizer,
3032
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
3133
IBankIdUiOptionsProtector uiOptionsProtector,
3234
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
33-
IBankIdUiStateProtector bankIdUiStateProtector)
35+
IBankIdUiStateProtector bankIdUiStateProtector,
36+
IBankIdUiOptionsCookieManager uiOptionsCookieManager)
3437
{
3538
_antiforgery = antiforgery;
3639
_localizer = localizer;
3740
_bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
3841
_uiOptionsProtector = uiOptionsProtector;
3942
_bankIdInvalidStateHandler = bankIdInvalidStateHandler;
4043
_bankIdUiStateProtector = bankIdUiStateProtector;
44+
_uiOptionsCookieManager = uiOptionsCookieManager;
4145
}
4246

43-
protected async Task<ActionResult> Initialize(string returnUrl, string apiControllerName, string protectedUiOptions, string viewName)
47+
protected async Task<ActionResult> Initialize(string returnUrl, string apiControllerName, string uiOptionsGuid, string viewName)
4448
{
4549
Validators.ThrowIfNullOrWhitespace(returnUrl);
46-
Validators.ThrowIfNullOrWhitespace(protectedUiOptions, BankIdConstants.QueryStringParameters.UiOptions);
50+
Validators.ThrowIfNullOrWhitespace(uiOptionsGuid, BankIdConstants.QueryStringParameters.UiOptions);
4751

4852
if (!Url.IsLocalUrl(returnUrl))
4953
{
5054
throw new ArgumentException(BankIdConstants.ErrorMessages.InvalidReturnUrl);
5155
}
5256

53-
var uiOptions = _uiOptionsProtector.Unprotect(protectedUiOptions);
57+
var uiOptions = _uiOptionsCookieManager.Retrieve(uiOptionsGuid) ?? throw new InvalidOperationException(BankIdConstants.ErrorMessages.InvalidUiOptions);
5458
if (!HasStateCookie(uiOptions))
5559
{
5660
var invalidStateContext = new BankIdInvalidStateContext(uiOptions.CancelReturnUrl);
@@ -71,7 +75,7 @@ protected async Task<ActionResult> Initialize(string returnUrl, string apiContro
7175
}
7276
var state = _bankIdUiStateProtector.Unprotect(protectedState);
7377

74-
var viewModel = GetUiViewModel(returnUrl, apiControllerName, protectedUiOptions, uiOptions, state, antiforgeryTokens);
78+
var viewModel = GetUiViewModel(returnUrl, apiControllerName, uiOptionsGuid, uiOptions, state, antiforgeryTokens);
7579

7680
return View(viewName, viewModel);
7781
}
@@ -87,7 +91,7 @@ private bool HasStateCookie(BankIdUiOptions uiOptions)
8791
return !string.IsNullOrEmpty(HttpContext.Request.Cookies[uiOptions.StateCookieName]);
8892
}
8993

90-
private BankIdUiViewModel GetUiViewModel(string returnUrl, string apiControllerName, string protectedUiOptions, BankIdUiOptions unprotectedUiOptions, BankIdUiState uiState, AntiforgeryTokenSet antiforgeryTokens)
94+
private BankIdUiViewModel GetUiViewModel(string returnUrl, string apiControllerName, string uiOptionsGuid, BankIdUiOptions unprotectedUiOptions, BankIdUiState uiState, AntiforgeryTokenSet antiforgeryTokens)
9195
{
9296
Validators.ThrowIfNullOrWhitespace(antiforgeryTokens.RequestToken, nameof(antiforgeryTokens.RequestToken));
9397

@@ -116,7 +120,7 @@ private BankIdUiViewModel GetUiViewModel(string returnUrl, string apiControllerN
116120
ReturnUrl = returnUrl,
117121
CancelReturnUrl = Url.Content(unprotectedUiOptions.CancelReturnUrl),
118122

119-
ProtectedUiOptions = protectedUiOptions
123+
UiOptionsGuid = uiOptionsGuid
120124
};
121125

122126
var localizedStartAppButtonText = _localizer["StartApp_Button"];

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiPaymentApiController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using ActiveLogin.Authentication.BankId.Api;
22
using ActiveLogin.Authentication.BankId.Api.UserMessage;
33
using ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Models;
4+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
45
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
56
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
67
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
@@ -28,11 +29,12 @@ public BankIdUiPaymentApiController(
2829
IBankIdUiOrderRefProtector orderRefProtector,
2930
IBankIdQrStartStateProtector qrStartStateProtector,
3031
IBankIdUiOptionsProtector uiOptionsProtector,
32+
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
3133
IBankIdUserMessage bankIdUserMessage,
3234
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
3335
IBankIdUiResultProtector uiAuthResultProtector,
3436
IBankIdUiStateProtector bankIdUiStateProtector)
35-
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
37+
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, uiOptionsCookieManager, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
3638
{
3739
_bankIdUiStateProtector = bankIdUiStateProtector;
3840
}
@@ -44,7 +46,7 @@ public async Task<ActionResult<BankIdUiApiInitializeResponse>> Initialize(BankId
4446
Validators.ThrowIfNullOrWhitespace(request.ReturnUrl, nameof(request.ReturnUrl));
4547
Validators.ThrowIfNullOrWhitespace(request.UiOptions, nameof(request.UiOptions));
4648

47-
var uiOptions = UiOptionsProtector.Unprotect(request.UiOptions);
49+
var uiOptions = ResolveProtectedUiOptions(request.UiOptions);
4850

4951
var state = GetStateFromCookie(uiOptions);
5052
if(state == null)

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiPaymentController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
12
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
23
using ActiveLogin.Authentication.BankId.AspNetCore.StateHandling;
34
using ActiveLogin.Authentication.BankId.Core.UserMessage;
@@ -20,9 +21,10 @@ public BankIdUiPaymentController(
2021
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
2122
IBankIdUiOptionsProtector uiOptionsProtector,
2223
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
23-
IBankIdUiStateProtector bankIdUiStateProtector
24+
IBankIdUiStateProtector bankIdUiStateProtector,
25+
IBankIdUiOptionsCookieManager uiOptionsCookieManager
2426
)
25-
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector)
27+
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector, uiOptionsCookieManager)
2628
{
2729

2830
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiSignApiController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using ActiveLogin.Authentication.BankId.Api;
22
using ActiveLogin.Authentication.BankId.Api.UserMessage;
33
using ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Models;
4+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
45
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
56
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
67
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
@@ -28,11 +29,12 @@ public BankIdUiSignApiController(
2829
IBankIdUiOrderRefProtector orderRefProtector,
2930
IBankIdQrStartStateProtector qrStartStateProtector,
3031
IBankIdUiOptionsProtector uiOptionsProtector,
32+
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
3133
IBankIdUserMessage bankIdUserMessage,
3234
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
3335
IBankIdUiResultProtector uiAuthResultProtector,
3436
IBankIdUiStateProtector bankIdUiStateProtector)
35-
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
37+
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, uiOptionsCookieManager, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
3638
{
3739
_bankIdUiStateProtector = bankIdUiStateProtector;
3840
}
@@ -44,7 +46,7 @@ public async Task<ActionResult<BankIdUiApiInitializeResponse>> Initialize(BankId
4446
Validators.ThrowIfNullOrWhitespace(request.ReturnUrl, nameof(request.ReturnUrl));
4547
Validators.ThrowIfNullOrWhitespace(request.UiOptions, nameof(request.UiOptions));
4648

47-
var uiOptions = UiOptionsProtector.Unprotect(request.UiOptions);
49+
var uiOptions = ResolveProtectedUiOptions(request.UiOptions);
4850

4951
var state = GetStateFromCookie(uiOptions);
5052
if(state == null)

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Controllers/BankIdUiSignController.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
12
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
23
using ActiveLogin.Authentication.BankId.AspNetCore.StateHandling;
34
using ActiveLogin.Authentication.BankId.Core.UserMessage;
@@ -20,9 +21,10 @@ public BankIdUiSignController(
2021
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
2122
IBankIdUiOptionsProtector uiOptionsProtector,
2223
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
23-
IBankIdUiStateProtector bankIdUiStateProtector
24+
IBankIdUiStateProtector bankIdUiStateProtector,
25+
IBankIdUiOptionsCookieManager uiOptionsCookieManager
2426
)
25-
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector)
27+
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector, uiOptionsCookieManager)
2628
{
2729

2830
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Areas/ActiveLogin/Models/BankIdUiScriptInitState.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ internal BankIdUiScriptInitState()
1717
[JsonPropertyName("cancelReturnUrl")]
1818
public string CancelReturnUrl { get; init; } = string.Empty;
1919

20-
[JsonPropertyName("protectedUiOptions")]
21-
public string ProtectedUiOptions { get; init; } = string.Empty;
20+
[JsonPropertyName("uiOptionsGuid")]
21+
public string UiOptionsGuid { get; init; } = string.Empty;
2222
}

0 commit comments

Comments
 (0)