diff --git a/Security/Principal/WindowsImpersonatedIdentity.cs b/Security/Principal/WindowsImpersonatedIdentity.cs index 144950b8..fe1ba64a 100644 --- a/Security/Principal/WindowsImpersonatedIdentity.cs +++ b/Security/Principal/WindowsImpersonatedIdentity.cs @@ -1,99 +1,65 @@ -#if (NET20 || NET35 || NET40 || NET45) -using System; -using System.ComponentModel; +#if NET20 || NET35 || NET40 || NET45 using System.Security.Principal; using static Vanara.PInvoke.AdvApi32; namespace Vanara.Security.Principal { /// - /// Impersonation of a user. Allows to execute code under another user context. Please note that the account that instantiates this class needs to have the 'Act as part of operating system' privilege set. + /// Impersonation of a user. Allows to execute code under another user context. Please note that the account that instantiates this class + /// needs to have the 'Act as part of operating system' privilege set. /// /// /// /// // The following code impersonates an account to perform work /// using (new WindowsImpersonatedIdentity("bob", "WORKDOMAIN", "bobs_secret_passw0rd") /// { - /// // Perform impersonated work in the body. Once the 'using' statement closes, - /// // the impersonation ends. + /// // Perform impersonated work in the body. Once the 'using' statement closes, + /// // the impersonation ends. /// } /// /// - public class WindowsImpersonatedIdentity : IDisposable, IIdentity + public class WindowsImpersonatedIdentity : WindowsLoggedInIdentity { private readonly WindowsImpersonationContext impersonationContext; - private WindowsIdentity identity; - private readonly bool ownId = true; /// - /// Starts the impersonation with the given credentials. Please note that the account that instantiates this class needs to have the 'Act as part of - /// operating system' privilege set. + /// Starts the impersonation with the given credentials. Please note that the account that instantiates this class needs to have the + /// 'Act as part of operating system' privilege set. /// /// - /// A string that specifies the name of the user. This is the name of the user account to log on to. If you use the user principal name (UPN) format, - /// User@DNSDomainName, the parameter must be NULL. + /// A string that specifies the name of the user. This is the name of the user account to log on to. If you use the user principal + /// name (UPN) format, User@DNSDomainName, the parameter must be NULL. /// /// - /// A string that specifies the name of the domain or server whose account database contains the account. If this parameter - /// is NULL, the user name must be specified in UPN format. If this parameter is ".", the account is validated by using only the local account database. + /// A string that specifies the name of the domain or server whose account database contains the account. + /// If this parameter is NULL, the user name must be specified in UPN format. If this parameter is ".", the account is validated by + /// using only the local account database. /// - /// A string that specifies the plaintext password for the user account specified by . + /// A string that specifies the plain-text password for the user account specified by . /// - /// Type of the logon. This parameter can usually be left as the default. For more information, lookup more detail for the dwLogonType parameter of the - /// Windows LogonUser function. + /// Type of the logon. This parameter can usually be left as the default. For more information, lookup more detail for the + /// dwLogonType parameter of the Windows LogonUser function. /// /// - /// The logon provider. This parameter can usually be left as the default. For more information, lookup more detail for the dwLogonProvider parameter of - /// the Windows LogonUser function. + /// The logon provider. This parameter can usually be left as the default. For more information, lookup more detail for the + /// dwLogonProvider parameter of the Windows LogonUser function. /// public WindowsImpersonatedIdentity(string userName, string domainName, string password, LogonUserType logonType = LogonUserType.LOGON32_LOGON_INTERACTIVE, - LogonUserProvider provider = LogonUserProvider.LOGON32_PROVIDER_DEFAULT) - { - if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException(nameof(userName)); - if (string.IsNullOrEmpty(password)) throw new ArgumentNullException(nameof(password)); - if (string.IsNullOrEmpty(domainName) && !userName.Contains("@")) throw new ArgumentNullException(nameof(domainName)); - if (LogonUser(userName, domainName, password, logonType, provider, out var hToken)) - { - using (hToken) - { - identity = new WindowsIdentity(hToken.DangerousGetHandle()); - impersonationContext = identity.Impersonate(); - } - } - else - throw new Win32Exception(); - } + LogonUserProvider provider = LogonUserProvider.LOGON32_PROVIDER_DEFAULT) : base(userName, domainName, password, logonType, provider) => impersonationContext = AuthenticatedIdentity.Impersonate(); /// - /// Starts the impersonation with the given . Please note that the account that instantiates this class needs to have the 'Act as part of operating system' privilege set. + /// Starts the impersonation with the given . Please note that the account that instantiates this class + /// needs to have the 'Act as part of operating system' privilege set. /// /// The identity to impersonate. - public WindowsImpersonatedIdentity(WindowsIdentity identityToImpersonate) - { - identity = identityToImpersonate; - impersonationContext = identity.Impersonate(); - ownId = false; - } + public WindowsImpersonatedIdentity(WindowsIdentity identityToImpersonate) : base(identityToImpersonate) => impersonationContext = AuthenticatedIdentity.Impersonate(); /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - public void Dispose() + public override void Dispose() { impersonationContext?.Undo(); - if (ownId) identity?.Dispose(); - identity = null; + base.Dispose(); } - - /// Gets the authenticated identity. - public WindowsIdentity AuthenticatedIdentity => identity; - - /// Gets the type of authentication used. - string IIdentity.AuthenticationType => identity?.AuthenticationType; - - /// Gets a value that indicates whether the user has been authenticated. - bool IIdentity.IsAuthenticated => identity?.IsAuthenticated ?? false; - - /// Gets the name of the current user. - string IIdentity.Name => identity?.Name; } } #endif \ No newline at end of file diff --git a/Security/Principal/WindowsLoggedInIdentity.cs b/Security/Principal/WindowsLoggedInIdentity.cs new file mode 100644 index 00000000..2e600e7b --- /dev/null +++ b/Security/Principal/WindowsLoggedInIdentity.cs @@ -0,0 +1,87 @@ +using System; +using System.ComponentModel; +using System.Security.Principal; +using static Vanara.PInvoke.AdvApi32; + +namespace Vanara.Security.Principal +{ + /// + /// Impersonation of a user. Allows to execute code under another user context. Please note that the account that instantiates this class + /// needs to have the 'Act as part of operating system' privilege set. + /// + public class WindowsLoggedInIdentity : IDisposable, IIdentity + { + private readonly SafeHTOKEN hToken; + private readonly bool ownId = true; + + /// + /// Provides an identity to a logged into user given the supplied credentials. Please note that the account that instantiates this + /// class needs to have the 'Act as part of operating system' privilege set. + /// + /// + /// A string that specifies the name of the user. This is the name of the user account to log on to. If you use the user principal + /// name (UPN) format, User@DNSDomainName, the parameter must be NULL. + /// + /// + /// A string that specifies the name of the domain or server whose account database contains the account. + /// If this parameter is NULL, the user name must be specified in UPN format. If this parameter is ".", the account is validated by + /// using only the local account database. + /// + /// A string that specifies the plain-text password for the user account specified by . + /// + /// Type of the logon. This parameter can usually be left as the default. For more information, lookup more detail for the + /// dwLogonType parameter of the Windows LogonUser function. + /// + /// + /// The logon provider. This parameter can usually be left as the default. For more information, lookup more detail for the + /// dwLogonProvider parameter of the Windows LogonUser function. + /// + public WindowsLoggedInIdentity(string userName, string domainName, string password, LogonUserType logonType = LogonUserType.LOGON32_LOGON_INTERACTIVE, + LogonUserProvider provider = LogonUserProvider.LOGON32_PROVIDER_DEFAULT) + { + if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException(nameof(userName)); + if (string.IsNullOrEmpty(password)) throw new ArgumentNullException(nameof(password)); + if (string.IsNullOrEmpty(domainName) && !userName.Contains("@")) throw new ArgumentNullException(nameof(domainName)); + if (LogonUser(userName, domainName, password, logonType, provider, out hToken)) + { + using (hToken) + { + AuthenticatedIdentity = new WindowsIdentity(hToken.DangerousGetHandle()); + } + } + else + throw new Win32Exception(); + } + + /// + /// Starts the impersonation with the given . Please note that the account that instantiates this class + /// needs to have the 'Act as part of operating system' privilege set. + /// + /// The identity to impersonate. + public WindowsLoggedInIdentity(WindowsIdentity identityToImpersonate) + { + AuthenticatedIdentity = identityToImpersonate; + ownId = false; + } + + /// Gets the authenticated identity. + public WindowsIdentity AuthenticatedIdentity { get; private set; } + + /// Gets the type of authentication used. + string IIdentity.AuthenticationType => AuthenticatedIdentity?.AuthenticationType; + + /// Gets a value that indicates whether the user has been authenticated. + bool IIdentity.IsAuthenticated => AuthenticatedIdentity?.IsAuthenticated ?? false; + + /// Gets the name of the current user. + string IIdentity.Name => AuthenticatedIdentity?.Name; + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public virtual void Dispose() + { + if (ownId) AuthenticatedIdentity?.Dispose(); + hToken?.Dispose(); + AuthenticatedIdentity = null; + } + } +} \ No newline at end of file