使用Kerberos更改密码协议和.NET Core 3更改Active Directory密码

时间:2019-11-02 10:03:20

标签: c# .net .net-core active-directory kerberos

可以使用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 ProtocolKerberos.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](ReadOnlyMemory 1 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)

感谢您的帮助。谢谢。

1 个答案:

答案 0 :(得分:1)

我也可以将其写成答案。

  

如果用户在下次登录时必须更改密码(或密码已过期),那么除非使用管理员凭据,否则无法更改密码

如果您使用用户自己的凭据对AD进行身份验证,这可能是一个问题,这是验证用户凭据的一种常用方法。如果用户密码已过期(或专门设置为在下次登录时强制更改),则身份验证将失败,并且将阻止您查找用户帐户和更改密码。

要解决此问题,您可以使用其他帐户向AD进行身份验证。 它不必是管理员帐户。任何域凭据都可以。然后,您可以查找用户的帐户。

由于您必须知道旧密码才能更改密码,因此AD认为 您需要更改它的所有授权。

重置密码不同,在该情况下,您需要一个对该帐户具有“重置密码”权限的帐户。

并且您发现,还需要安全地连接到AD,以便新密码不会以纯文本形式发送。

所有这些都记录在documentation for the unicodePwd attribute中。