可以使用LDAP协议更改AD用户的密码。但是,如果用户在下次登录时必须更改其密码(或密码已过期),则除非使用管理员凭据才能更改密码。通过使用WIN32 API,我能够解决此问题in the past。不幸的是,我不能在Linux环境中使用WINAPI。
根据this article:
当用户通过按CTRL + ALT + DELETE然后单击“更改密码”来更改其自己的密码时,如果目标是域,则从Windows NT到Windows 2003(直到Windows 2003)都使用NetUserChangePassword机制(方法1)。 从Windows Vista开始,Kerberos更改密码协议用于域帐户。如果目标是Kerberos领域,则使用Kerberos更改密码协议(方法3)。
我寻找了可以在.NET Core上运行的Kerberos客户端,并且发现了SteveSyfuhs/Kerberos.NET
。
通过阅读Kerberos Change Password Protocol和Kerberos.NET Samples,我编写了以下代码:
using Kerberos.NET;
using Kerberos.NET.Client;
using Kerberos.NET.Credentials;
using Kerberos.NET.Crypto;
using Kerberos.NET.Entities;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace KerberosDemo
{
class Program
{
static async Task Main(string[] args)
{
string activeDirectoryServer = "10.12.34.56:88"; // kdc port
string domain = "TEST.LOCAL";
string username = "testuser@" + domain;
string oldPassword = "123";
string newPassword = "456";
using var client = new KerberosClient(activeDirectoryServer);
var kerbCred = new KerberosPasswordCredential(username, oldPassword, domain);
await client.Authenticate(kerbCred);
var serviceTicket = await client.GetServiceTicket("kadmin/changepw");
var apReq = new KrbApReq
{
Ticket = serviceTicket.Ticket,
Authenticator = KrbEncryptedData.Encrypt(Encoding.UTF8.GetBytes(newPassword).AsMemory(), kerbCred.CreateKey(), KeyUsage.ApReqAuthenticator),
ProtocolVersionNumber = 1
};
var tcp = client.Transports.FirstOrDefault(t => t.Protocol == ProtocolType.Tcp);
await tcp.SendMessage<KrbApReq, KrbAsRep>(domain, apReq);
}
}
}
我在await tcp.SendMessage<KrbApReq, KrbAsRep>(domain, apReq);
遇到以下异常:
未处理的异常。 System.Security.Cryptography.CryptographicException:ASN1损坏 数据。在 System.Security.Cryptography.Asn1.AsnReader.ReadTagAndLength(可空
1& contentsLength, Int32& bytesRead) in d:\a\1\s\Kerberos.NET\Asn1\Experimental\AsnReader.cs:line 305 at Kerberos.NET.Entities.KrbError.CanDecode(ReadOnlyMemory
1编码)在 d:\ a \ 1 \ s \ Kerberos.NET \ Entities \ Krb \ KrbError.cs:第23行位于 Kerberos.NET.Transport.KerberosTransportBase.Decode [T](ReadOnlyMemory1 response) in d:\a\1\s\Kerberos.NET\Client\Transport\KerberosTransportBase.cs:line 41 at Kerberos.NET.Transport.TcpKerberosTransport.ReadResponse[T](NetworkStream stream, CancellationToken cancellation) in d:\a\1\s\Kerberos.NET\Client\Transport\TcpKerberosTransport.cs:line 69 at Kerberos.NET.Transport.TcpKerberosTransport.SendMessage[T](String domain, ReadOnlyMemory
1编码,取消了CancellationToken) d:\ a \ 1 \ s \ Kerberos.NET \ Client \ Transport \ TcpKerberosTransport.cs:第58行 在KerberosDemo.Program.Main(String [] args)处 KerberosDemo.Program。(String [] args)
感谢您的帮助。谢谢。
答案 0 :(得分:1)
我也可以将其写成答案。
如果用户在下次登录时必须更改密码(或密码已过期),那么除非使用管理员凭据,否则无法更改密码
如果您使用用户自己的凭据对AD进行身份验证,这可能是一个问题,这是验证用户凭据的一种常用方法。如果用户密码已过期(或专门设置为在下次登录时强制更改),则身份验证将失败,并且将阻止您查找用户帐户和更改密码。
要解决此问题,您可以使用其他帐户向AD进行身份验证。 它不必是管理员帐户。任何域凭据都可以。然后,您可以查找用户的帐户。
由于您必须知道旧密码才能更改密码,因此AD认为 您需要更改它的所有授权。
与重置密码不同,在该情况下,您需要一个对该帐户具有“重置密码”权限的帐户。
并且您发现,还需要安全地连接到AD,以便新密码不会以纯文本形式发送。