2016-11-04 01:16:01 +03:00
package ldap
import (
"fmt"
2020-10-15 22:27:33 +03:00
ber "github.com/go-asn1-ber/asn1-ber"
2016-11-04 01:16:01 +03:00
)
const (
passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
)
// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt
type PasswordModifyRequest struct {
// 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
UserIdentity string
// OldPassword, if present, contains the user's current password
OldPassword string
// NewPassword, if present, contains the desired password for this user
NewPassword string
}
// PasswordModifyResult holds the server response to a PasswordModifyRequest
type PasswordModifyResult struct {
// GeneratedPassword holds a password generated by the server, if present
GeneratedPassword string
2019-02-18 15:34:37 +03:00
// Referral are the returned referral
Referral string
2016-11-04 01:16:01 +03:00
}
2020-10-15 22:27:33 +03:00
func ( req * PasswordModifyRequest ) appendTo ( envelope * ber . Packet ) error {
pkt := ber . Encode ( ber . ClassApplication , ber . TypeConstructed , ApplicationExtendedRequest , nil , "Password Modify Extended Operation" )
pkt . AppendChild ( ber . NewString ( ber . ClassContext , ber . TypePrimitive , 0 , passwordModifyOID , "Extended Request Name: Password Modify OID" ) )
2016-11-04 01:16:01 +03:00
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" )
2020-10-15 22:27:33 +03:00
if req . UserIdentity != "" {
passwordModifyRequestValue . AppendChild ( ber . NewString ( ber . ClassContext , ber . TypePrimitive , 0 , req . UserIdentity , "User Identity" ) )
2016-11-04 01:16:01 +03:00
}
2020-10-15 22:27:33 +03:00
if req . OldPassword != "" {
passwordModifyRequestValue . AppendChild ( ber . NewString ( ber . ClassContext , ber . TypePrimitive , 1 , req . OldPassword , "Old Password" ) )
2016-11-04 01:16:01 +03:00
}
2020-10-15 22:27:33 +03:00
if req . NewPassword != "" {
passwordModifyRequestValue . AppendChild ( ber . NewString ( ber . ClassContext , ber . TypePrimitive , 2 , req . NewPassword , "New Password" ) )
2016-11-04 01:16:01 +03:00
}
extendedRequestValue . AppendChild ( passwordModifyRequestValue )
2020-10-15 22:27:33 +03:00
pkt . AppendChild ( extendedRequestValue )
envelope . AppendChild ( pkt )
return nil
2016-11-04 01:16:01 +03:00
}
// NewPasswordModifyRequest creates a new PasswordModifyRequest
//
2020-10-15 22:27:33 +03:00
// According to the RFC 3602 (https://tools.ietf.org/html/rfc3062):
2016-11-04 01:16:01 +03:00
// 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 ,
}
}
// PasswordModify performs the modification request
func ( l * Conn ) PasswordModify ( passwordModifyRequest * PasswordModifyRequest ) ( * PasswordModifyResult , error ) {
2020-10-15 22:27:33 +03:00
msgCtx , err := l . doRequest ( passwordModifyRequest )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
defer l . finishMessage ( msgCtx )
2020-10-15 22:27:33 +03:00
packet , err := l . readPacket ( msgCtx )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
2020-10-15 22:27:33 +03:00
result := & PasswordModifyResult { }
2016-11-04 01:16:01 +03:00
if packet . Children [ 1 ] . Tag == ApplicationExtendedResponse {
2019-02-18 15:34:37 +03:00
err := GetLDAPError ( packet )
if err != nil {
if IsErrorWithCode ( err , LDAPResultReferral ) {
for _ , child := range packet . Children [ 1 ] . Children {
if child . Tag == 3 {
result . Referral = child . Children [ 0 ] . Value . ( string )
}
}
}
return result , err
2016-11-04 01:16:01 +03:00
}
} else {
2019-02-18 15:34:37 +03:00
return nil , NewError ( ErrorUnexpectedResponse , fmt . Errorf ( "unexpected Response: %d" , packet . Children [ 1 ] . Tag ) )
2016-11-04 01:16:01 +03:00
}
extendedResponse := packet . Children [ 1 ]
for _ , child := range extendedResponse . Children {
if child . Tag == 11 {
2019-01-24 02:25:33 +03:00
passwordModifyResponseValue := ber . DecodePacket ( child . Data . Bytes ( ) )
if len ( passwordModifyResponseValue . Children ) == 1 {
if passwordModifyResponseValue . Children [ 0 ] . Tag == 0 {
result . GeneratedPassword = ber . DecodeString ( passwordModifyResponseValue . Children [ 0 ] . Data . Bytes ( ) )
2016-11-04 01:16:01 +03:00
}
}
}
}
return result , nil
}