seb-win-refactoring/SafeExamBrowser.SystemComponents/UserInfo.cs

112 lines
2.7 KiB
C#

/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Diagnostics;
using System.Security.Principal;
using System.Text.RegularExpressions;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.SystemComponents.Contracts;
namespace SafeExamBrowser.SystemComponents
{
public class UserInfo : IUserInfo
{
private const string SID_REGEX_PATTERN = @"S-\d(-\d+)+";
private ILogger logger;
public UserInfo(ILogger logger)
{
this.logger = logger;
}
public string GetUserName()
{
return Environment.UserName;
}
public string GetUserSid()
{
return WindowsIdentity.GetCurrent().User.Value;
}
public bool TryGetSidForUser(string userName, out string sid)
{
var strategies = new Func<string, string>[] { NtAccount, Wmi };
var success = false;
sid = default(string);
foreach (var strategy in strategies)
{
try
{
sid = strategy.Invoke(userName);
if (IsValid(sid))
{
logger.Info($"Found SID '{sid}' via '{strategy.Method.Name}' for user name '{userName}'!");
success = true;
break;
}
logger.Warn($"Retrieved invalid SID '{sid}' via '{strategy.Method.Name}' for user name '{userName}'!");
}
catch (Exception e)
{
logger.Error($"Failed to get SID via '{strategy.Method.Name}' for user name '{userName}'!", e);
}
}
if (!success)
{
logger.Error($"All attempts to retrieve SID for user name '{userName}' failed!");
}
return success;
}
private string NtAccount(string userName)
{
var account = new NTAccount(userName);
if (account.IsValidTargetType(typeof(SecurityIdentifier)))
{
return account.Translate(typeof(SecurityIdentifier)).Value;
}
return null;
}
private string Wmi(string userName)
{
var process = new Process();
process.StartInfo.Arguments = $"/c \"wmic useraccount where name='{userName}' get sid\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
process.Start();
process.WaitForExit(5000);
var output = process.StandardOutput.ReadToEnd();
var match = Regex.Match(output, SID_REGEX_PATTERN);
return match.Success ? match.Value : null;
}
private bool IsValid(string sid)
{
return !String.IsNullOrWhiteSpace(sid) && Regex.IsMatch(sid, $"^{SID_REGEX_PATTERN}$");
}
}
}