1package ldap 2 3import ( 4 "errors" 5 "fmt" 6 7 "gopkg.in/asn1-ber.v1" 8) 9 10// SimpleBindRequest represents a username/password bind operation 11type SimpleBindRequest struct { 12 // Username is the name of the Directory object that the client wishes to bind as 13 Username string 14 // Password is the credentials to bind with 15 Password string 16 // Controls are optional controls to send with the bind request 17 Controls []Control 18 // AllowEmptyPassword sets whether the client allows binding with an empty password 19 // (normally used for unauthenticated bind). 20 AllowEmptyPassword bool 21} 22 23// SimpleBindResult contains the response from the server 24type SimpleBindResult struct { 25 Controls []Control 26} 27 28// NewSimpleBindRequest returns a bind request 29func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest { 30 return &SimpleBindRequest{ 31 Username: username, 32 Password: password, 33 Controls: controls, 34 AllowEmptyPassword: false, 35 } 36} 37 38func (bindRequest *SimpleBindRequest) encode() *ber.Packet { 39 request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") 40 request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) 41 request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name")) 42 request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password")) 43 44 return request 45} 46 47// SimpleBind performs the simple bind operation defined in the given request 48func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) { 49 if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword { 50 return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client")) 51 } 52 53 packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") 54 packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) 55 encodedBindRequest := simpleBindRequest.encode() 56 packet.AppendChild(encodedBindRequest) 57 if len(simpleBindRequest.Controls) > 0 { 58 packet.AppendChild(encodeControls(simpleBindRequest.Controls)) 59 } 60 61 if l.Debug { 62 ber.PrintPacket(packet) 63 } 64 65 msgCtx, err := l.sendMessage(packet) 66 if err != nil { 67 return nil, err 68 } 69 defer l.finishMessage(msgCtx) 70 71 packetResponse, ok := <-msgCtx.responses 72 if !ok { 73 return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) 74 } 75 packet, err = packetResponse.ReadPacket() 76 l.Debug.Printf("%d: got response %p", msgCtx.id, packet) 77 if err != nil { 78 return nil, err 79 } 80 81 if l.Debug { 82 if err = addLDAPDescriptions(packet); err != nil { 83 return nil, err 84 } 85 ber.PrintPacket(packet) 86 } 87 88 result := &SimpleBindResult{ 89 Controls: make([]Control, 0), 90 } 91 92 if len(packet.Children) == 3 { 93 for _, child := range packet.Children[2].Children { 94 decodedChild, decodeErr := DecodeControl(child) 95 if decodeErr != nil { 96 return nil, fmt.Errorf("failed to decode child control: %s", decodeErr) 97 } 98 result.Controls = append(result.Controls, decodedChild) 99 } 100 } 101 102 err = GetLDAPError(packet) 103 return result, err 104} 105 106// Bind performs a bind with the given username and password. 107// 108// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method 109// for that. 110func (l *Conn) Bind(username, password string) error { 111 req := &SimpleBindRequest{ 112 Username: username, 113 Password: password, 114 AllowEmptyPassword: false, 115 } 116 _, err := l.SimpleBind(req) 117 return err 118} 119 120// UnauthenticatedBind performs an unauthenticated bind. 121// 122// A username may be provided for trace (e.g. logging) purpose only, but it is normally not 123// authenticated or otherwise validated by the LDAP server. 124// 125// See https://tools.ietf.org/html/rfc4513#section-5.1.2 . 126// See https://tools.ietf.org/html/rfc4513#section-6.3.1 . 127func (l *Conn) UnauthenticatedBind(username string) error { 128 req := &SimpleBindRequest{ 129 Username: username, 130 Password: "", 131 AllowEmptyPassword: true, 132 } 133 _, err := l.SimpleBind(req) 134 return err 135} 136