passwdmodify.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // This file contains the password modify extended operation as specified in rfc 3062
  2. //
  3. // https://tools.ietf.org/html/rfc3062
  4. //
  5. package ldap
  6. import (
  7. "errors"
  8. "fmt"
  9. "gopkg.in/asn1-ber.v1"
  10. )
  11. const (
  12. passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1"
  13. )
  14. type PasswordModifyRequest struct {
  15. UserIdentity string
  16. OldPassword string
  17. NewPassword string
  18. }
  19. type PasswordModifyResult struct {
  20. GeneratedPassword string
  21. }
  22. func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
  23. request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")
  24. request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))
  25. extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")
  26. passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")
  27. if r.UserIdentity != "" {
  28. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity"))
  29. }
  30. if r.OldPassword != "" {
  31. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password"))
  32. }
  33. if r.NewPassword != "" {
  34. passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password"))
  35. }
  36. extendedRequestValue.AppendChild(passwordModifyRequestValue)
  37. request.AppendChild(extendedRequestValue)
  38. return request, nil
  39. }
  40. // Create a new PasswordModifyRequest
  41. //
  42. // According to the RFC 3602:
  43. // userIdentity is a string representing the user associated with the request.
  44. // This string may or may not be an LDAPDN (RFC 2253).
  45. // If userIdentity is empty then the operation will act on the user associated
  46. // with the session.
  47. //
  48. // oldPassword is the current user's password, it can be empty or it can be
  49. // needed depending on the session user access rights (usually an administrator
  50. // can change a user's password without knowing the current one) and the
  51. // password policy (see pwdSafeModify password policy's attribute)
  52. //
  53. // newPassword is the desired user's password. If empty the server can return
  54. // an error or generate a new password that will be available in the
  55. // PasswordModifyResult.GeneratedPassword
  56. //
  57. func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {
  58. return &PasswordModifyRequest{
  59. UserIdentity: userIdentity,
  60. OldPassword: oldPassword,
  61. NewPassword: newPassword,
  62. }
  63. }
  64. func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {
  65. messageID := l.nextMessageID()
  66. packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
  67. packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
  68. encodedPasswordModifyRequest, err := passwordModifyRequest.encode()
  69. if err != nil {
  70. return nil, err
  71. }
  72. packet.AppendChild(encodedPasswordModifyRequest)
  73. l.Debug.PrintPacket(packet)
  74. channel, err := l.sendMessage(packet)
  75. if err != nil {
  76. return nil, err
  77. }
  78. if channel == nil {
  79. return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
  80. }
  81. defer l.finishMessage(messageID)
  82. result := &PasswordModifyResult{}
  83. l.Debug.Printf("%d: waiting for response", messageID)
  84. packet = <-channel
  85. l.Debug.Printf("%d: got response %p", messageID, packet)
  86. if packet == nil {
  87. return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
  88. }
  89. if l.Debug {
  90. if err := addLDAPDescriptions(packet); err != nil {
  91. return nil, err
  92. }
  93. ber.PrintPacket(packet)
  94. }
  95. if packet.Children[1].Tag == ApplicationExtendedResponse {
  96. resultCode, resultDescription := getLDAPResultCode(packet)
  97. if resultCode != 0 {
  98. return nil, NewError(resultCode, errors.New(resultDescription))
  99. }
  100. } else {
  101. return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
  102. }
  103. extendedResponse := packet.Children[1]
  104. for _, child := range extendedResponse.Children {
  105. if child.Tag == 11 {
  106. passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes())
  107. if len(passwordModifyReponseValue.Children) == 1 {
  108. if passwordModifyReponseValue.Children[0].Tag == 0 {
  109. result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes())
  110. }
  111. }
  112. }
  113. }
  114. return result, nil
  115. }