Last active
May 6, 2024 09:47
-
-
Save project0/61c13130563cf7f595e031d54fe55aab to your computer and use it in GitHub Desktop.
Go AD password reset
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package passwordresetservice | |
import ( | |
"crypto/tls" | |
"fmt" | |
ldap "github.com/go-ldap/ldap" | |
"golang.org/x/text/encoding/unicode" | |
ber "gopkg.in/asn1-ber.v1" | |
) | |
// need at least v3 of library | |
const ( | |
ldapAttrAccountName = "sAMAccountName" | |
ldapAttrDN = "dn" | |
ldapAttrUAC = "userAccountControl" | |
ldapAttrUPN = "userPrincipalName" // username@logon.domain | |
ldapAttrEmail = "mail" | |
ldapAttrUnicodePw = "unicodePwd" | |
controlTypeLdapServerPolicyHints = "1.2.840.113556.1.4.2239" | |
controlTypeLdapServerPolicyHintsDeprecated = "1.2.840.113556.1.4.2066" | |
) | |
type ( | |
// ldapControlServerPolicyHints implements ldap.Control | |
ldapControlServerPolicyHints struct { | |
oid string | |
} | |
) | |
// GetControlType implements ldap.Control | |
func (c *ldapControlServerPolicyHints) GetControlType() string { | |
return c.oid | |
} | |
// Encode implements ldap.Control | |
func (c *ldapControlServerPolicyHints) Encode() *ber.Packet { | |
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") | |
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.GetControlType(), "Control Type (LDAP_SERVER_POLICY_HINTS_OID)")) | |
packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, true, "Criticality")) | |
p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Policy Hints)") | |
seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PolicyHintsRequestValue") | |
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 1, "Flags")) | |
p2.AppendChild(seq) | |
packet.AppendChild(p2) | |
return packet | |
} | |
// String implements ldap.Control | |
func (c *ldapControlServerPolicyHints) String() string { | |
return "Enforce password history policies during password set: " + c.GetControlType() | |
} | |
// ChangePassword modifies the user password of a user | |
func ChangePassword(userdn string, password string) error { | |
// requires ldaps connection | |
conn, err = ldap.DialTLS("tcp", "contoso.local:636", &tls.Config{ | |
InsecureSkipVerify: false, | |
ServerName: "contoso.local", | |
}) | |
if err != nil { | |
return err | |
} | |
defer conn.Close() | |
// PasswordModify does not work with AD | |
// https://github.com/go-ldap/ldap/issues/106 | |
// request := ldap.NewPasswordModifyRequest(username, "", password) | |
// _, err = conn.PasswordModify(request) | |
utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) | |
// The password needs to be enclosed in quotes | |
pwdEncoded, err := utf16.NewEncoder().String(fmt.Sprintf("\"%s\"", password)) | |
if err != nil { | |
return err | |
} | |
// add additional control to request if supported | |
controlTypes, err := getSupportedControl(conn) | |
if err != nil { | |
return err | |
} | |
control := []ldap.Control{} | |
for _, oid := range controlTypes { | |
if oid == controlTypeLdapServerPolicyHints || oid == controlTypeLdapServerPolicyHintsDeprecated { | |
control = append(control, &ldapControlServerPolicyHints{oid: oid}) | |
break | |
} | |
} | |
passReq := ldap.NewModifyRequest(userdn, control) | |
passReq.Replace(ldapAttrUnicodePw, []string{pwdEncoded}) | |
return onn.Modify(passReq) | |
} | |
// getSupportedControl retrieves supported extended control types | |
func getSupportedControl(conn ldap.Client) ([]string, error) { | |
req := ldap.NewSearchRequest("", ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", []string{"supportedControl"}, nil) | |
res, err := conn.Search(req) | |
if err != nil { | |
return nil, err | |
} | |
return res.Entries[0].GetAttributeValues("supportedControl"), nil | |
} |
utf16 := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) pwdEncoded, err := utf16.NewEncoder().String(fmt.Sprintf("\"%s\"", newPassword))I Working with
AWS Managed Microsoft AD
, using LDAP (not LDAPS), and I succeed to get list of users for example.... but I can't change user password successfully.
Update: Active Directory Require to use secure connection in order to change users passwords (Like: LDAPS, NTLM or Kerberos).
From Microsoft Docs: Change a Windows Active Directory and LDS user password through LDAP
In order to modify this attribute, the client must have a 128-bit Transport Layer Security (TLS)/Secure Socket Layer (SSL) connection to the server.
The "attribute" they are referring to is "unicodePwd"
.
LDAP Result Code 53 "Unwilling To Perform": 0000001F: SvcErr: DSID-031A12E8, problem 5003 (WILL_NOT_PERFORM), data 0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I got
LDAP Result Code 32 "No Such Object": 0000208D: NameErr: DSID-0310020A, problem 2001(NO_OBJECT), data 0
. I tried to use "sAMAccountName" as useDN, but did't work as well.And I' using it without tls.