open-vault/vendor/github.com/go-ldap/ldap/passwdmodify.go

149 lines
5.3 KiB
Go
Raw Normal View History

2015-06-29 21:50:55 +00:00
// This file contains the password modify extended operation as specified in rfc 3062
//
// https://tools.ietf.org/html/rfc3062
//
package ldap
import (
"errors"
"fmt"
"gopkg.in/asn1-ber.v1"
)
const (
passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
)
2016-07-23 00:11:47 +00:00
// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt
2015-06-29 21:50:55 +00:00
type PasswordModifyRequest struct {
2016-07-23 00:11:47 +00:00
// UserIdentity is an optional string representation of the user associated with the request.
// This string may or may not be an LDAPDN [RFC2253].
// If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session
2015-06-29 21:50:55 +00:00
UserIdentity string
2016-07-23 00:11:47 +00:00
// OldPassword, if present, contains the user's current password
OldPassword string
// NewPassword, if present, contains the desired password for this user
NewPassword string
2015-06-29 21:50:55 +00:00
}
2016-07-23 00:11:47 +00:00
// PasswordModifyResult holds the server response to a PasswordModifyRequest
2015-06-29 21:50:55 +00:00
type PasswordModifyResult struct {
2016-07-23 00:11:47 +00:00
// GeneratedPassword holds a password generated by the server, if present
2015-06-29 21:50:55 +00:00
GeneratedPassword string
}
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))
extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")
passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")
if r.UserIdentity != "" {
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity"))
}
if r.OldPassword != "" {
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password"))
}
if r.NewPassword != "" {
passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password"))
}
extendedRequestValue.AppendChild(passwordModifyRequestValue)
request.AppendChild(extendedRequestValue)
return request, nil
}
2016-07-23 00:11:47 +00:00
// NewPasswordModifyRequest creates a new PasswordModifyRequest
2015-06-29 21:50:55 +00:00
//
// According to the RFC 3602:
// userIdentity is a string representing the user associated with the request.
// This string may or may not be an LDAPDN (RFC 2253).
// If userIdentity is empty then the operation will act on the user associated
// with the session.
//
// oldPassword is the current user's password, it can be empty or it can be
// needed depending on the session user access rights (usually an administrator
// can change a user's password without knowing the current one) and the
// password policy (see pwdSafeModify password policy's attribute)
//
// newPassword is the desired user's password. If empty the server can return
// an error or generate a new password that will be available in the
// PasswordModifyResult.GeneratedPassword
//
func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
return &PasswordModifyRequest{
UserIdentity: userIdentity,
OldPassword: oldPassword,
NewPassword: newPassword,
}
}
2016-07-23 00:11:47 +00:00
// PasswordModify performs the modification request
2015-06-29 21:50:55 +00:00
func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
2016-06-30 18:19:03 +00:00
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
2015-06-29 21:50:55 +00:00
encodedPasswordModifyRequest, err := passwordModifyRequest.encode()
if err != nil {
return nil, err
}
packet.AppendChild(encodedPasswordModifyRequest)
l.Debug.PrintPacket(packet)
2016-06-30 18:19:03 +00:00
msgCtx, err := l.sendMessage(packet)
2015-06-29 21:50:55 +00:00
if err != nil {
return nil, err
}
2016-06-30 18:19:03 +00:00
defer l.finishMessage(msgCtx)
2015-06-29 21:50:55 +00:00
result := &PasswordModifyResult{}
2016-06-30 18:19:03 +00:00
l.Debug.Printf("%d: waiting for response", msgCtx.id)
packetResponse, ok := <-msgCtx.responses
2016-04-26 00:18:04 +00:00
if !ok {
2016-06-30 18:19:03 +00:00
return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
2016-04-26 00:18:04 +00:00
}
packet, err = packetResponse.ReadPacket()
2016-06-30 18:19:03 +00:00
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
2016-04-26 00:18:04 +00:00
if err != nil {
return nil, err
}
2015-06-29 21:50:55 +00:00
if packet == nil {
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}
if packet.Children[1].Tag == ApplicationExtendedResponse {
resultCode, resultDescription := getLDAPResultCode(packet)
if resultCode != 0 {
return nil, NewError(resultCode, errors.New(resultDescription))
}
} else {
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
}
extendedResponse := packet.Children[1]
for _, child := range extendedResponse.Children {
if child.Tag == 11 {
passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes())
if len(passwordModifyReponseValue.Children) == 1 {
if passwordModifyReponseValue.Children[0].Tag == 0 {
result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes())
}
}
}
}
return result, nil
}