mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.3 KiB
148 lines
5.3 KiB
// 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" |
|
) |
|
|
|
// 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 |
|
} |
|
|
|
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 |
|
} |
|
|
|
// NewPasswordModifyRequest creates a new PasswordModifyRequest |
|
// |
|
// 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, |
|
} |
|
} |
|
|
|
// PasswordModify performs the modification request |
|
func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) { |
|
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") |
|
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) |
|
|
|
encodedPasswordModifyRequest, err := passwordModifyRequest.encode() |
|
if err != nil { |
|
return nil, err |
|
} |
|
packet.AppendChild(encodedPasswordModifyRequest) |
|
|
|
l.Debug.PrintPacket(packet) |
|
|
|
msgCtx, err := l.sendMessage(packet) |
|
if err != nil { |
|
return nil, err |
|
} |
|
defer l.finishMessage(msgCtx) |
|
|
|
result := &PasswordModifyResult{} |
|
|
|
l.Debug.Printf("%d: waiting for response", msgCtx.id) |
|
packetResponse, ok := <-msgCtx.responses |
|
if !ok { |
|
return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) |
|
} |
|
packet, err = packetResponse.ReadPacket() |
|
l.Debug.Printf("%d: got response %p", msgCtx.id, packet) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
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 |
|
}
|
|
|