[英]System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
[英]LDAP reset password from outside the domain network C# Error: RPC server is unavailable. (exception from hresult: 0x800706ba)
我們正在嘗試重置 LDAP 密碼,它適用於開發環境,但不適用於生產環境。
我們的開發環境在域內,生產環境在域外。
在連接 LDAP 的開發中,我們使用了像abc.com
這樣的域名,在生產環境中我們使用了 IP 地址IPaddress:389
,它已經在兩種環境中用於 LDAP用戶身份驗證。 但不適用於LDAP 重置密碼。
Error: RPC server is unavailable. (exception from hresult: 0x800706ba)
發展:(工作)
PrincipalContext principalContext =
new PrincipalContext(ContextType.Domain, "<domain.com>", container: "<DC=domain,DC=com>",
"<username>", "<password>");
UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, "<LdapUserName>");
// "<username>", "<password>" are Administrative credential.
bool isValid = user.ValidateCredentials("<username>", "<password>");
_logger.Log($"Is Connection: {isValid}");
**// Output: Is Connection: True**
user.UserCannotChangePassword = false;
user.SetPassword("<NewPassword>");
// Password has been successfully reset.
生產:(工作)我們還使用以下方法對 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
生產:(不工作)
// "<username>", "<password>" are Administrative credential.
PrincipalContext principalContext =
new PrincipalContext(ContextType.Domain, "<IP:389>", container: "<DC=domain,DC=com>",
"<username>", "<password>");
UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, "<LdapUserName>");
bool isValid = user.ValidateCredentials("<username>", "<password>");
_logger.Log($"Is Connection: {isValid}");
**// Output: Is Connection: True**
user.UserCannotChangePassword = false;
user.SetPassword("<NewPassword>");
// Error: RPC server is unavailable. (exception from hresult: 0x800706ba)
還嘗試使用以下代碼(不工作)
// "<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)
用於修改密碼的屬性是unicodePwd
。 該文檔揭示了更改密碼必須滿足的一些條件。 首先,連接必須加密。
調用.Invoke("SetPassword", ...)
實際上調用本機 Windows IADsUser::SetPassword
方法。 該文檔顯示它會自動嘗試幾種不同的加密方式。 發生異常是因為這些方法均無效。
實際上,您可以直接修改unicodePwd
屬性,而無需調用SetPassword
,我將進行介紹,但無論如何,您必須先解決加密問題。
當您從 .network 內的計算機運行它時, AuthenticationTypes.Sealing
就足夠了。 正如文檔所說,效果是它使用 Kerberos 來加密連接。
但是當您從域外連接時,Kerberos 將不起作用(也許它會努力 - 我不是 Kerberos 專家)。 所以唯一可用的加密方法是SetPassword
方法實際上嘗試使用 SSL,但顯然它沒有用。
我馬上看到的一個問題是您正在使用 IP 地址連接到 DC,而 SSL 將無法使用 IP 地址,因為 SSL 證書上的域名名稱必須與您用於訪問的名稱匹配到服務器,SSL 證書上將沒有 IP 地址。 因此,您必須更改它才能使用域名。 如果 DNS 無法解析該名稱,您可以將其添加到您的主機文件中。
改變它可能會解決所有問題。 如果不是,可能還有另外兩個問題:
LDAP over SSL (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
的文件,您可以打開並檢查該文件。 如果它不受信任,它會警告您。 如果它不受信任,則您必須將根證書作為受信任的根證書安裝在服務器上。
如果它已被信任,請確保證書上的“頒發給:”域名與您用於連接的名稱相匹配。 在我們的環境中,SSL 證書位於每個域 controller ( dc1.example.com
) 的名稱中,而不是域名 ( example.com
)。 所以我必須針對特定域 controller 才能使 LDAPS 工作。
一旦你把所有這些都整理好,你的代碼就應該可以工作了。
如果您想直接更改unicodePwd
屬性而不是使用SetPassword
(它可能會或可能不會執行得更快),您將需要通過 SSL 建立原始連接。例如:
DirectoryEntry de = new DirectoryEntry("LDAP://dc1.example.com:636","<username>", "<password>",
AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.ServerBind);
如果您的目標是特定 DC,則僅使用AuthenticationTypes.ServerBind
。
然后你可以用它想要的非常具體的方式更新unicodePwd
屬性:
uEntry.Properties["unicodePwd"].Value = Encoding.Unicode.GetBytes("\"NewPassword\"");
uEntry.CommitChanges();
請注意,新密碼必須用引號引起來。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.