diff --git a/src/Gemstone.Security/AuthenticationProviders/WindowsAuthenticationProvider.cs b/src/Gemstone.Security/AuthenticationProviders/WindowsAuthenticationProvider.cs index 8ba20c0b..7fdf3a0e 100644 --- a/src/Gemstone.Security/AuthenticationProviders/WindowsAuthenticationProvider.cs +++ b/src/Gemstone.Security/AuthenticationProviders/WindowsAuthenticationProvider.cs @@ -25,6 +25,7 @@ using System.Collections.Generic; using System.DirectoryServices; using System.Linq; +using System.Management; using System.Runtime.CompilerServices; using System.Security.Claims; using System.Security.Principal; @@ -42,6 +43,11 @@ public class WindowsAuthenticationProviderOptions /// Root path from which LDAP searches should be performed. /// public string? LDAPPath { get; set; } + + /// + /// Flag to indicate whether the UI will also search local Users and Groups. + /// + public bool AllowLocalAccounts { get; set; } = false; } /// @@ -176,6 +182,27 @@ private IEnumerable FindUsers(string searchText) yield return new ProviderClaim(value, description); } + + if (!Options.AllowLocalAccounts) + yield break; + + using ManagementObjectSearcher localSearcher = new ("root\\CIMV2", $"SELECT * FROM Win32_UserAccount WHERE LocalAccount = True AND Name LIKE '{escapedSearchText.Replace("*", "%")}'"); + + foreach (ManagementObject user in localSearcher.Get()) + { + string? name = user["Name"]?.ToString(); + string? sid = user["SID"]?.ToString(); + string? fullName = user["FullName"]?.ToString(); + + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(sid)) + continue; + + string description = !string.IsNullOrEmpty(fullName) + ? $"{name} ({fullName}. Local)" + : $"{name} (Local)"; + + yield return new ProviderClaim(sid, description); + } } private IEnumerable FindGroups(string searchText) @@ -222,6 +249,28 @@ private IEnumerable FindGroups(string searchText) return string.Join('.', dc); } + + if (!Options.AllowLocalAccounts) + yield break; + + + using ManagementObjectSearcher localSearcher = new("root\\CIMV2", $"SELECT * FROM Win32_Group WHERE LocalAccount = True AND Name LIKE '{escapedSearchText.Replace("*", "%")}'"); + + foreach (ManagementObject group in localSearcher.Get()) + { + string? name = group["Name"]?.ToString(); + string? sid = group["SID"]?.ToString(); + string? description = group["Description"]?.ToString(); + + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(sid)) + continue; + + string groupDescription = !string.IsNullOrEmpty(description) + ? $"{name} ({description}. Local)" + : $"{name} (Local)"; + + yield return new ProviderClaim(sid, groupDescription); + } } #endregion