tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
TokenFactory.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Diagnostics.CodeAnalysis;
4using System.Globalization;
5using System.IdentityModel.Tokens.Jwt;
6using System.Linq;
7using System.Security.Claims;
8
9using Microsoft.Extensions.Options;
10using Microsoft.IdentityModel.Tokens;
11
16
18{
21 {
23 public TokenValidationParameters ValidationParameters { get; }
24
26 public ReadOnlySpan<byte> SigningKeyBytes
27 {
28 get => signingKey.Key;
29 [MemberNotNull(nameof(signingKey))]
30 [MemberNotNull(nameof(tokenHeader))]
31 set
32 {
33 signingKey = new SymmetricSecurityKey(value.ToArray());
34 tokenHeader = new JwtHeader(
35 new SigningCredentials(
37 SecurityAlgorithms.HmacSha256));
38 }
39 }
40
45
49 readonly JwtSecurityTokenHandler tokenHandler;
50
54 SymmetricSecurityKey signingKey;
55
59 JwtHeader tokenHeader;
60
68 ICryptographySuite cryptographySuite,
69 IAssemblyInformationProvider assemblyInformationProvider,
70 IOptions<SecurityConfiguration> securityConfigurationOptions)
71 {
72 ArgumentNullException.ThrowIfNull(cryptographySuite);
73 ArgumentNullException.ThrowIfNull(assemblyInformationProvider);
74
75 securityConfiguration = securityConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(securityConfigurationOptions));
76
79 : Convert.FromBase64String(securityConfiguration.CustomTokenSigningKeyBase64);
80
81 ValidationParameters = new TokenValidationParameters
82 {
83 ValidateIssuerSigningKey = true,
84 IssuerSigningKeyResolver = (_, _, _, _) => Enumerable.Repeat(signingKey, 1),
85
86 ValidateIssuer = true,
87 ValidIssuer = assemblyInformationProvider.AssemblyName.Name,
88
89 ValidateLifetime = true,
90 ValidateAudience = true,
91 ValidAudience = typeof(TokenResponse).Assembly.GetName().Name,
92
93 ClockSkew = TimeSpan.FromMinutes(securityConfiguration.TokenClockSkewMinutes),
94
95 RequireSignedTokens = true,
96
97 RequireExpirationTime = true,
98 };
99
100 tokenHandler = new JwtSecurityTokenHandler();
101 }
102
104 public string CreateToken(User user, bool oAuth)
105 {
106 ArgumentNullException.ThrowIfNull(user);
107
108 var uid = user.Require(x => x.Id);
109 var now = DateTimeOffset.UtcNow;
110 var nowUnix = now.ToUnixTimeSeconds();
111
112 // this prevents validation conflicts down the line
113 // tldr we can (theoretically) receive a token the same second after we generate it
114 // since unix time rounds down, it looks like it came from before the user changed their password
115 // this happens occasionally in unit tests
116 // just delay a second so we can force a round up
117 var userLastPassworUpdateUnix = user.LastPasswordUpdate?.ToUnixTimeSeconds();
118 DateTimeOffset notBefore;
119 if (nowUnix == userLastPassworUpdateUnix)
120 notBefore = now.AddSeconds(1);
121 else
122 notBefore = now;
123
124 var expiry = now.AddMinutes(oAuth
127
128 var securityToken = new JwtSecurityToken(
130 new JwtPayload(
131 ValidationParameters.ValidIssuer,
132 ValidationParameters.ValidAudience,
133 Enumerable.Empty<Claim>(),
134 new Dictionary<string, object>
135 {
136 { JwtRegisteredClaimNames.Sub, uid.ToString(CultureInfo.InvariantCulture) },
137 },
138 notBefore.UtcDateTime,
139 expiry.UtcDateTime,
140 now.UtcDateTime));
141
142 var tokenResponse = tokenHandler.WriteToken(securityToken);
143
144 return tokenResponse;
145 }
146 }
147}
Represents a JWT returned by the API.
Configuration options pertaining to user security.
uint TokenSigningKeyByteCount
Amount of bytes to use in the Microsoft.IdentityModel.Tokens.TokenValidationParameters....
string? CustomTokenSigningKeyBase64
A custom token signing key. Overrides TokenSigningKeyByteCount.
uint TokenClockSkewMinutes
Amount of minutes to skew the clock for Api.Models.Response.TokenResponse validation.
uint OAuthTokenExpiryMinutes
Amount of minutes until Api.Models.Response.TokenResponses generated from OAuth logins expire.
uint TokenExpiryMinutes
Amount of minutes until Api.Models.Response.TokenResponses generated from passwords expire.
DateTimeOffset? LastPasswordUpdate
When PasswordHash was last changed.
Definition User.cs:63
SymmetricSecurityKey signingKey
Backing field for SigningKeyBytes.
TokenValidationParameters ValidationParameters
The TokenValidationParameters for the ITokenFactory.
ReadOnlySpan< byte > SigningKeyBytes
Gets or sets the ITokenFactory's signing key bytes.
string CreateToken(User user, bool oAuth)
Create a TokenResponse for a given user .A new token string.
readonly JwtSecurityTokenHandler tokenHandler
The JwtSecurityTokenHandler used to generate TokenResponse.Bearer strings.
readonly SecurityConfiguration securityConfiguration
The SecurityConfiguration for the TokenFactory.
TokenFactory(ICryptographySuite cryptographySuite, IAssemblyInformationProvider assemblyInformationProvider, IOptions< SecurityConfiguration > securityConfigurationOptions)
Initializes a new instance of the TokenFactory class.
JwtHeader tokenHeader
The JwtHeader for generating tokens.
Contains various cryptographic functions.
byte[] GetSecureBytes(uint amount)
Generates a secure set of bytes.
AssemblyName AssemblyName
Gets the global::System.Reflection.AssemblyName.