github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/ldap.v2/passwdmodify.go (about) 1 // This file contains the password modify extended operation as specified in rfc 3062 2 // 3 // https://tools.ietf.org/html/rfc3062 4 // 5 6 package ldap 7 8 import ( 9 "errors" 10 "fmt" 11 12 "gopkg.in/asn1-ber.v1" 13 ) 14 15 const ( 16 passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1" 17 ) 18 19 // PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt 20 type PasswordModifyRequest struct { 21 // UserIdentity is an optional string representation of the user associated with the request. 22 // This string may or may not be an LDAPDN [RFC2253]. 23 // If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session 24 UserIdentity string 25 // OldPassword, if present, contains the user's current password 26 OldPassword string 27 // NewPassword, if present, contains the desired password for this user 28 NewPassword string 29 } 30 31 // PasswordModifyResult holds the server response to a PasswordModifyRequest 32 type PasswordModifyResult struct { 33 // GeneratedPassword holds a password generated by the server, if present 34 GeneratedPassword string 35 } 36 37 func (r *PasswordModifyRequest) encode() (*ber.Packet, error) { 38 request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation") 39 request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID")) 40 extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request") 41 passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request") 42 if r.UserIdentity != "" { 43 passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity")) 44 } 45 if r.OldPassword != "" { 46 passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password")) 47 } 48 if r.NewPassword != "" { 49 passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password")) 50 } 51 52 extendedRequestValue.AppendChild(passwordModifyRequestValue) 53 request.AppendChild(extendedRequestValue) 54 55 return request, nil 56 } 57 58 // NewPasswordModifyRequest creates a new PasswordModifyRequest 59 // 60 // According to the RFC 3602: 61 // userIdentity is a string representing the user associated with the request. 62 // This string may or may not be an LDAPDN (RFC 2253). 63 // If userIdentity is empty then the operation will act on the user associated 64 // with the session. 65 // 66 // oldPassword is the current user's password, it can be empty or it can be 67 // needed depending on the session user access rights (usually an administrator 68 // can change a user's password without knowing the current one) and the 69 // password policy (see pwdSafeModify password policy's attribute) 70 // 71 // newPassword is the desired user's password. If empty the server can return 72 // an error or generate a new password that will be available in the 73 // PasswordModifyResult.GeneratedPassword 74 // 75 func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest { 76 return &PasswordModifyRequest{ 77 UserIdentity: userIdentity, 78 OldPassword: oldPassword, 79 NewPassword: newPassword, 80 } 81 } 82 83 // PasswordModify performs the modification request 84 func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) { 85 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") 86 packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) 87 88 encodedPasswordModifyRequest, err := passwordModifyRequest.encode() 89 if err != nil { 90 return nil, err 91 } 92 packet.AppendChild(encodedPasswordModifyRequest) 93 94 l.Debug.PrintPacket(packet) 95 96 msgCtx, err := l.sendMessage(packet) 97 if err != nil { 98 return nil, err 99 } 100 defer l.finishMessage(msgCtx) 101 102 result := &PasswordModifyResult{} 103 104 l.Debug.Printf("%d: waiting for response", msgCtx.id) 105 packetResponse, ok := <-msgCtx.responses 106 if !ok { 107 return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) 108 } 109 packet, err = packetResponse.ReadPacket() 110 l.Debug.Printf("%d: got response %p", msgCtx.id, packet) 111 if err != nil { 112 return nil, err 113 } 114 115 if packet == nil { 116 return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) 117 } 118 119 if l.Debug { 120 if err := addLDAPDescriptions(packet); err != nil { 121 return nil, err 122 } 123 ber.PrintPacket(packet) 124 } 125 126 if packet.Children[1].Tag == ApplicationExtendedResponse { 127 resultCode, resultDescription := getLDAPResultCode(packet) 128 if resultCode != 0 { 129 return nil, NewError(resultCode, errors.New(resultDescription)) 130 } 131 } else { 132 return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)) 133 } 134 135 extendedResponse := packet.Children[1] 136 for _, child := range extendedResponse.Children { 137 if child.Tag == 11 { 138 passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes()) 139 if len(passwordModifyReponseValue.Children) == 1 { 140 if passwordModifyReponseValue.Children[0].Tag == 0 { 141 result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes()) 142 } 143 } 144 } 145 } 146 147 return result, nil 148 }