passwdmodify.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package ldap
  2. import (
  3. "fmt"
  4. ber "github.com/go-asn1-ber/asn1-ber"
  5. )
  6. const (
  7. passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
  8. )
  9. // PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt
  10. type PasswordModifyRequest struct {
  11. // UserIdentity is an optional string representation of the user associated with the request.
  12. // This string may or may not be an LDAPDN [RFC2253].
  13. // If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session
  14. UserIdentity string
  15. // OldPassword, if present, contains the user's current password
  16. OldPassword string
  17. // NewPassword, if present, contains the desired password for this user
  18. NewPassword string
  19. }
  20. // PasswordModifyResult holds the server response to a PasswordModifyRequest
  21. type PasswordModifyResult struct {
  22. // GeneratedPassword holds a password generated by the server, if present
  23. GeneratedPassword string
  24. // Referral are the returned referral
  25. Referral string
  26. }
  27. func (req *PasswordModifyRequest) appendTo(envelope *ber.Packet) error {
  28. pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")
  29. pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))
  30. extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")
  31. passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")
  32. if req.UserIdentity != "" {
  33. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.UserIdentity, "User Identity"))
  34. }
  35. if req.OldPassword != "" {
  36. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, req.OldPassword, "Old Password"))
  37. }
  38. if req.NewPassword != "" {
  39. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, req.NewPassword, "New Password"))
  40. }
  41. extendedRequestValue.AppendChild(passwordModifyRequestValue)
  42. pkt.AppendChild(extendedRequestValue)
  43. envelope.AppendChild(pkt)
  44. return nil
  45. }
  46. // NewPasswordModifyRequest creates a new PasswordModifyRequest
  47. //
  48. // According to the RFC 3602 (https://tools.ietf.org/html/rfc3062):
  49. // userIdentity is a string representing the user associated with the request.
  50. // This string may or may not be an LDAPDN (RFC 2253).
  51. // If userIdentity is empty then the operation will act on the user associated
  52. // with the session.
  53. //
  54. // oldPassword is the current user's password, it can be empty or it can be
  55. // needed depending on the session user access rights (usually an administrator
  56. // can change a user's password without knowing the current one) and the
  57. // password policy (see pwdSafeModify password policy's attribute)
  58. //
  59. // newPassword is the desired user's password. If empty the server can return
  60. // an error or generate a new password that will be available in the
  61. // PasswordModifyResult.GeneratedPassword
  62. //
  63. func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
  64. return &PasswordModifyRequest{
  65. UserIdentity: userIdentity,
  66. OldPassword: oldPassword,
  67. NewPassword: newPassword,
  68. }
  69. }
  70. // PasswordModify performs the modification request
  71. func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {
  72. msgCtx, err := l.doRequest(passwordModifyRequest)
  73. if err != nil {
  74. return nil, err
  75. }
  76. defer l.finishMessage(msgCtx)
  77. packet, err := l.readPacket(msgCtx)
  78. if err != nil {
  79. return nil, err
  80. }
  81. result := &PasswordModifyResult{}
  82. if packet.Children[1].Tag == ApplicationExtendedResponse {
  83. err := GetLDAPError(packet)
  84. if err != nil {
  85. if IsErrorWithCode(err, LDAPResultReferral) {
  86. for _, child := range packet.Children[1].Children {
  87. if child.Tag == 3 {
  88. result.Referral = child.Children[0].Value.(string)
  89. }
  90. }
  91. }
  92. return result, err
  93. }
  94. } else {
  95. return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
  96. }
  97. extendedResponse := packet.Children[1]
  98. for _, child := range extendedResponse.Children {
  99. if child.Tag == 11 {
  100. passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes())
  101. if len(passwordModifyResponseValue.Children) == 1 {
  102. if passwordModifyResponseValue.Children[0].Tag == 0 {
  103. result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes())
  104. }
  105. }
  106. }
  107. }
  108. return result, nil
  109. }