tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
WindowsSystemIdentityFactory.cs
Go to the documentation of this file.
1using System;
2using System.Diagnostics.CodeAnalysis;
3using System.DirectoryServices.AccountManagement;
4using System.Runtime.Versioning;
5using System.Security.Principal;
6using System.Threading;
7using System.Threading.Tasks;
8
9using Microsoft.Extensions.Logging;
10using Microsoft.Win32.SafeHandles;
11
15
17{
21 [SupportedOSPlatform("windows")]
23 {
27 readonly ILogger<WindowsSystemIdentityFactory> logger;
28
35 static void GetUserAndDomainName(string input, out string username, out string? domainName)
36 {
37 var splits = input.Split('\\');
38 username = splits.Length > 1 ? splits[1] : splits[0];
39 domainName = splits.Length > 1 ? splits[0] : null;
40 }
41
46 public WindowsSystemIdentityFactory(ILogger<WindowsSystemIdentityFactory> logger)
47 {
48 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
49 }
50
52 public ISystemIdentity GetCurrent() => new WindowsSystemIdentity(WindowsIdentity.GetCurrent());
53
55 public Task<ISystemIdentity?> CreateSystemIdentity(User user, CancellationToken cancellationToken) => Task.Factory.StartNew(
56 () =>
57 {
58 ArgumentNullException.ThrowIfNull(user);
59
60 if (user.SystemIdentifier == null)
61 throw new InvalidOperationException("User's SystemIdentifier must not be null!");
62
63 PrincipalContext? pc = null;
64 GetUserAndDomainName(user.SystemIdentifier, out _, out var domainName);
65
66 bool TryGetPrincipalFromContextType(ContextType contextType, [NotNullWhen(true)] out UserPrincipal? principal)
67 {
68 principal = null;
69 try
70 {
71 pc = domainName != null
72 ? new PrincipalContext(contextType, domainName)
73 : new PrincipalContext(contextType);
74 cancellationToken.ThrowIfCancellationRequested();
75 principal = UserPrincipal.FindByIdentity(pc, user.SystemIdentifier);
76 }
77 catch (OperationCanceledException)
78 {
79 throw;
80 }
81 catch (Exception ex)
82 {
83 logger.LogDebug(
84 ex,
85 "Error loading user for context type {contextType} and principal \"{domainName}\"!",
86 contextType,
87 domainName);
88 }
89 finally
90 {
91 if (principal == null)
92 {
93 pc?.Dispose();
94 cancellationToken.ThrowIfCancellationRequested();
95 }
96 }
97
98 return principal != null;
99 }
100
101 if (!TryGetPrincipalFromContextType(ContextType.Machine, out var principal) && !TryGetPrincipalFromContextType(ContextType.Domain, out principal))
102 return null;
103 return (ISystemIdentity)new WindowsSystemIdentity(principal);
104 },
105 cancellationToken,
107 TaskScheduler.Current);
108
110 public Task<ISystemIdentity?> CreateSystemIdentity(string username, string password, CancellationToken cancellationToken) => Task.Factory.StartNew(
111 () =>
112 {
113 ArgumentNullException.ThrowIfNull(username);
114 ArgumentNullException.ThrowIfNull(password);
115
116 var originalUsername = username;
117 GetUserAndDomainName(originalUsername, out username, out var domainName);
118
119 var res = NativeMethods.LogonUser(username, domainName, password, 3 /*LOGON32_LOGON_NETWORK*/, 0 /*LOGON32_PROVIDER_DEFAULT*/, out var token);
120 if (!res)
121 {
122 logger.LogTrace("Invalid system identity/password combo for username {0}!", originalUsername);
123 return null;
124 }
125
126 logger.LogTrace("Authenticated username {0} using system identity!", originalUsername);
127
128 // checked internally, windows identity always duplicates the handle when constructed
129 using var handle = new SafeAccessTokenHandle(token);
131 new WindowsIdentity(handle.DangerousGetHandle())); // https://github.com/dotnet/corefx/blob/6ed61acebe3214fcf79b4274f2bb9b55c0604a4d/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs#L271
132 },
133 cancellationToken,
135 TaskScheduler.Current);
136 }
137}
IIOManager that resolves paths to Environment.CurrentDirectory.
const TaskCreationOptions BlockingTaskCreationOptions
The TaskCreationOptions used to spawn Tasks for potentially long running, blocking operations.
ISystemIdentityFactory for windows systems. Uses long running tasks due to potential networked domain...
readonly ILogger< WindowsSystemIdentityFactory > logger
The ILogger for the WindowsSystemIdentityFactory.
WindowsSystemIdentityFactory(ILogger< WindowsSystemIdentityFactory > logger)
Initializes a new instance of the WindowsSystemIdentityFactory class.
static void GetUserAndDomainName(string input, out string username, out string? domainName)
Extract the username and domain name from a string in the format "username\\domainname".
ISystemIdentity GetCurrent()
Retrieves a ISystemIdentity representing the user executing tgstation-server.A ISystemIdentity repres...
Task< ISystemIdentity?> CreateSystemIdentity(User user, CancellationToken cancellationToken)
Create a ISystemIdentity for a given user .A Task<TResult> resulting in a new ISystemIdentity based o...
Task< ISystemIdentity?> CreateSystemIdentity(string username, string password, CancellationToken cancellationToken)
Create a ISystemIdentity for a given username and password.A Task<TResult> resulting in a new ISystem...
Native methods used by the code.
static bool LogonUser(string lpszUsername, string? lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken)
See https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx.
Represents a user on the current global::System.Runtime.InteropServices.OSPlatform.