问题描述
在.NET应用程序,我试图验证通过用户名和密码的用户对Windows用户来说,本地的和域用户。 。我的代码来获取PrincipalContext看起来如下:
受保护的静态PrincipalContext TryCreatePrincipalContext(字符串域)
{
变种computerDomain = TryGetComputerDomain();
如果(String.IsNullOrEmpty(域)及和放大器; String.IsNullOrEmpty(computerDomain))
返回新PrincipalContext(ContextType.Machine);
,否则如果(String.IsNullOrEmpty(域))
返回新PrincipalContext(ContextType.Domain,computerDomain);
,否则
返回新PrincipalContext(ContextType.Domain,域);
}
受保护的静态字符串TryGetComputerDomain()
{
试
{
VAR域= Domain.GetComputerDomain();
返回domain.Name;
}赶上
{
返回NULL;
}
}
这对于本地Windows用户的用户和远程工作正常用户在ActiveDirectory中。但是,如果我尝试运行的机器上的认证,也加入到非的ActiveDirectory域主,例如。 Samba服务器出现以下异常:
System.DirectoryServices.AccountManagement.PrincipalServerDownException:麻省理工学院的马克服务器konnte keine Verbindung hergestellt werden。 --->
System.DirectoryServices.Protocols.LdapException:明镜LDAP服务器IST nichtverfügbar。
贝System.DirectoryServices.Protocols.LdapConnection.Connect()
贝System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest请求的Int32&安培; MESSAGEID)
贝System.DirectoryServices.Protocols.LdapConnection .SendRequest(DirectoryRequest要求,时间跨度将requestTimeout)
贝System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest要求)
贝System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(字符串服务器名,ServerProperties和放大器;属性)
---电恩德德internenAusnahmestapelüberwachung---
贝System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(字符串服务器名,ServerProperties和放大器;属性)
贝System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval( )
贝System.DirectoryServices.AccountManagement.PrincipalContext..ctor(contextType contextType,字符串名称,字符串容器,ContextOptions选项,用户名字符串,字符串密码)
贝System.DirectoryServices.AccountManagement.PrincipalContext..ctor (contextType contextType,字符串名称)
贝DomainAuthTest.DomainAuthenticator.TryCreatePrincipalContext(字符串域)
贝DomainAuthTest.DomainAuthenticator.Authenticate(字符串domainUser,字符串密码)
贝DomainAuthTest.Program.Main(字符串[]参数)
如此看来,在PrincipalContext试图在ContextType.Domain的情况下使用LDAP。如果我尝试使用ContextType.Machine我无法使用工作组/域名为PrincipalContext尝试直接连接到本机。 。那如果已经有一个来自同一台计算机的窗口到该计算机连接失败
所以我的问题是:
- 如何使用针对域主凭据域,用户名和密码,这不一定是基于一个ActiveDirectory的用户进行身份验证?
- 是有管理的API来完成上述任务?
- 如果没有管理基础类,什么是做与?
右方向UL>
感谢您的答复。
有关完整起见,在这里我的解决方案,它似乎做正是我想要的:
公共类WinApiDomainAuthenticator
{
函数[DllImport (ADVAPI32.DLL,SetLastError = TRUE)]
公共静态的extern BOOL LogonUser的(字符串lpszUsername,
串lpszDomain,
串lpszPassword,
INT dwLogonType,
INT dwLogonProvider,
OUT的IntPtr phToken);
函数[DllImport(KERNEL32.DLL,字符集= CharSet.Auto)]
公众的extern静态布尔CloseHandle的(IntPtr的手柄);
公共静态的IPrincipal进行身份验证(字符串domainUser,字符串密码)
{
VAR userToken = IntPtr.Zero;
变种creds =新DomainAuthCredentials(domainUser,密码);
如果(!LogonUser的(creds.Username,
creds.Domain,
creds.Password,
(INT)LogonType.LOGON32_LOGON_BATCH,
(INT )LogonProvider.LOGON32_PROVIDER_DEFAULT,出userToken))
{
VAR误差=新Win32Exception(Marshal.GetLastWin32Error());
抛出新SecurityException异常(错误而认证用户,错误);
}
变种标识=新的WindowsIdentity(userToken);
如果(userToken = IntPtr.Zero!)
CloseHandle的(userToken);
返回ConvertWindowsIdentityToGenericPrincipal(身份);
}
保护静态的IPrincipal ConvertWindowsIdentityToGenericPrincipal(的WindowsIdentity的WindowsIdentity)
{
如果(的WindowsIdentity == NULL)
返回NULL;
//认同格式DOMAIN\Username
变种标识=新的GenericIdentity(windowsIdentity.Name);
VAR组名=新的字符串[0];
如果(windowsIdentity.Groups!= NULL)
格式DOMAIN\Group $ B $ {
//阵列组,名称乙组名= windowsIdentity.Groups
。选择(GID => gId.Translate(typeof运算(NTACCOUNT)))
。选择(GNT => gNt.ToString())
.ToArray();
}
变种的GenericPrincipal =新的GenericPrincipal(标识,组名);
回报率的GenericPrincipal;
}
类保护DomainAuthCredentials
{
公共DomainAuthCredentials(字符串domainUser,字符串密码)
{
=用户名domainUser;
密码=密码;
结构域=;
如果
回报率(domainUser.Contains(@\)!);
VAR令牌= domainUser.Split(新的char [] {'\\'},2);
结构域=令牌[0];
用户名=令牌[1];
}
公共DomainAuthCredentials()
{
区=的String.Empty;
}
#区域属性
公共字符串域{搞定;组; }
公共字符串用户名{搞定;组; }
公共字符串密码{搞定;组; }
#endregion
}
}
的登录类型和LogonProvider枚举反映WINBASE.H的定义。我LogonType.LOGON32_LOGON_BATCH代替LogonType.LOGON32_LOGON_NETWORK定居,因为桑巴3.4.X似乎与这种类型的麻烦。
in an .NET application, I'm trying to authenticate users by username and password a against windows users, local ones as well as domain users. I already tried this solution . My code to get the PrincipalContext looks the following:
protected static PrincipalContext TryCreatePrincipalContext(String domain)
{
var computerDomain = TryGetComputerDomain();
if (String.IsNullOrEmpty(domain) && String.IsNullOrEmpty(computerDomain))
return new PrincipalContext(ContextType.Machine);
else if (String.IsNullOrEmpty(domain))
return new PrincipalContext(ContextType.Domain, computerDomain);
else
return new PrincipalContext(ContextType.Domain, domain);
}
protected static String TryGetComputerDomain()
{
try
{
var domain = Domain.GetComputerDomain();
return domain.Name;
} catch
{
return null;
}
}
That works fine for local windows users users and for remote users in an ActiveDirectory. But if I try to run the authentication on a machine, that is joined to a non-ActiveDirectory Domain Master, eg. a Samba Server I get the following Exception:
System.DirectoryServices.AccountManagement.PrincipalServerDownException: Mit dem Server konnte keine Verbindung hergestellt werden. --->
System.DirectoryServices.Protocols.LdapException: Der LDAP-Server ist nicht verfügbar.
bei System.DirectoryServices.Protocols.LdapConnection.Connect()
bei System.DirectoryServices.Protocols.LdapConnection.SendRequestHelper(DirectoryRequest request, Int32& messageID)
bei System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
bei System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request)
bei System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
--- Ende der internen Ausnahmestapelüberwachung ---
bei System.DirectoryServices.AccountManagement.PrincipalContext.ReadServerConfig(String serverName, ServerProperties& properties)
bei System.DirectoryServices.AccountManagement.PrincipalContext.DoServerVerifyAndPropRetrieval()
bei System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name, String container, ContextOptions options, String userName, String password)
bei System.DirectoryServices.AccountManagement.PrincipalContext..ctor(ContextType contextType, String name)
bei DomainAuthTest.DomainAuthenticator.TryCreatePrincipalContext(String domain)
bei DomainAuthTest.DomainAuthenticator.Authenticate(String domainUser, String password)
bei DomainAuthTest.Program.Main(String[] args)
So it seems that the PrincipalContext tries to use LDAP in case of ContextType.Domain. If I try to use ContextType.Machine I have cannot use the workgroup/domain-name as PrincipalContext tries to connect directly to the machine. That fails if there is already a connection to that machine with that windows from the same machine.
So my question is:
- How to authenticate a user with the credentials domain, username and password against a domain master, which is not necessarily based on an ActiveDirectory?
- Are there managed APIs to accomplish the above described task?
- If there are no managed foundation-classes, what is the right direction to do that with?
Thank you for your replies.
For the sake of completeness, here my solution which seems to do exactly what I want:
public class WinApiDomainAuthenticator
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
public static IPrincipal Authenticate(String domainUser, String password)
{
var userToken = IntPtr.Zero;
var creds = new DomainAuthCredentials(domainUser, password);
if (! LogonUser(creds.Username,
creds.Domain,
creds.Password,
(int)LogonType.LOGON32_LOGON_BATCH,
(int)LogonProvider.LOGON32_PROVIDER_DEFAULT, out userToken))
{
var error = new Win32Exception(Marshal.GetLastWin32Error());
throw new SecurityException("Error while authenticating user", error);
}
var identity = new WindowsIdentity(userToken);
if (userToken != IntPtr.Zero)
CloseHandle(userToken);
return ConvertWindowsIdentityToGenericPrincipal(identity);
}
protected static IPrincipal ConvertWindowsIdentityToGenericPrincipal(WindowsIdentity windowsIdentity)
{
if (windowsIdentity == null)
return null;
// Identity in format DOMAIN\Username
var identity = new GenericIdentity(windowsIdentity.Name);
var groupNames = new string[0];
if (windowsIdentity.Groups != null)
{
// Array of Group-Names in format DOMAIN\Group
groupNames = windowsIdentity.Groups
.Select(gId => gId.Translate(typeof(NTAccount)))
.Select(gNt => gNt.ToString())
.ToArray();
}
var genericPrincipal = new GenericPrincipal(identity, groupNames);
return genericPrincipal;
}
protected class DomainAuthCredentials
{
public DomainAuthCredentials(String domainUser, String password)
{
Username = domainUser;
Password = password;
Domain = ".";
if (!domainUser.Contains(@"\"))
return;
var tokens = domainUser.Split(new char[] { '\\' }, 2);
Domain = tokens[0];
Username = tokens[1];
}
public DomainAuthCredentials()
{
Domain = String.Empty;
}
#region Properties
public String Domain { get; set; }
public String Username { get; set; }
public String Password { get; set; }
#endregion
}
}
The LogonType and LogonProvider enums reflect the definitions in "Winbase.h". I settled with LogonType.LOGON32_LOGON_BATCH instead of LogonType.LOGON32_LOGON_NETWORK because samba 3.4.X seems to have trouble with this type.
这篇关于验证对域控制器的用户凭据.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!