-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathIDialogTokenGenerator.cs
130 lines (112 loc) · 5.16 KB
/
IDialogTokenGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System.Globalization;
using System.Text;
using Digdir.Domain.Dialogporten.Application.Common.Extensions;
using Digdir.Domain.Dialogporten.Application.Externals.AltinnAuthorization;
using Digdir.Domain.Dialogporten.Application.Externals.Presentation;
using Digdir.Domain.Dialogporten.Domain.Dialogs.Entities;
using Digdir.Domain.Dialogporten.Domain.Parties;
using Microsoft.Extensions.Options;
namespace Digdir.Domain.Dialogporten.Application.Common;
public interface IDialogTokenGenerator
{
string GetDialogToken(DialogEntity dialog, DialogDetailsAuthorizationResult authorizationResult, string issuerVersion);
}
internal sealed class DialogTokenGenerator : IDialogTokenGenerator
{
private readonly ApplicationSettings _applicationSettings;
private readonly IUser _user;
private readonly IClock _clock;
private readonly ICompactJwsGenerator _compactJwsGenerator;
// Keep the lifetime semi-short to reduce the risk of token misuse
// after rights revocation, whilst still making it possible for the
// user to idle a reasonable amount of time before committing to an action.
//
// End user systems should make sure to re-request the dialog, upon
// which a new token will be issued based on current authorization data.
private readonly TimeSpan _tokenLifetime = TimeSpan.FromMinutes(10);
public DialogTokenGenerator(
IOptions<ApplicationSettings> applicationSettings,
IUser user,
IClock clock,
ICompactJwsGenerator compactJwsGenerator)
{
_applicationSettings = applicationSettings.Value ?? throw new ArgumentNullException(nameof(applicationSettings));
_user = user ?? throw new ArgumentNullException(nameof(user));
_clock = clock ?? throw new ArgumentNullException(nameof(clock));
_compactJwsGenerator = compactJwsGenerator ?? throw new ArgumentNullException(nameof(compactJwsGenerator));
}
public string GetDialogToken(DialogEntity dialog, DialogDetailsAuthorizationResult authorizationResult, string issuerVersion)
{
var claimsPrincipal = _user.GetPrincipal();
var now = _clock.UtcNowOffset.ToUnixTimeSeconds();
var claims = new Dictionary<string, object?>
{
{ DialogTokenClaimTypes.JwtId, Guid.NewGuid() },
{ DialogTokenClaimTypes.AuthenticatedParty, GetAuthenticatedParty() },
{ DialogTokenClaimTypes.AuthenticationLevel,
claimsPrincipal.TryGetAuthenticationLevel(out var authenticationLevel)
? authenticationLevel.Value
: 0 },
{ DialogTokenClaimTypes.DialogParty, dialog.Party },
{ DialogTokenClaimTypes.ServiceResource, dialog.ServiceResource },
{ DialogTokenClaimTypes.DialogId, dialog.Id },
{ DialogTokenClaimTypes.Actions, GetAuthorizedActions(authorizationResult) },
{ DialogTokenClaimTypes.Issuer, _applicationSettings.Dialogporten.BaseUri.AbsoluteUri.TrimEnd('/') + issuerVersion },
{ DialogTokenClaimTypes.IssuedAt, now },
{ DialogTokenClaimTypes.NotBefore, now },
{ DialogTokenClaimTypes.Expires, now + (long)_tokenLifetime.TotalSeconds }
};
if (claimsPrincipal.TryGetSupplierOrgNumber(out var supplierOrgNumber))
{
claims.Add(DialogTokenClaimTypes.SupplierParty, NorwegianOrganizationIdentifier.PrefixWithSeparator + supplierOrgNumber);
}
return _compactJwsGenerator.GetCompactJws(claims);
}
private static string GetAuthorizedActions(DialogDetailsAuthorizationResult authorizationResult)
{
if (authorizationResult.AuthorizedAltinnActions.Count == 0)
{
return string.Empty;
}
var actions = new StringBuilder();
foreach (var (action, resource) in authorizationResult.AuthorizedAltinnActions)
{
actions.Append(action);
if (resource != Authorization.Constants.MainResource)
{
actions.Append(CultureInfo.InvariantCulture, $",{resource}");
}
actions.Append(';');
}
// Remove trailing semicolon
actions.Remove(actions.Length - 1, 1);
return actions.ToString();
}
private string GetAuthenticatedParty()
{
if (_user.TryGetPid(out var pid))
{
return NorwegianPersonIdentifier.PrefixWithSeparator + pid;
}
if (_user.TryGetOrganizationNumber(out var orgNumber))
{
return NorwegianOrganizationIdentifier.PrefixWithSeparator + orgNumber;
}
throw new InvalidOperationException("User must have either pid or org number");
}
}
public static class DialogTokenClaimTypes
{
public const string JwtId = "jti";
public const string Issuer = "iss";
public const string IssuedAt = "iat";
public const string NotBefore = "nbf";
public const string Expires = "exp";
public const string AuthenticationLevel = "l";
public const string AuthenticatedParty = "c";
public const string DialogParty = "p";
public const string SupplierParty = "u";
public const string ServiceResource = "s";
public const string DialogId = "i";
public const string Actions = "a";
}