Skip to content

Commit 967a017

Browse files
authored
Merge pull request #475 from ActiveLogin/feature/459-personalidentitynumber-requirement
Set requirements on how the authentication or signing order must be performed dynamically
2 parents fe7939e + 4dcac3c commit 967a017

15 files changed

Lines changed: 222 additions & 8 deletions

File tree

docs/articles/bankid.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ The most common scenbario is to use Active Login for BankID auth/login, so most
3939
+ [Event listeners](#event-listeners)
4040
+ [Store data on auth completion](#store-data-on-auth-completion)
4141
+ [Resolve the end user ip](#resolve-the-end-user-ip)
42+
+ [Resolve requirements on Auth request](#resolve-requirements-on-auth-request)
4243
+ [Resolve user data on Auth request](#resolve-user-data-on-auth-request)
4344
+ [Custom QR code generation](#custom-qr-code-generation)
4445
+ [Custom browser detection and launch info](#custom-browser-detection-and-launch-info)
@@ -359,6 +360,10 @@ public class SignController : Controller
359360
{"returnUrl", "~/"},
360361
{"scheme", provider}
361362
}
363+
364+
RequirePinCode = true,
365+
RequireMrtd = true
366+
RequiredPersonalIdentityNumber = new PersonalIdentityNumber(1999, 8, 7, 239, 1)
362367
};
363368
var returnPath = $"{Url.Action(nameof(Callback))}?provider={provider}";
364369
return this.BankIdInitiateSign(props, returnPath, provider);
@@ -446,7 +451,7 @@ services
446451

447452
### Customizing BankID options
448453

449-
BankId options allows you to set and override some options such as these.
454+
BankId options allows you to set and override some options such as the below requirements on how the authentication or signature order must be performed.
450455

451456
```csharp
452457
.AddOtherDevice(options =>
@@ -478,6 +483,7 @@ If you want to apply some options for all BankID schemes, you can do so by using
478483
});
479484
```
480485

486+
Requirements can also be set dynamically for each authentication, see section [Resolve requirements on Auth request](#resolve-requirements-on-auth-request). To use dynamic requirements with signatures provide the requirements as part the `BankIdSignProperties`, see section [Sign](#sign).
481487

482488
---
483489

@@ -970,6 +976,29 @@ Either register a class implementing `IBankIdEndUserIpResolver`:
970976
services.AddTransient<IBankIdEndUserIpResolver, EndUserIpResolver>();
971977
```
972978

979+
### Resolve requirements on Auth request
980+
981+
If you want to set the requirements on how the authentication order must be performed dynamically for each order instead of statically during startup in `Program.cs`, it can be done by overriding the default implementation of the `IBankIdAuthRequestRequirementsResolver`.
982+
983+
```csharp
984+
public class BankIdAuthRequestDynamicRequirementsResolver : IBankIdAuthRequestRequirementsResolver
985+
{
986+
public Task<BankIdAuthRequirements> GetRequirementsAsync()
987+
{
988+
return Task.FromResult(new BankIdAuthRequirements()
989+
{
990+
RequireMrtd = true,
991+
RequirePinCode = true,
992+
RequiredPersonalIdentityNumber = new PersonalIdentityNumber(1999, 8, 7, 239, 1)
993+
});
994+
}
995+
}
996+
```
997+
998+
```csharp
999+
services.AddTransient<IBankIdAuthRequestRequirementsResolver, BankIdAuthRequestDynamicRequirementsResolver>();
1000+
```
1001+
9731002
### Resolve user data on Auth request
9741003

9751004
BankID allows you to display a text during authentication to describe the intent. Active Login allows you to set these parameters when authenticating:

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "8.0.403",
3+
"version": "8.0.404",
44
"rollForward": "latestFeature"
55
}
66
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ public async Task<ActionResult<BankIdUiApiInitializeResponse>> Initialize(BankId
6767
{
6868
Items = state.BankIdSignProperties.Items,
6969
UserNonVisibleData = state.BankIdSignProperties.UserNonVisibleData,
70-
UserVisibleDataFormat = state.BankIdSignProperties.UserVisibleDataFormat
70+
UserVisibleDataFormat = state.BankIdSignProperties.UserVisibleDataFormat,
71+
RequiredPersonalIdentityNumber = state.BankIdSignProperties.RequiredPersonalIdentityNumber,
72+
RequireMrtd = state.BankIdSignProperties.RequireMrtd,
73+
RequirePinCode = state.BankIdSignProperties.RequirePinCode,
7174
},
7275
returnRedirectUrl);
7376
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Auth/AuthenticationBuilderBankIdExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using ActiveLogin.Authentication.BankId.AspNetCore.ClaimsTransformation;
33
using ActiveLogin.Authentication.BankId.AspNetCore.DataProtection;
44
using ActiveLogin.Authentication.BankId.Core;
5+
using ActiveLogin.Authentication.BankId.Core.Requirements;
56
using ActiveLogin.Authentication.BankId.Core.UserData;
67

78
using Microsoft.AspNetCore.Authentication;
@@ -77,5 +78,6 @@ private static void AddBankIdAuthDefaultServices(IBankIdAuthBuilder builder)
7778
builder.AddClaimsTransformer<BankIdDefaultClaimsTransformer>();
7879

7980
builder.UseAuthRequestUserDataResolver<BankIdAuthRequestEmptyUserDataResolver>();
81+
builder.UseAuthRequestRequirementsResolver<BankIdAuthRequestEmptyRequirementsResolver>();
8082
}
8183
}

src/ActiveLogin.Authentication.BankId.AspNetCore/Auth/IBankIdAuthBuilderExtensions.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ActiveLogin.Authentication.BankId.AspNetCore.ClaimsTransformation;
2+
using ActiveLogin.Authentication.BankId.Core.Requirements;
23
using ActiveLogin.Authentication.BankId.Core.UserData;
34

45
using Microsoft.Extensions.DependencyInjection;
@@ -61,6 +62,19 @@ public static IBankIdAuthBuilder UseAuthRequestUserDataResolver<TBankIdAuthReque
6162
return builder;
6263
}
6364

65+
/// <summary>
66+
/// Use a custom requirements resolver.
67+
/// </summary>
68+
/// <typeparam name="TBankIdAuthRequestRequirementsResolverImplementation"></typeparam>
69+
/// <param name="builder"></param>
70+
/// <returns></returns>
71+
public static IBankIdAuthBuilder UseAuthRequestRequirementsResolver<TBankIdAuthRequestRequirementsResolverImplementation>(this IBankIdAuthBuilder builder) where TBankIdAuthRequestRequirementsResolverImplementation : class, IBankIdAuthRequestRequirementsResolver
72+
{
73+
builder.Services.AddTransient<IBankIdAuthRequestRequirementsResolver, TBankIdAuthRequestRequirementsResolverImplementation>();
74+
75+
return builder;
76+
}
77+
6478

6579
/// <summary>
6680
/// Configures options that will apply to all BankID schemes.

src/ActiveLogin.Authentication.BankId.AspNetCore/DataProtection/Serialization/BankIdUiStateSerializer.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using ActiveLogin.Authentication.BankId.AspNetCore.Auth;
22
using ActiveLogin.Authentication.BankId.AspNetCore.Models;
33
using ActiveLogin.Authentication.BankId.AspNetCore.Sign;
4+
using ActiveLogin.Identity.Swedish;
45

56
using Microsoft.AspNetCore.Authentication;
67

@@ -31,6 +32,15 @@ protected override void Write(BinaryWriter writer, BankIdUiState model)
3132
writer.Write(signState.BankIdSignProperties.UserNonVisibleData?.Length ?? -1);
3233
writer.Write(signState.BankIdSignProperties.UserNonVisibleData ?? Array.Empty<byte>());
3334

35+
writer.Write(signState.BankIdSignProperties.RequiredPersonalIdentityNumber == null);
36+
writer.Write(signState.BankIdSignProperties.RequiredPersonalIdentityNumber?.To12DigitString() ?? string.Empty);
37+
38+
writer.Write(signState.BankIdSignProperties.RequireMrtd == null);
39+
writer.Write(signState.BankIdSignProperties.RequireMrtd.GetValueOrDefault());
40+
41+
writer.Write(signState.BankIdSignProperties.RequirePinCode == null);
42+
writer.Write(signState.BankIdSignProperties.RequirePinCode.GetValueOrDefault());
43+
3444
writer.Write(signState.BankIdSignProperties.Items.Count);
3545
foreach (var item in signState.BankIdSignProperties.Items)
3646
{
@@ -75,6 +85,20 @@ protected override BankIdUiState Read(BinaryReader reader)
7585
{
7686
userNonVisibleData = null;
7787
}
88+
89+
var requiredPersonalIdentityNumberIsNull = reader.ReadBoolean();
90+
var requiredPersonalIdentityNumber = reader.ReadString();
91+
if (requiredPersonalIdentityNumberIsNull)
92+
{
93+
requiredPersonalIdentityNumber = null;
94+
}
95+
96+
var requireMrtdIsNull = reader.ReadBoolean();
97+
var requireMrtd = reader.ReadBoolean();
98+
99+
var requirePinCodeIsNull = reader.ReadBoolean();
100+
var requirePinCode = reader.ReadBoolean();
101+
78102
var count = reader.ReadInt32();
79103
var items = new Dictionary<string, string?>(count);
80104

@@ -89,7 +113,9 @@ protected override BankIdUiState Read(BinaryReader reader)
89113
{
90114
UserVisibleDataFormat = userVisibleDataFormat,
91115
UserNonVisibleData = userNonVisibleData,
92-
116+
RequiredPersonalIdentityNumber = requiredPersonalIdentityNumber != null ? PersonalIdentityNumber.Parse(requiredPersonalIdentityNumber) : null,
117+
RequireMrtd = requireMrtdIsNull ? null : requireMrtd,
118+
RequirePinCode = requirePinCodeIsNull ? null : requirePinCode,
93119
Items = items
94120
};
95121
return new BankIdUiSignState(configKey, bankIdSignProperties);

src/ActiveLogin.Authentication.BankId.AspNetCore/Sign/BankIdSignProperties.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using ActiveLogin.Identity.Swedish;
2+
13
namespace ActiveLogin.Authentication.BankId.AspNetCore.Sign;
24

35
public class BankIdSignProperties
@@ -33,6 +35,7 @@ public BankIdSignProperties(string userVisibleData)
3335
/// there is something wrong about the identification and avoid attempted frauds.
3436
/// </summary>
3537
public string UserVisibleData { get; set; }
38+
3639
/// <summary>
3740
/// If present, and set to "simpleMarkdownV1", this parameter indicates that userVisibleData holds formatting characters which, if used correctly, will make the text displayed with the user nicer to look at.
3841
/// For further information of formatting options, please study the document Guidelines for Formatted Text.
@@ -44,6 +47,24 @@ public BankIdSignProperties(string userVisibleData)
4447
/// </summary>
4548
public byte[]? UserNonVisibleData { get; set; }
4649

50+
/// <summary>
51+
/// The personal identity number allowed to confirm the sign request.
52+
/// If a BankID with another personal identity number attempts to confirm the sign request, it will fail.
53+
/// If left empty any personal identity number will be allowed.
54+
/// </summary>
55+
public PersonalIdentityNumber? RequiredPersonalIdentityNumber { get; set; }
56+
57+
/// <summary>
58+
/// Whether the user needs to confirm their identity with a valid Swedish passport or national ID card to complete the order.
59+
/// No identity confirmation is required by default.
60+
/// </summary>
61+
public bool? RequireMrtd { get; set; }
62+
63+
/// <summary>
64+
/// Users are required to confirm the order with their security code even if they have biometrics activated.
65+
/// </summary>
66+
public bool? RequirePinCode { get; set; }
67+
4768
/// <summary>
4869
/// A collection of items where you can store state that will be provided once the sign flow is done.
4970
/// </summary>

src/ActiveLogin.Authentication.BankId.Core/Flow/BankIdFlowService.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using ActiveLogin.Authentication.BankId.Core.Launcher;
88
using ActiveLogin.Authentication.BankId.Core.Models;
99
using ActiveLogin.Authentication.BankId.Core.Qr;
10+
using ActiveLogin.Authentication.BankId.Core.Requirements;
1011
using ActiveLogin.Authentication.BankId.Core.SupportedDevice;
1112
using ActiveLogin.Authentication.BankId.Core.UserContext;
1213
using ActiveLogin.Authentication.BankId.Core.UserData;
@@ -26,6 +27,7 @@ public class BankIdFlowService : IBankIdFlowService
2627
private readonly IBankIdSupportedDeviceDetector _bankIdSupportedDeviceDetector;
2728
private readonly IBankIdEndUserIpResolver _bankIdEndUserIpResolver;
2829
private readonly IBankIdAuthRequestUserDataResolver _bankIdAuthUserDataResolver;
30+
private readonly IBankIdAuthRequestRequirementsResolver _bankIdAuthRequestRequirementsResolver;
2931
private readonly IBankIdQrCodeGenerator _bankIdQrCodeGenerator;
3032
private readonly IBankIdLauncher _bankIdLauncher;
3133
private readonly IBankIdCertificatePolicyResolver _bankIdCertificatePolicyResolver;
@@ -39,6 +41,7 @@ public BankIdFlowService(
3941
IBankIdSupportedDeviceDetector bankIdSupportedDeviceDetector,
4042
IBankIdEndUserIpResolver bankIdEndUserIpResolver,
4143
IBankIdAuthRequestUserDataResolver bankIdAuthUserDataResolver,
44+
IBankIdAuthRequestRequirementsResolver bankIdAuthRequestRequirementsResolver,
4245
IBankIdQrCodeGenerator bankIdQrCodeGenerator,
4346
IBankIdLauncher bankIdLauncher,
4447
IBankIdCertificatePolicyResolver bankIdCertificatePolicyResolver
@@ -52,6 +55,7 @@ IBankIdCertificatePolicyResolver bankIdCertificatePolicyResolver
5255
_bankIdSupportedDeviceDetector = bankIdSupportedDeviceDetector;
5356
_bankIdEndUserIpResolver = bankIdEndUserIpResolver;
5457
_bankIdAuthUserDataResolver = bankIdAuthUserDataResolver;
58+
_bankIdAuthRequestRequirementsResolver = bankIdAuthRequestRequirementsResolver;
5559
_bankIdQrCodeGenerator = bankIdQrCodeGenerator;
5660
_bankIdLauncher = bankIdLauncher;
5761
_bankIdCertificatePolicyResolver = bankIdCertificatePolicyResolver;
@@ -102,14 +106,18 @@ private async Task<AuthRequest> GetAuthRequest(BankIdFlowOptions flowOptions)
102106
var resolvedCertificatePolicies = GetResolvedCertificatePolicies(flowOptions);
103107
var resolvedRiskLevel = flowOptions.AllowedRiskLevel == Risk.BankIdAllowedRiskLevel.NoRiskLevel ? null : flowOptions.AllowedRiskLevel.ToString().ToLower();
104108

105-
var authRequestRequirement = new Requirement(resolvedCertificatePolicies, resolvedRiskLevel, flowOptions.RequirePinCode, flowOptions.RequireMrtd);
109+
var resolvedRequirements = await _bankIdAuthRequestRequirementsResolver.GetRequirementsAsync();
110+
var requiredPersonalIdentityNumber = resolvedRequirements.RequiredPersonalIdentityNumber ?? flowOptions.RequiredPersonalIdentityNumber;
111+
var requireMrtd = resolvedRequirements.RequireMrtd ?? flowOptions.RequireMrtd;
112+
var requirePinCode = resolvedRequirements.RequirePinCode ?? flowOptions.RequirePinCode;
113+
var requestRequirement = new Requirement(resolvedCertificatePolicies, resolvedRiskLevel, requirePinCode, requireMrtd, requiredPersonalIdentityNumber?.To12DigitString());
106114

107-
var authRequestContext = new BankIdAuthRequestContext(endUserIp, authRequestRequirement);
115+
var authRequestContext = new BankIdAuthRequestContext(endUserIp, requestRequirement);
108116
var userData = await _bankIdAuthUserDataResolver.GetUserDataAsync(authRequestContext);
109117

110118
return new AuthRequest(
111119
endUserIp,
112-
authRequestRequirement,
120+
requestRequirement,
113121
userData.UserVisibleData,
114122
userData.UserNonVisibleData,
115123
userData.UserVisibleDataFormat
@@ -161,7 +169,10 @@ private SignRequest GetSignRequest(BankIdFlowOptions flowOptions, BankIdSignData
161169
var resolvedCertificatePolicies = GetResolvedCertificatePolicies(flowOptions);
162170
var resolvedRiskLevel = flowOptions.AllowedRiskLevel == Risk.BankIdAllowedRiskLevel.NoRiskLevel ? null : flowOptions.AllowedRiskLevel.ToString().ToLower();
163171

164-
var requestRequirement = new Requirement(resolvedCertificatePolicies, resolvedRiskLevel, flowOptions.RequirePinCode, flowOptions.RequireMrtd, flowOptions.RequiredPersonalIdentityNumber?.To12DigitString());
172+
var requiredPersonalIdentityNumber = bankIdSignData.RequiredPersonalIdentityNumber ?? flowOptions.RequiredPersonalIdentityNumber;
173+
var requireMrtd = bankIdSignData.RequireMrtd ?? flowOptions.RequireMrtd;
174+
var requirePinCode = bankIdSignData.RequirePinCode ?? flowOptions.RequirePinCode;
175+
var requestRequirement = new Requirement(resolvedCertificatePolicies, resolvedRiskLevel, requirePinCode, requireMrtd, requiredPersonalIdentityNumber?.To12DigitString());
165176

166177
return new SignRequest(
167178
endUserIp,

src/ActiveLogin.Authentication.BankId.Core/Models/BankIdSignData.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using ActiveLogin.Identity.Swedish;
2+
13
namespace ActiveLogin.Authentication.BankId.Core.Models;
24

35
public class BankIdSignData
@@ -12,5 +14,9 @@ public BankIdSignData(string userVisibleData)
1214

1315
public byte[]? UserNonVisibleData { get; set; }
1416

17+
public PersonalIdentityNumber? RequiredPersonalIdentityNumber { get; set; }
18+
public bool? RequireMrtd { get; set; }
19+
public bool? RequirePinCode { get; set; }
20+
1521
public IDictionary<string, string?> Items { get; set; } = new Dictionary<string, string?>();
1622
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace ActiveLogin.Authentication.BankId.Core.Requirements;
2+
3+
public class BankIdAuthRequestEmptyRequirementsResolver : IBankIdAuthRequestRequirementsResolver
4+
{
5+
public static readonly BankIdAuthRequirements EmptyAuthRequirements = new();
6+
7+
public Task<BankIdAuthRequirements> GetRequirementsAsync()
8+
{
9+
return Task.FromResult(EmptyAuthRequirements);
10+
}
11+
}

0 commit comments

Comments
 (0)