//******************************************************************************************************// WindowsUserInfo.cs - Gbtc//// Copyright © 2014, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 08/27/2014 - J. Ritchie Carroll// Generated original version of source code.////****************************************************************************************************** using System;using System.Collections;using System.Collections.Generic;using System.DirectoryServices;using System.IO;using System.Linq;using System.Management;using System.Reflection;using System.Runtime.InteropServices;using System.Security;using System.Security.Principal;using System.Text.RegularExpressions;using System.Threading;using GSF.Configuration;using GSF.Diagnostics;using GSF.Interop;using GSF.IO;using Microsoft.Win32; #if !MONOusing System.DirectoryServices.AccountManagement;#endif // ReSharper disable RedundantExplicitParamsArrayCreationnamespace GSF.Identity{ // Windows implementation of key UserInfo class elements internal sealed class WindowsUserInfo : IUserInfo { #region [ Members ] // Constants private const string LogonDomainRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"; private const string LogonDomainRegistryValue = "DefaultDomainName"; // Fields private readonly UserInfo m_parent; private DirectoryEntry m_userEntry; private bool m_domainRespondsForUser; private readonly bool m_useLegacyGroupLookups; private bool m_disposed; private bool m_initialized; #endregion #region [ Constructors ] public WindowsUserInfo(UserInfo parent) { m_parent = parent; // Attempt to attach to power mode changed system event try { SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; } catch { // This event will not be raised when running from a Windows service since // a service does not establish a message loop. } // Attempt to get configuration flag for using legacy group lookups try { ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[m_parent.SettingsCategory]; settings.Add("UseLegacyGroupLookups", m_useLegacyGroupLookups, "Flag that determines if group based lookups for local users should use legacy algorithm. Enabling may speed up authentication when using local accounts."); m_useLegacyGroupLookups = settings["UseLegacyGroupLookups"].ValueAs(m_useLegacyGroupLookups); } catch (Exception ex) { Logger.SwallowException(ex, "Failed while checking configuration for legacy group lookups"); } } ~WindowsUserInfo() { Dispose(false); } #endregion #region [ Properties ] public bool DomainRespondsForUser { get { if (!m_initialized) { // Attempt to initialize try { Initialize(); } catch (InitializationException) { // Initialization failures are due to domain not responding, // member flag is set in Initialize() method. } } return m_domainRespondsForUser; } } public bool Exists { get { bool exists = false; if (!m_initialized) { // Attempt to initialize try { Initialize(); } catch (InitializationException) { // User could not be found - this could simply mean that ActiveDirectory is unavailable (e.g., laptop disconnected from the domain). // In this case, if user logged in with cached credentials they are at least authenticated so we can assume that the user exists... IPrincipal principal = m_parent.PassthroughPrincipal; IIdentity identity = principal?.Identity ?? WindowsIdentity.GetCurrent(); exists = !string.IsNullOrEmpty(m_parent.LoginID) && identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase) && identity.IsAuthenticated; } } if (!exists) { if (IsLocalAccount) { try { exists = DirectoryEntry.Exists($"WinNT://{m_parent.Domain}/{m_parent.UserName}"); } catch { exists = false; } } else { exists = !(m_userEntry is null); } } return exists; } } public bool Enabled { get; set; } public DateTime LastLogon { get { if (Enabled) { try { return IsLocalAccount ? DateTime.Parse(GetUserPropertyValue("lastLogin")) : DateTime.FromFileTime(ConvertToLong(GetUserPropertyValueCollection("lastLogon").Value)); } catch { return DateTime.MinValue; } } return DateTime.MinValue; } } public DateTime AccountCreationDate { get { if (Enabled) { try { if (IsLocalAccount) { string profilePath = GetUserPropertyValue("profile"); if (string.IsNullOrEmpty(profilePath) || !Directory.Exists(profilePath)) { // Remove any trailing directory separator character from the file path. string rootFolder = FilePath.AddPathSuffix(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); string userFolder = FilePath.GetLastDirectoryName(rootFolder); int folderLocation = rootFolder.LastIndexOf(userFolder, StringComparison.OrdinalIgnoreCase); // Remove user profile name for current user (this class may be for user other than owner of current thread) rootFolder = FilePath.AddPathSuffix(rootFolder.Substring(0, folderLocation)); // Create profile path for user referenced in this UserInfo class profilePath = FilePath.AddPathSuffix(rootFolder + m_parent.UserName); } return Directory.GetCreationTime(profilePath); } return Convert.ToDateTime(GetUserPropertyValue("whenCreated")); } catch { return DateTime.MinValue; } } return DateTime.MinValue; } } public DateTime NextPasswordChangeDate { get { DateTime passwordChangeDate = DateTime.MaxValue; if (Enabled && !m_parent.PasswordCannotChange && !m_parent.PasswordDoesNotExpire) { try { if (IsLocalAccount) { Ticks maxPasswordTicksAge = MaximumPasswordAge; if (maxPasswordTicksAge >= 0) { // WinNT properties are in seconds, not ticks long passwordAge = long.Parse(GetUserPropertyValue("passwordAge")); long maxPasswordAge = (long)maxPasswordTicksAge.ToSeconds(); if (passwordAge > maxPasswordAge || GetUserPropertyValue("passwordExpired").ParseBoolean()) { // User must change password on next logon. passwordChangeDate = DateTime.UtcNow; } else { // User must change password periodically. passwordChangeDate = DateTime.UtcNow.AddSeconds(maxPasswordAge - passwordAge); } } } else { long passwordSetOn = ConvertToLong(GetUserPropertyValueCollection("pwdLastSet").Value); if (passwordSetOn == 0) { // User must change password on next logon. passwordChangeDate = DateTime.UtcNow; } else { // User must change password periodically. long maxPasswordAge = MaximumPasswordAge; // Ignore extremes if (maxPasswordAge != long.MaxValue && maxPasswordAge > 0) passwordChangeDate = DateTime.FromFileTime(passwordSetOn).AddDays(TimeSpan.FromTicks(maxPasswordAge).Duration().Days); } } } catch { return DateTime.MaxValue; } } return passwordChangeDate; } } public int LocalUserAccountControl { get { int userAccountControl = -1; if (Enabled && IsLocalAccount) { string userPropertyValue = GetUserPropertyValue("userFlags"); if (string.IsNullOrEmpty(userPropertyValue)) throw new SecurityException(string.Format(UserInfo.SecurityExceptionFormat, "Local", UserInfo.CurrentUserID, "local machine accounts")); if (!int.TryParse(userPropertyValue, out userAccountControl)) throw new InvalidOperationException(string.Format(UserInfo.UnknownErrorFormat, m_parent.LoginID, userPropertyValue)); } return userAccountControl; } } public Ticks MaximumPasswordAge { get { if (!Enabled) return -1; string maxAgePropertyValue = string.Empty; if (IsLocalAccount) { maxAgePropertyValue = GetUserPropertyValue("maxPasswordAge"); } else { WindowsImpersonationContext currentContext = null; try { currentContext = m_parent.ImpersonatePrivilegedAccount(); using (DirectorySearcher searcher = CreateDirectorySearcher()) { SearchResult searchResult = searcher.FindOne(); if (!(searchResult is null) && searchResult.Properties.Contains("maxPwdAge")) maxAgePropertyValue = searchResult.Properties["maxPwdAge"][0].ToString(); } } finally { UserInfo.EndImpersonation(currentContext); } } if (string.IsNullOrEmpty(maxAgePropertyValue)) return -1; long maxPasswordAge = long.Parse(maxAgePropertyValue); if (IsLocalAccount) return Ticks.FromSeconds(maxPasswordAge); return maxPasswordAge; } } public string[] Groups { get { #if !MONO if (!Enabled) return Array.Empty<string>(); if (IsLocalAccount || m_useLegacyGroupLookups) return OldGetGroups(); using (Logger.SuppressFirstChanceExceptionLogMessages()) { try { using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain)) using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName)) { return principal?.GetAuthorizationGroups() .Select(groupPrincipal => groupPrincipal.Sid.ToString()) .Select(SIDToAccountName) .ToArray() ?? Array.Empty<string>(); } } catch (Exception ex) { Log.Publish(MessageLevel.Error, "Get Groups", ex.Message, null, ex); // TODO: Fix random, inexplicable errors when looking up // identities via System.DirectoryServices.AccountManagement return OldGetGroups(); } } #else return OldGetGroups(); #endif } } public string[] LocalGroups { get { #if !MONO if (!Enabled) return Array.Empty<string>(); if (IsLocalAccount || m_useLegacyGroupLookups) return OldGetLocalGroups(); using (Logger.SuppressFirstChanceExceptionLogMessages()) { try { using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain)) using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName)) { return principal?.GetAuthorizationGroups() .Cast<GroupPrincipal>() .Where(groupPrincipal => groupPrincipal.GroupScope == GroupScope.Local) .Select(groupPrincipal => groupPrincipal.Sid.ToString()) .Select(SIDToAccountName) .ToArray() ?? Array.Empty<string>(); } } catch (Exception ex) { Log.Publish(MessageLevel.Error, "Get LocalGroups", ex.Message, null, ex); // TODO: Fix random, inexplicable errors when looking up // identities via System.DirectoryServices.AccountManagement return OldGetLocalGroups(); } } #else return OldGetLocalGroups(); #endif } } public string FullLocalUserName { get { string name = GetUserPropertyValue("fullName"); if (string.IsNullOrEmpty(name)) name = GetUserPropertyValue("Name"); return name; } } public bool IsLocalAccount { get; private set; } #endregion #region [ Methods ] /// <summary> /// Releases all the resources used by the <see cref="WindowsUserInfo"/> object. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Releases the unmanaged resources used by the <see cref="WindowsUserInfo"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> private void Dispose(bool disposing) { if (m_disposed) return; try { // This will be done regardless of whether the object is finalized or disposed. if (!disposing) return; m_userEntry?.Dispose();Lines 1–500 of 1543. Load more
//****************************************************************************************************** // WindowsUserInfo.cs - Gbtc // // Copyright © 2014, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 08/27/2014 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections; using System.Collections.Generic; using System.DirectoryServices; using System.IO; using System.Linq; using System.Management; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; using System.Text.RegularExpressions; using System.Threading; using GSF.Configuration; using GSF.Diagnostics; using GSF.Interop; using GSF.IO; using Microsoft.Win32; #if !MONO using System.DirectoryServices.AccountManagement; #endif // ReSharper disable RedundantExplicitParamsArrayCreation namespace GSF.Identity { // Windows implementation of key UserInfo class elements internal sealed class WindowsUserInfo : IUserInfo { #region [ Members ] // Constants private const string LogonDomainRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"; private const string LogonDomainRegistryValue = "DefaultDomainName"; // Fields private readonly UserInfo m_parent; private DirectoryEntry m_userEntry; private bool m_domainRespondsForUser; private readonly bool m_useLegacyGroupLookups; private bool m_disposed; private bool m_initialized; #endregion #region [ Constructors ] public WindowsUserInfo(UserInfo parent) { m_parent = parent; // Attempt to attach to power mode changed system event try { SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; } catch { // This event will not be raised when running from a Windows service since // a service does not establish a message loop. } // Attempt to get configuration flag for using legacy group lookups try { ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[m_parent.SettingsCategory]; settings.Add("UseLegacyGroupLookups", m_useLegacyGroupLookups, "Flag that determines if group based lookups for local users should use legacy algorithm. Enabling may speed up authentication when using local accounts."); m_useLegacyGroupLookups = settings["UseLegacyGroupLookups"].ValueAs(m_useLegacyGroupLookups); } catch (Exception ex) { Logger.SwallowException(ex, "Failed while checking configuration for legacy group lookups"); } } ~WindowsUserInfo() { Dispose(false); } #endregion #region [ Properties ] public bool DomainRespondsForUser { get { if (!m_initialized) { // Attempt to initialize try { Initialize(); } catch (InitializationException) { // Initialization failures are due to domain not responding, // member flag is set in Initialize() method. } } return m_domainRespondsForUser; } } public bool Exists { get { bool exists = false; if (!m_initialized) { // Attempt to initialize try { Initialize(); } catch (InitializationException) { // User could not be found - this could simply mean that ActiveDirectory is unavailable (e.g., laptop disconnected from the domain). // In this case, if user logged in with cached credentials they are at least authenticated so we can assume that the user exists... IPrincipal principal = m_parent.PassthroughPrincipal; IIdentity identity = principal?.Identity ?? WindowsIdentity.GetCurrent(); exists = !string.IsNullOrEmpty(m_parent.LoginID) && identity.Name.Equals(m_parent.LoginID, StringComparison.OrdinalIgnoreCase) && identity.IsAuthenticated; } } if (!exists) { if (IsLocalAccount) { try { exists = DirectoryEntry.Exists($"WinNT://{m_parent.Domain}/{m_parent.UserName}"); } catch { exists = false; } } else { exists = !(m_userEntry is null); } } return exists; } } public bool Enabled { get; set; } public DateTime LastLogon { get { if (Enabled) { try { return IsLocalAccount ? DateTime.Parse(GetUserPropertyValue("lastLogin")) : DateTime.FromFileTime(ConvertToLong(GetUserPropertyValueCollection("lastLogon").Value)); } catch { return DateTime.MinValue; } } return DateTime.MinValue; } } public DateTime AccountCreationDate { get { if (Enabled) { try { if (IsLocalAccount) { string profilePath = GetUserPropertyValue("profile"); if (string.IsNullOrEmpty(profilePath) || !Directory.Exists(profilePath)) { // Remove any trailing directory separator character from the file path. string rootFolder = FilePath.AddPathSuffix(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); string userFolder = FilePath.GetLastDirectoryName(rootFolder); int folderLocation = rootFolder.LastIndexOf(userFolder, StringComparison.OrdinalIgnoreCase); // Remove user profile name for current user (this class may be for user other than owner of current thread) rootFolder = FilePath.AddPathSuffix(rootFolder.Substring(0, folderLocation)); // Create profile path for user referenced in this UserInfo class profilePath = FilePath.AddPathSuffix(rootFolder + m_parent.UserName); } return Directory.GetCreationTime(profilePath); } return Convert.ToDateTime(GetUserPropertyValue("whenCreated")); } catch { return DateTime.MinValue; } } return DateTime.MinValue; } } public DateTime NextPasswordChangeDate { get { DateTime passwordChangeDate = DateTime.MaxValue; if (Enabled && !m_parent.PasswordCannotChange && !m_parent.PasswordDoesNotExpire) { try { if (IsLocalAccount) { Ticks maxPasswordTicksAge = MaximumPasswordAge; if (maxPasswordTicksAge >= 0) { // WinNT properties are in seconds, not ticks long passwordAge = long.Parse(GetUserPropertyValue("passwordAge")); long maxPasswordAge = (long)maxPasswordTicksAge.ToSeconds(); if (passwordAge > maxPasswordAge || GetUserPropertyValue("passwordExpired").ParseBoolean()) { // User must change password on next logon. passwordChangeDate = DateTime.UtcNow; } else { // User must change password periodically. passwordChangeDate = DateTime.UtcNow.AddSeconds(maxPasswordAge - passwordAge); } } } else { long passwordSetOn = ConvertToLong(GetUserPropertyValueCollection("pwdLastSet").Value); if (passwordSetOn == 0) { // User must change password on next logon. passwordChangeDate = DateTime.UtcNow; } else { // User must change password periodically. long maxPasswordAge = MaximumPasswordAge; // Ignore extremes if (maxPasswordAge != long.MaxValue && maxPasswordAge > 0) passwordChangeDate = DateTime.FromFileTime(passwordSetOn).AddDays(TimeSpan.FromTicks(maxPasswordAge).Duration().Days); } } } catch { return DateTime.MaxValue; } } return passwordChangeDate; } } public int LocalUserAccountControl { get { int userAccountControl = -1; if (Enabled && IsLocalAccount) { string userPropertyValue = GetUserPropertyValue("userFlags"); if (string.IsNullOrEmpty(userPropertyValue)) throw new SecurityException(string.Format(UserInfo.SecurityExceptionFormat, "Local", UserInfo.CurrentUserID, "local machine accounts")); if (!int.TryParse(userPropertyValue, out userAccountControl)) throw new InvalidOperationException(string.Format(UserInfo.UnknownErrorFormat, m_parent.LoginID, userPropertyValue)); } return userAccountControl; } } public Ticks MaximumPasswordAge { get { if (!Enabled) return -1; string maxAgePropertyValue = string.Empty; if (IsLocalAccount) { maxAgePropertyValue = GetUserPropertyValue("maxPasswordAge"); } else { WindowsImpersonationContext currentContext = null; try { currentContext = m_parent.ImpersonatePrivilegedAccount(); using (DirectorySearcher searcher = CreateDirectorySearcher()) { SearchResult searchResult = searcher.FindOne(); if (!(searchResult is null) && searchResult.Properties.Contains("maxPwdAge")) maxAgePropertyValue = searchResult.Properties["maxPwdAge"][0].ToString(); } } finally { UserInfo.EndImpersonation(currentContext); } } if (string.IsNullOrEmpty(maxAgePropertyValue)) return -1; long maxPasswordAge = long.Parse(maxAgePropertyValue); if (IsLocalAccount) return Ticks.FromSeconds(maxPasswordAge); return maxPasswordAge; } } public string[] Groups { get { #if !MONO if (!Enabled) return Array.Empty<string>(); if (IsLocalAccount || m_useLegacyGroupLookups) return OldGetGroups(); using (Logger.SuppressFirstChanceExceptionLogMessages()) { try { using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain)) using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName)) { return principal?.GetAuthorizationGroups() .Select(groupPrincipal => groupPrincipal.Sid.ToString()) .Select(SIDToAccountName) .ToArray() ?? Array.Empty<string>(); } } catch (Exception ex) { Log.Publish(MessageLevel.Error, "Get Groups", ex.Message, null, ex); // TODO: Fix random, inexplicable errors when looking up // identities via System.DirectoryServices.AccountManagement return OldGetGroups(); } } #else return OldGetGroups(); #endif } } public string[] LocalGroups { get { #if !MONO if (!Enabled) return Array.Empty<string>(); if (IsLocalAccount || m_useLegacyGroupLookups) return OldGetLocalGroups(); using (Logger.SuppressFirstChanceExceptionLogMessages()) { try { using (PrincipalContext context = IsLocalAccount ? new PrincipalContext(ContextType.Machine) : new PrincipalContext(ContextType.Domain, m_parent.Domain)) using (UserPrincipal principal = UserPrincipal.FindByIdentity(context, m_parent.UserName)) { return principal?.GetAuthorizationGroups() .Cast<GroupPrincipal>() .Where(groupPrincipal => groupPrincipal.GroupScope == GroupScope.Local) .Select(groupPrincipal => groupPrincipal.Sid.ToString()) .Select(SIDToAccountName) .ToArray() ?? Array.Empty<string>(); } } catch (Exception ex) { Log.Publish(MessageLevel.Error, "Get LocalGroups", ex.Message, null, ex); // TODO: Fix random, inexplicable errors when looking up // identities via System.DirectoryServices.AccountManagement return OldGetLocalGroups(); } } #else return OldGetLocalGroups(); #endif } } public string FullLocalUserName { get { string name = GetUserPropertyValue("fullName"); if (string.IsNullOrEmpty(name)) name = GetUserPropertyValue("Name"); return name; } } public bool IsLocalAccount { get; private set; } #endregion #region [ Methods ] /// <summary> /// Releases all the resources used by the <see cref="WindowsUserInfo"/> object. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Releases the unmanaged resources used by the <see cref="WindowsUserInfo"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> private void Dispose(bool disposing) { if (m_disposed) return; try { // This will be done regardless of whether the object is finalized or disposed. if (!disposing) return; m_userEntry?.Dispose();