Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"markdownlint.config": {
"MD033": {
"allowed_elements": ["a", "img"]
}
}
}
352 changes: 197 additions & 155 deletions docs/articles/bankid.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion samples/Standalone.MvcSample/Standalone.MvcSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.23.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.2" />
<PackageReference Include="ActiveLogin.Identity.Swedish" Version="3.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
using ActiveLogin.Authentication.BankId.AspNetCore.Helpers;
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
using ActiveLogin.Authentication.BankId.Core;
using ActiveLogin.Authentication.BankId.Core.Flow;
using ActiveLogin.Authentication.BankId.Core.Models;
using ActiveLogin.Authentication.BankId.Core.UserMessage;

using Microsoft.AspNetCore.Http;
Expand All @@ -18,43 +20,29 @@
namespace ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Controllers;

[NonController]
public abstract class BankIdUiApiControllerBase : ControllerBase
public abstract class BankIdUiApiControllerBase(
IBankIdFlowService bankIdFlowService,
IBankIdDataStateProtector<BankIdUiOrderRef> orderRefProtector,
IBankIdDataStateProtector<BankIdQrStartState> qrStartStateProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,

IBankIdUserMessage bankIdUserMessage,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdDataStateProtector<BankIdUiResult> uiAuthResultProtector,
IStateStorage stateStorage
) : ControllerBase
{
private static JsonSerializerOptions JsonSerializerOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

protected readonly IBankIdFlowService BankIdFlowService;
protected readonly IBankIdUiOrderRefProtector OrderRefProtector;
protected readonly IBankIdQrStartStateProtector QrStartStateProtector;
protected readonly IBankIdUiOptionsProtector UiOptionsProtector;
protected readonly IBankIdUiOptionsCookieManager UiOptionsCookieManager;
protected readonly IBankIdFlowService BankIdFlowService = bankIdFlowService;
protected readonly IBankIdDataStateProtector<BankIdUiOrderRef> OrderRefProtector = orderRefProtector;
protected readonly IBankIdDataStateProtector<BankIdQrStartState> QrStartStateProtector = qrStartStateProtector;
protected readonly IStateStorage _stateStorage = stateStorage;
protected readonly IBankIdUiOptionsCookieManager UiOptionsCookieManager = uiOptionsCookieManager;

private readonly IBankIdUserMessage _bankIdUserMessage;
private readonly IBankIdUserMessageLocalizer _bankIdUserMessageLocalizer;
private readonly IBankIdUiResultProtector _uiAuthResultProtector;

protected BankIdUiApiControllerBase(
IBankIdFlowService bankIdFlowService,
IBankIdUiOrderRefProtector orderRefProtector,
IBankIdQrStartStateProtector qrStartStateProtector,
IBankIdUiOptionsProtector uiOptionsProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,

IBankIdUserMessage bankIdUserMessage,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdUiResultProtector uiAuthResultProtector

)
{
BankIdFlowService = bankIdFlowService;
OrderRefProtector = orderRefProtector;
QrStartStateProtector = qrStartStateProtector;
UiOptionsProtector = uiOptionsProtector;
UiOptionsCookieManager = uiOptionsCookieManager;

_bankIdUserMessage = bankIdUserMessage;
_bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
_uiAuthResultProtector = uiAuthResultProtector;
}
private readonly IBankIdUserMessage _bankIdUserMessage = bankIdUserMessage;
private readonly IBankIdUserMessageLocalizer _bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
private readonly IBankIdDataStateProtector<BankIdUiResult> _uiAuthResultProtector = uiAuthResultProtector;

[ValidateAntiForgeryToken]
[HttpPost(BankIdConstants.Routes.BankIdApiStatusActionName)]
Expand Down Expand Up @@ -83,7 +71,7 @@ public async Task<ActionResult> Status(BankIdUiApiStatusRequest request)
return BadRequestJsonResult(new BankIdUiApiErrorResponse(errorStatusMessage));
}

switch(result)
switch (result)
{
case BankIdFlowCollectResultPending pending:
{
Expand Down Expand Up @@ -196,4 +184,18 @@ protected BankIdUiOptions ResolveProtectedUiOptions(string protectedUiOptionsOrG
return UiOptionsCookieManager.Retrieve(protectedUiOptionsOrGuid)
?? throw new InvalidOperationException(BankIdConstants.ErrorMessages.InvalidUiOptions);
}

protected async ValueTask<T?> GetState<T>(BankIdUiOptions uiOptions)
where T : BankIdUiState
{
var cookie = Request.Cookies[uiOptions.StateKeyCookieName];
if (cookie == null)
{
return null;
}

var stateKey = new StateKey(cookie);
return await _stateStorage.GetAsync<T>(stateKey);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
using ActiveLogin.Authentication.BankId.Core.Flow;
using ActiveLogin.Authentication.BankId.Core.UserMessage;

using ActiveLogin.Authentication.BankId.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

Expand All @@ -18,21 +18,17 @@ namespace ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Control
[ApiController]
[AllowAnonymous]
[NonController]
public class BankIdUiAuthApiController : BankIdUiApiControllerBase
public class BankIdUiAuthApiController(
IBankIdFlowService bankIdFlowService,
IBankIdDataStateProtector<BankIdUiOrderRef> orderRefProtector,
IBankIdDataStateProtector<Core.Models.BankIdQrStartState> qrStartStateProtector,
IBankIdUserMessage bankIdUserMessage,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdDataStateProtector<BankIdUiResult> uiAuthResultProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
IStateStorage stateStorage
) : BankIdUiApiControllerBase(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsCookieManager, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector, stateStorage)
{
public BankIdUiAuthApiController(
IBankIdFlowService bankIdFlowService,
IBankIdUiOrderRefProtector orderRefProtector,
IBankIdQrStartStateProtector qrStartStateProtector,
IBankIdUiOptionsProtector uiOptionsProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
IBankIdUserMessage bankIdUserMessage,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdUiResultProtector uiAuthResultProtector)
: base(bankIdFlowService, orderRefProtector, qrStartStateProtector, uiOptionsProtector, uiOptionsCookieManager, bankIdUserMessage, bankIdUserMessageLocalizer, uiAuthResultProtector)
{
}

[ValidateAntiForgeryToken]
[HttpPost(BankIdConstants.Routes.BankIdApiInitializeActionName)]
public async Task<ActionResult<BankIdUiApiInitializeResponse>> Initialize(BankIdUiApiInitializeRequest request)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using ActiveLogin.Authentication.BankId.AspNetCore.Auth;
using ActiveLogin.Authentication.BankId.AspNetCore.Cookies;
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
using ActiveLogin.Authentication.BankId.AspNetCore.StateHandling;
using ActiveLogin.Authentication.BankId.Core;
using ActiveLogin.Authentication.BankId.Core.UserMessage;

using Microsoft.AspNetCore.Antiforgery;
Expand All @@ -13,22 +14,15 @@ namespace ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Control
[Area(BankIdConstants.Routes.ActiveLoginAreaName)]
[AllowAnonymous]
[NonController]
public class BankIdUiAuthController : BankIdUiControllerBase
public class BankIdUiAuthController(
IAntiforgery antiforgery,
IStringLocalizer<ActiveLoginResources> localizer,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
IStateStorage stateStorage
) : BankIdUiControllerBase<BankIdUiAuthState>(antiforgery, localizer, bankIdUserMessageLocalizer, bankIdInvalidStateHandler, uiOptionsCookieManager, stateStorage)
{
public BankIdUiAuthController(
IAntiforgery antiforgery,
IStringLocalizer<ActiveLoginResources> localizer,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdUiOptionsProtector uiOptionsProtector,
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
IBankIdUiStateProtector bankIdUiStateProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager
)
: base(antiforgery, localizer, bankIdUserMessageLocalizer, uiOptionsProtector, bankIdInvalidStateHandler, bankIdUiStateProtector, uiOptionsCookieManager)
{

}

[HttpGet]
[Route($"/[area]/{BankIdConstants.Routes.BankIdPathName}/{BankIdConstants.Routes.BankIdAuthControllerPath}")]
public Task<ActionResult> Init(string returnUrl, [FromQuery(Name = BankIdConstants.QueryStringParameters.UiOptions)] string uiOptionsGuid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using ActiveLogin.Authentication.BankId.AspNetCore.Payment;
using ActiveLogin.Authentication.BankId.AspNetCore.Sign;
using ActiveLogin.Authentication.BankId.AspNetCore.StateHandling;
using ActiveLogin.Authentication.BankId.Core;
using ActiveLogin.Authentication.BankId.Core.UserMessage;

using Microsoft.AspNetCore.Antiforgery;
Expand All @@ -16,32 +17,32 @@
namespace ActiveLogin.Authentication.BankId.AspNetCore.Areas.ActiveLogin.Controllers;

[NonController]
public abstract class BankIdUiControllerBase : Controller
public abstract class BankIdUiControllerBase<T>(
IAntiforgery antiforgery,
IStringLocalizer<ActiveLoginResources> localizer,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
IBankIdUiOptionsCookieManager uiOptionsCookieManager,
IStateStorage stateStorage
) : Controller
where T : BankIdUiState
{
private readonly IAntiforgery _antiforgery;
private readonly IStringLocalizer<ActiveLoginResources> _localizer;
private readonly IBankIdUserMessageLocalizer _bankIdUserMessageLocalizer;
private readonly IBankIdUiOptionsProtector _uiOptionsProtector;
private readonly IBankIdInvalidStateHandler _bankIdInvalidStateHandler;
private readonly IBankIdUiStateProtector _bankIdUiStateProtector;
private readonly IBankIdUiOptionsCookieManager _uiOptionsCookieManager;

protected BankIdUiControllerBase(
IAntiforgery antiforgery,
IStringLocalizer<ActiveLoginResources> localizer,
IBankIdUserMessageLocalizer bankIdUserMessageLocalizer,
IBankIdUiOptionsProtector uiOptionsProtector,
IBankIdInvalidStateHandler bankIdInvalidStateHandler,
IBankIdUiStateProtector bankIdUiStateProtector,
IBankIdUiOptionsCookieManager uiOptionsCookieManager)
private readonly IAntiforgery _antiforgery = antiforgery;
private readonly IStringLocalizer<ActiveLoginResources> _localizer = localizer;
private readonly IBankIdUserMessageLocalizer _bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
private readonly IBankIdInvalidStateHandler _bankIdInvalidStateHandler = bankIdInvalidStateHandler;
private readonly IBankIdUiOptionsCookieManager _uiOptionsCookieManager = uiOptionsCookieManager;
private readonly IStateStorage stateStorage = stateStorage;

protected Task<T?> GetUIState(BankIdUiOptions uiOptions)
{
_antiforgery = antiforgery;
_localizer = localizer;
_bankIdUserMessageLocalizer = bankIdUserMessageLocalizer;
_uiOptionsProtector = uiOptionsProtector;
_bankIdInvalidStateHandler = bankIdInvalidStateHandler;
_bankIdUiStateProtector = bankIdUiStateProtector;
_uiOptionsCookieManager = uiOptionsCookieManager;
var cookie = HttpContext.Request.Cookies[uiOptions.StateKeyCookieName];
if (cookie is null)
{
return Task.FromResult<T?>(default);
}
var stateKey = new StateKey(cookie);
return stateStorage.GetAsync<T>(stateKey);
}

protected async Task<ActionResult> Initialize(string returnUrl, string apiControllerName, string uiOptionsGuid, string viewName)
Expand All @@ -63,32 +64,40 @@ protected async Task<ActionResult> Initialize(string returnUrl, string apiContro
return new EmptyResult();
}

var antiforgeryTokens = _antiforgery.GetAndStoreTokens(HttpContext);
var state = await GetUIState(uiOptions);

var protectedState = Request.Cookies[uiOptions.StateCookieName];
if(protectedState == null)
if (state == null)
{
var invalidStateContext = new BankIdInvalidStateContext(uiOptions.CancelReturnUrl);
await _bankIdInvalidStateHandler.HandleAsync(invalidStateContext);

return new EmptyResult();
}
var state = _bankIdUiStateProtector.Unprotect(protectedState);

var antiforgeryTokens = _antiforgery.GetAndStoreTokens(HttpContext);
var viewModel = GetUiViewModel(returnUrl, apiControllerName, uiOptionsGuid, uiOptions, state, antiforgeryTokens);

return View(viewName, viewModel);
}

private bool HasStateCookie(BankIdUiOptions uiOptions)
{
if (string.IsNullOrEmpty(uiOptions.StateCookieName)
|| !HttpContext.Request.Cookies.ContainsKey(uiOptions.StateCookieName))
if (string.IsNullOrEmpty(uiOptions.StateKeyCookieName))
{
return false;
}

if (!HttpContext.Request.Cookies.ContainsKey(uiOptions.StateKeyCookieName))
{
return false;
}

if (string.IsNullOrEmpty(HttpContext.Request.Cookies[uiOptions.StateKeyCookieName]))
{
return false;
}

return !string.IsNullOrEmpty(HttpContext.Request.Cookies[uiOptions.StateCookieName]);
return true;
}

private BankIdUiViewModel GetUiViewModel(string returnUrl, string apiControllerName, string uiOptionsGuid, BankIdUiOptions unprotectedUiOptions, BankIdUiState uiState, AntiforgeryTokenSet antiforgeryTokens)
Expand Down Expand Up @@ -127,7 +136,7 @@ private BankIdUiViewModel GetUiViewModel(string returnUrl, string apiControllerN
var localizedCancelButtonText = _localizer["Cancel_Button"];
var localizedQrCodeImageAltText = _localizer["Qr_Code_Image"];

if(uiState is BankIdUiSignState signState)
if (uiState is BankIdUiSignState signState)
{
var uiSignData = new BankIdUiSignData
{
Expand Down
Loading
Loading