tgstation-server
The /tg/station 13 server suite
AuthenticationContextFactory.cs
Go to the documentation of this file.
1 using Microsoft.EntityFrameworkCore;
2 using System;
3 using System.Linq;
4 using System.Threading;
5 using System.Threading.Tasks;
7 
8 namespace Tgstation.Server.Host.Security
9 {
12  {
14  public IAuthenticationContext CurrentAuthenticationContext { get; private set; }
15 
20 
25 
30 
37  public AuthenticationContextFactory(ISystemIdentityFactory systemIdentityFactory, IDatabaseContext databaseContext, IIdentityCache identityCache)
38  {
39  this.systemIdentityFactory = systemIdentityFactory ?? throw new ArgumentNullException(nameof(systemIdentityFactory));
40  this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
41  this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
42  }
43 
45  public void Dispose() => CurrentAuthenticationContext?.Dispose();
46 
48  public async Task CreateAuthenticationContext(long userId, long? instanceId, DateTimeOffset validAfter, CancellationToken cancellationToken)
49  {
50  if (CurrentAuthenticationContext != null)
51  throw new InvalidOperationException("Authentication context has already been loaded");
52 
53  var userQuery = databaseContext.Users.Where(x => x.Id == userId)
54  .Include(x => x.CreatedBy)
55  .FirstOrDefaultAsync(cancellationToken);
56 
57  var instanceUserQuery = instanceId.HasValue ? databaseContext.InstanceUsers
58  .Where(x => x.UserId == userId && x.InstanceId == instanceId && x.Instance.Online.Value)
59  .Include(x => x.Instance)
60  .FirstOrDefaultAsync(cancellationToken) : Task.FromResult<InstanceUser>(null);
61 
62  var user = await userQuery.ConfigureAwait(false);
63  if (user == default)
64  {
65  CurrentAuthenticationContext = new AuthenticationContext();
66  return;
67  }
68 
69  ISystemIdentity systemIdentity;
70  if (user.SystemIdentifier != null)
71  systemIdentity = identityCache.LoadCachedIdentity(user);
72  else
73  {
74  if (user.LastPasswordUpdate.HasValue && user.LastPasswordUpdate > validAfter)
75  {
76  CurrentAuthenticationContext = new AuthenticationContext();
77  return;
78  }
79  systemIdentity = null;
80  }
81 
82  try
83  {
84  var instanceUser = await instanceUserQuery.ConfigureAwait(false);
85 
86  CurrentAuthenticationContext = new AuthenticationContext(systemIdentity, user, instanceUser);
87  }
88  catch
89  {
90  systemIdentity?.Dispose();
91  throw;
92  }
93  }
94  }
95 }
AuthenticationContextFactory(ISystemIdentityFactory systemIdentityFactory, IDatabaseContext databaseContext, IIdentityCache identityCache)
Construct an AuthenticationContextFactory
Represents a user on the current System.Runtime.InteropServices.OSPlatform
Represents the currently authenticated Api.Models.User
readonly IIdentityCache identityCache
The IIdentityCache for the AuthenticationContextFactory
readonly ISystemIdentityFactory systemIdentityFactory
The ISystemIdentityFactory for the AuthenticationContextFactory
readonly IDatabaseContext databaseContext
The IDatabaseContext for the AuthenticationContextFactory
async Task CreateAuthenticationContext(long userId, long?instanceId, DateTimeOffset validAfter, CancellationToken cancellationToken)
Create an IAuthenticationContext to populate CurrentAuthenticationContext