域网络外部的LDAP重置密码C#错误:RPC服务器不可用。(来自hresult的异常:0x800706ba)

域网络外部的LDAP重置密码C#错误:RPC服务器不可用。(来自hresult的异常:0x800706ba),c#,asp.net,asp.net-core,authentication,ldap,C#,Asp.net,Asp.net Core,Authentication,Ldap,我们正在尝试重置LDAP密码,它在开发环境中工作,但在生产环境中不工作 我们的开发环境在域内,生产环境在域外 在连接LDAP的开发过程中,我们使用了像abc.com这样的域名和我们使用的生产环境IPaddress:389,这两种环境中的LDAP用户身份验证都已经在使用。但不适用于LDAP重置密码 Error: RPC server is unavailable. (exception from hresult: 0x800706ba) 开发:(工作) PrincipalContext Prin

我们正在尝试重置LDAP密码,它在开发环境中工作,但在生产环境中不工作

我们的开发环境在域内,生产环境在域外

在连接LDAP的开发过程中,我们使用了像
abc.com
这样的域名和我们使用的生产环境
IPaddress:389
,这两种环境中的LDAP用户身份验证都已经在使用。但不适用于LDAP重置密码

Error: RPC server is unavailable. (exception from hresult: 0x800706ba)
开发:(工作)

PrincipalContext PrincipalContext=
新PrincipalContext(ContextType.Domain,“,容器:”,
"", "");
UserPrincipal user=UserPrincipal.FindByIdentity(principalContext,“”);
//“”和“”是管理凭据。
bool isValid=user.ValidateCredentials(“,”);
_Log($”是连接:{isValid}”);
**//输出:连接是否为真**
user.UserCannotChangePassword=false;
user.SetPassword(“”);
//密码已成功重置。
生产:(工作) 此外,我们正在使用以下方法对LDAP用户进行身份验证,该方法将用于生产:

检查用户是否具有LDAP帐户:

// "<username>", "<password>" are Administrative credential.
var entry = new DirectoryEntry($"LDAP://{"<IP:389>"}", "<username>", "<password>",
    AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind);
var search = new DirectorySearcher(entry);
var strFilter = $"(mail={"<UserEmailId>"})";
search.Filter = strFilter;
var result = await Task.Run(() => search.FindOne());
if (result != null)
{
    //IsLdapUser = true;
    //result.Properties["samaccountname"][0]);
}
else
{
    //IsLdapUser = false;
}
// Successfully


// Authenticate LDAP user:
var ldapConnection = new LdapConnection(new LdapDirectoryIdentifier("<IP:389>", false, false));                    
var nc = new NetworkCredential("<LdapUserName>", "<LdapUserPassword>", "<IP:389>");
ldapConnection.Credential = nc;
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(nc);
// Successfully

/“,”是管理凭据。
var entry=new DirectoryEntry($“LDAP://{”}、“”、“”、,
AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind);
var search=新的DirectorySearcher(条目);
var strFilter=$“(邮件={”“})”;
search.Filter=strFilter;
var result=wait Task.Run(()=>search.FindOne());
如果(结果!=null)
{
//IsLdapUser=true;
//result.Properties[“samaccountname”][0]);
}
其他的
{
//IsLdapUser=false;
}
//成功地
//验证LDAP用户:
var ldapConnection=new ldapConnection(new LdapDirectoryIdentifier(“,false,false));
var nc=新的网络凭证(“,”,“);
ldapConnection.Credential=nc;
ldapConnection.AuthType=AuthType.Negotiate;
ldapConnection.Bind(nc);
//成功地
生产:(不工作)

/“,”是管理凭据。
PrincipalContext PrincipalContext=
新PrincipalContext(ContextType.Domain,“,容器:”,
"", "");
UserPrincipal user=UserPrincipal.FindByIdentity(principalContext,“”);
bool isValid=user.ValidateCredentials(“,”);
_Log($”是连接:{isValid}”);
**//输出:连接是否为真**
user.UserCannotChangePassword=false;
user.SetPassword(“”);
//错误:RPC服务器不可用。(来自hresult的异常:0x800706ba)
还尝试了以下代码(不工作)

/“,”是管理凭据。
DirectoryEntry de=新的DirectoryEntry(“,”,“,”,
AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind);
//LDAP搜索筛选器
DirectorySearcher ds=新的DirectorySearcher(de);
ds.Filter=“(&(objectClass=user)(|(sAMAccountName=“+”“+”)))”;
//要加载的LDAP属性
ds.PropertiesToLoad.Add(“displayName”);
ds.PropertiesToLoad.Add(“sAMAccountName”);
ds.PropertiesToLoad.Add(“区分名称”);
ds.PropertiesToLoad.Add(“CN”);
//执行搜索
SearchResult=wait Task.Run(()=>ds.FindOne());
字符串dn=result.Properties[“DifferentizedName”][0].ToString();
DirectoryEntry=result.GetDirectoryEntry();
Invoke(“SetPassword”,新对象[]{”“})//设置新密码
委托变更();
关闭();
//错误:RPC服务器不可用。(来自hresult的异常:0x800706ba)

用于修改密码的属性为。该文档揭示了更改密码必须满足的一些条件。首先,必须对连接进行加密

调用
.Invoke(“SetPassword”,…)
实际上调用本机Windows方法。该文档显示,它会自动尝试几种不同的加密方式。发生异常是因为这些方法都不起作用

实际上,您可以直接修改
unicodePwd
属性,而无需调用
SetPassword
,我将介绍这一点,但无论如何,您必须首先解决加密问题

当您从网络中的计算机运行此操作时,
AuthenticationTypes.Sealing
就足够了。其效果是,它使用Kerberos加密连接

但是,当您从域外连接时,Kerberos将无法工作(可能需要努力才能工作-我不是Kerberos专家)。因此,唯一可用的加密方法是SSL。
SetPassword
方法实际上尝试使用SSL,但显然不起作用

我马上看到的一个问题是,您正在使用IP地址连接到DC,而SSL使用IP地址无法工作,因为SSL证书上的域名必须与您用于访问服务器的名称匹配,并且SSL证书上不会有IP地址。因此,您必须更改该名称才能使用域名。如果DNS无法解析该名称,您可以将其添加到主机文件中

改变可能会解决一切。如果没有,可能还有两个问题:

  • 无法访问端口636(途中有防火墙)
  • 运行此操作的计算机上不信任SSL证书
  • SSL上的LDAP(LDAPS)在端口636上工作。您可以在PowerShell中测试此连接:

    Test-NetConnection example.com -Port 636
    
    如果失败,请先修复

    接下来,检查证书。您可以使用以下PowerShell脚本下载证书:

    $webRequest = [Net.WebRequest]::Create("https://example.com:636")
    try { $webRequest.GetResponse() } catch {}
    $cert = $webRequest.ServicePoint.Certificate
    $bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
    set-content -value $bytes -encoding byte -path "certificate.cer"
    
    将第一行中的
    example.com
    更改为您的域名(保留
    https://
    :636
    )。然后,您将在当前目录中有一个名为
    certificate.cer
    的文件,您可以打开并检查该文件。如果它不受信任,它将警告您。如果它不可信,t
    // "<username>", "<password>" are Administrative credential.
    DirectoryEntry de = new DirectoryEntry("<IP:389>","<username>", "<password>", 
    AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.ServerBind);
    // LDAP Search Filter
    DirectorySearcher ds = new DirectorySearcher(de);
    ds.Filter = "(&(objectClass=user)(|(sAMAccountName=" + "<LdapUserName>"+ ")))";
    
    // LDAP Properties to Load
    ds.PropertiesToLoad.Add("displayName");
    ds.PropertiesToLoad.Add("sAMAccountName");
    ds.PropertiesToLoad.Add("DistinguishedName");
    ds.PropertiesToLoad.Add("CN");
    
    // Execute Search
    SearchResult result = await Task.Run(() => ds.FindOne());
    
    string dn = result.Properties["DistinguishedName"][0].ToString();
    
    DirectoryEntry uEntry = result.GetDirectoryEntry();
    
    uEntry.Invoke("SetPassword", new object[] { "<NewPassword>"});  //Set New Password                        
    uEntry.CommitChanges();
    uEntry.Close();
    // Error: RPC server is unavailable. (exception from hresult: 0x800706ba)
    
    Test-NetConnection example.com -Port 636
    
    $webRequest = [Net.WebRequest]::Create("https://example.com:636")
    try { $webRequest.GetResponse() } catch {}
    $cert = $webRequest.ServicePoint.Certificate
    $bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
    set-content -value $bytes -encoding byte -path "certificate.cer"
    
    DirectoryEntry de = new DirectoryEntry("LDAP://dc1.example.com:636","<username>", "<password>", 
        AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.ServerBind);
    
    uEntry.Properties["unicodePwd"].Value = Encoding.Unicode.GetBytes("\"NewPassword\"");
    uEntry.CommitChanges();