mirror of https://github.com/dahall/Vanara.git
Added WindowsLoggedInIdentity to capture LogonUser typical work. Changed WindowsImpersonatedIdentity to derive from this new class.
parent
3877cc58bc
commit
3e23723019
|
@ -1,99 +1,65 @@
|
||||||
#if (NET20 || NET35 || NET40 || NET45)
|
#if NET20 || NET35 || NET40 || NET45
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using static Vanara.PInvoke.AdvApi32;
|
using static Vanara.PInvoke.AdvApi32;
|
||||||
|
|
||||||
namespace Vanara.Security.Principal
|
namespace Vanara.Security.Principal
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <code>
|
/// <code>
|
||||||
/// // The following code impersonates an account to perform work
|
/// // The following code impersonates an account to perform work
|
||||||
/// using (new WindowsImpersonatedIdentity("bob", "WORKDOMAIN", "bobs_secret_passw0rd")
|
/// using (new WindowsImpersonatedIdentity("bob", "WORKDOMAIN", "bobs_secret_passw0rd")
|
||||||
/// {
|
/// {
|
||||||
/// // Perform impersonated work in the body. Once the 'using' statement closes,
|
/// // Perform impersonated work in the body. Once the 'using' statement closes,
|
||||||
/// // the impersonation ends.
|
/// // the impersonation ends.
|
||||||
/// }
|
/// }
|
||||||
/// </code>
|
/// </code>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class WindowsImpersonatedIdentity : IDisposable, IIdentity
|
public class WindowsImpersonatedIdentity : WindowsLoggedInIdentity
|
||||||
{
|
{
|
||||||
private readonly WindowsImpersonationContext impersonationContext;
|
private readonly WindowsImpersonationContext impersonationContext;
|
||||||
private WindowsIdentity identity;
|
|
||||||
private readonly bool ownId = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the impersonation with the given credentials. Please note that the account that instantiates this class needs to have the 'Act as part of
|
/// Starts the impersonation with the given credentials. Please note that the account that instantiates this class needs to have the
|
||||||
/// operating system' privilege set.
|
/// 'Act as part of operating system' privilege set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userName">
|
/// <param name="userName">
|
||||||
/// 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,
|
/// 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
|
||||||
/// User@DNSDomainName, the <paramref name="domainName"/> parameter must be NULL.
|
/// name (UPN) format, User@DNSDomainName, the <paramref name="domainName"/> parameter must be NULL.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="domainName">
|
/// <param name="domainName">
|
||||||
/// A string that specifies the name of the domain or server whose account database contains the <paramref name="userName"/> account. If this parameter
|
/// A string that specifies the name of the domain or server whose account database contains the <paramref name="userName"/> account.
|
||||||
/// 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.
|
/// 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.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="password">A string that specifies the plaintext password for the user account specified by <paramref name="userName"/>.</param>
|
/// <param name="password">A string that specifies the plain-text password for the user account specified by <paramref name="userName"/>.</param>
|
||||||
/// <param name="logonType">
|
/// <param name="logonType">
|
||||||
/// 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
|
/// Type of the logon. This parameter can usually be left as the default. For more information, lookup more detail for the
|
||||||
/// Windows LogonUser function.
|
/// dwLogonType parameter of the Windows LogonUser function.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="provider">
|
/// <param name="provider">
|
||||||
/// The logon provider. This parameter can usually be left as the default. For more information, lookup more detail for the dwLogonProvider parameter of
|
/// The logon provider. This parameter can usually be left as the default. For more information, lookup more detail for the
|
||||||
/// the Windows LogonUser function.
|
/// dwLogonProvider parameter of the Windows LogonUser function.
|
||||||
/// </param>
|
/// </param>
|
||||||
public WindowsImpersonatedIdentity(string userName, string domainName, string password, LogonUserType logonType = LogonUserType.LOGON32_LOGON_INTERACTIVE,
|
public WindowsImpersonatedIdentity(string userName, string domainName, string password, LogonUserType logonType = LogonUserType.LOGON32_LOGON_INTERACTIVE,
|
||||||
LogonUserProvider provider = LogonUserProvider.LOGON32_PROVIDER_DEFAULT)
|
LogonUserProvider provider = LogonUserProvider.LOGON32_PROVIDER_DEFAULT) : base(userName, domainName, password, logonType, provider) => impersonationContext = AuthenticatedIdentity.Impersonate();
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the impersonation with the given <see cref="WindowsIdentity" />. 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 <see cref="WindowsIdentity"/>. Please note that the account that instantiates this class
|
||||||
|
/// needs to have the 'Act as part of operating system' privilege set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identityToImpersonate">The identity to impersonate.</param>
|
/// <param name="identityToImpersonate">The identity to impersonate.</param>
|
||||||
public WindowsImpersonatedIdentity(WindowsIdentity identityToImpersonate)
|
public WindowsImpersonatedIdentity(WindowsIdentity identityToImpersonate) : base(identityToImpersonate) => impersonationContext = AuthenticatedIdentity.Impersonate();
|
||||||
{
|
|
||||||
identity = identityToImpersonate;
|
|
||||||
impersonationContext = identity.Impersonate();
|
|
||||||
ownId = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||||
public void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
impersonationContext?.Undo();
|
impersonationContext?.Undo();
|
||||||
if (ownId) identity?.Dispose();
|
base.Dispose();
|
||||||
identity = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Gets the authenticated identity.</summary>
|
|
||||||
public WindowsIdentity AuthenticatedIdentity => identity;
|
|
||||||
|
|
||||||
/// <summary>Gets the type of authentication used.</summary>
|
|
||||||
string IIdentity.AuthenticationType => identity?.AuthenticationType;
|
|
||||||
|
|
||||||
/// <summary>Gets a value that indicates whether the user has been authenticated.</summary>
|
|
||||||
bool IIdentity.IsAuthenticated => identity?.IsAuthenticated ?? false;
|
|
||||||
|
|
||||||
/// <summary>Gets the name of the current user.</summary>
|
|
||||||
string IIdentity.Name => identity?.Name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using static Vanara.PInvoke.AdvApi32;
|
||||||
|
|
||||||
|
namespace Vanara.Security.Principal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public class WindowsLoggedInIdentity : IDisposable, IIdentity
|
||||||
|
{
|
||||||
|
private readonly SafeHTOKEN hToken;
|
||||||
|
private readonly bool ownId = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userName">
|
||||||
|
/// 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 <paramref name="domainName"/> parameter must be NULL.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="domainName">
|
||||||
|
/// A string that specifies the name of the domain or server whose account database contains the <paramref name="userName"/> 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.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="password">A string that specifies the plain-text password for the user account specified by <paramref name="userName"/>.</param>
|
||||||
|
/// <param name="logonType">
|
||||||
|
/// 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.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="provider">
|
||||||
|
/// 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.
|
||||||
|
/// </param>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the impersonation with the given <see cref="WindowsIdentity"/>. Please note that the account that instantiates this class
|
||||||
|
/// needs to have the 'Act as part of operating system' privilege set.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identityToImpersonate">The identity to impersonate.</param>
|
||||||
|
public WindowsLoggedInIdentity(WindowsIdentity identityToImpersonate)
|
||||||
|
{
|
||||||
|
AuthenticatedIdentity = identityToImpersonate;
|
||||||
|
ownId = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Gets the authenticated identity.</summary>
|
||||||
|
public WindowsIdentity AuthenticatedIdentity { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>Gets the type of authentication used.</summary>
|
||||||
|
string IIdentity.AuthenticationType => AuthenticatedIdentity?.AuthenticationType;
|
||||||
|
|
||||||
|
/// <summary>Gets a value that indicates whether the user has been authenticated.</summary>
|
||||||
|
bool IIdentity.IsAuthenticated => AuthenticatedIdentity?.IsAuthenticated ?? false;
|
||||||
|
|
||||||
|
/// <summary>Gets the name of the current user.</summary>
|
||||||
|
string IIdentity.Name => AuthenticatedIdentity?.Name;
|
||||||
|
|
||||||
|
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
if (ownId) AuthenticatedIdentity?.Dispose();
|
||||||
|
hToken?.Dispose();
|
||||||
|
AuthenticatedIdentity = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue