tgstation-server  4.4.0
The /tg/station 13 server suite
AuthenticationContextFactory.cs
Go to the documentation of this file.
1 using Microsoft.EntityFrameworkCore;
2 using Microsoft.Extensions.Logging;
3 using System;
4 using System.Linq;
5 using System.Threading;
6 using System.Threading.Tasks;
9 
10 namespace Tgstation.Server.Host.Security
11 {
14  {
16  public IAuthenticationContext CurrentAuthenticationContext { get; private set; }
17 
22 
27 
31  readonly ILogger<AuthenticationContextFactory> logger;
32 
40  IDatabaseContext databaseContext,
41  IIdentityCache identityCache,
42  ILogger<AuthenticationContextFactory> logger)
43  {
44  this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
45  this.identityCache = identityCache ?? throw new ArgumentNullException(nameof(identityCache));
46  this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
47  }
48 
50  public void Dispose() => CurrentAuthenticationContext?.Dispose();
51 
53  public async Task CreateAuthenticationContext(long userId, long? instanceId, DateTimeOffset validAfter, CancellationToken cancellationToken)
54  {
55  if (CurrentAuthenticationContext != null)
56  throw new InvalidOperationException("Authentication context has already been loaded");
57 
58  var user = await databaseContext
59  .Users
60  .AsQueryable()
61  .Where(x => x.Id == userId)
62  .Include(x => x.CreatedBy)
63  .FirstOrDefaultAsync(cancellationToken)
64  .ConfigureAwait(false);
65  if (user == default)
66  {
67  logger.LogWarning("Unable to find user with ID {0}!", userId);
68  CurrentAuthenticationContext = new AuthenticationContext();
69  return;
70  }
71 
72  ISystemIdentity systemIdentity;
73  if (user.SystemIdentifier != null)
74  systemIdentity = identityCache.LoadCachedIdentity(user);
75  else
76  {
77  if (user.LastPasswordUpdate.HasValue && user.LastPasswordUpdate > validAfter)
78  {
79  logger.LogDebug("Rejecting token for user {0} created before last password update: {1}", userId, user.LastPasswordUpdate.Value);
80  CurrentAuthenticationContext = new AuthenticationContext();
81  return;
82  }
83 
84  systemIdentity = null;
85  }
86 
87  try
88  {
89  InstanceUser instanceUser = null;
90  if (instanceId.HasValue)
91  {
92  instanceUser = await databaseContext.InstanceUsers
93  .AsQueryable()
94  .Where(x => x.UserId == userId && x.InstanceId == instanceId && x.Instance.Online.Value)
95  .Include(x => x.Instance)
96  .FirstOrDefaultAsync(cancellationToken)
97  .ConfigureAwait(false);
98 
99  if (instanceUser == null)
100  logger.LogDebug("User {0} does not have permissions on instance {1}!", userId, instanceId.Value);
101  }
102 
103  CurrentAuthenticationContext = new AuthenticationContext(systemIdentity, user, instanceUser);
104  }
105  catch
106  {
107  systemIdentity?.Dispose();
108  throw;
109  }
110  }
111  }
112 }
Represents a user on the current global::System.Runtime.InteropServices.OSPlatform ...
Represents the currently authenticated Api.Models.User
readonly IIdentityCache identityCache
The IIdentityCache for the AuthenticationContextFactory
readonly ILogger< AuthenticationContextFactory > logger
The ILogger 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
AuthenticationContextFactory(IDatabaseContext databaseContext, IIdentityCache identityCache, ILogger< AuthenticationContextFactory > logger)
Construct an AuthenticationContextFactory