summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/ldap/bind.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/ldap/bind.go')
-rw-r--r--vendor/github.com/mattermost/ldap/bind.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/ldap/bind.go b/vendor/github.com/mattermost/ldap/bind.go
new file mode 100644
index 00000000..15307f50
--- /dev/null
+++ b/vendor/github.com/mattermost/ldap/bind.go
@@ -0,0 +1,152 @@
+package ldap
+
+import (
+ "errors"
+ "fmt"
+
+ ber "github.com/go-asn1-ber/asn1-ber"
+)
+
+// SimpleBindRequest represents a username/password bind operation
+type SimpleBindRequest struct {
+ // Username is the name of the Directory object that the client wishes to bind as
+ Username string
+ // Password is the credentials to bind with
+ Password string
+ // Controls are optional controls to send with the bind request
+ Controls []Control
+ // AllowEmptyPassword sets whether the client allows binding with an empty password
+ // (normally used for unauthenticated bind).
+ AllowEmptyPassword bool
+}
+
+// SimpleBindResult contains the response from the server
+type SimpleBindResult struct {
+ Controls []Control
+}
+
+// NewSimpleBindRequest returns a bind request
+func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
+ return &SimpleBindRequest{
+ Username: username,
+ Password: password,
+ Controls: controls,
+ AllowEmptyPassword: false,
+ }
+}
+
+func (req *SimpleBindRequest) appendTo(envelope *ber.Packet) error {
+ pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
+ pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
+ pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Username, "User Name"))
+ pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.Password, "Password"))
+
+ envelope.AppendChild(pkt)
+ if len(req.Controls) > 0 {
+ envelope.AppendChild(encodeControls(req.Controls))
+ }
+
+ return nil
+}
+
+// SimpleBind performs the simple bind operation defined in the given request
+func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
+ if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
+ return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
+ }
+
+ msgCtx, err := l.doRequest(simpleBindRequest)
+ if err != nil {
+ return nil, err
+ }
+ defer l.finishMessage(msgCtx)
+
+ packet, err := l.readPacket(msgCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ result := &SimpleBindResult{
+ Controls: make([]Control, 0),
+ }
+
+ if len(packet.Children) == 3 {
+ for _, child := range packet.Children[2].Children {
+ decodedChild, decodeErr := DecodeControl(child)
+ if decodeErr != nil {
+ return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
+ }
+ result.Controls = append(result.Controls, decodedChild)
+ }
+ }
+
+ err = GetLDAPError(packet)
+ return result, err
+}
+
+// Bind performs a bind with the given username and password.
+//
+// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
+// for that.
+func (l *Conn) Bind(username, password string) error {
+ req := &SimpleBindRequest{
+ Username: username,
+ Password: password,
+ AllowEmptyPassword: false,
+ }
+ _, err := l.SimpleBind(req)
+ return err
+}
+
+// UnauthenticatedBind performs an unauthenticated bind.
+//
+// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
+// authenticated or otherwise validated by the LDAP server.
+//
+// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
+// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
+func (l *Conn) UnauthenticatedBind(username string) error {
+ req := &SimpleBindRequest{
+ Username: username,
+ Password: "",
+ AllowEmptyPassword: true,
+ }
+ _, err := l.SimpleBind(req)
+ return err
+}
+
+var externalBindRequest = requestFunc(func(envelope *ber.Packet) error {
+ pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
+ pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
+ pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "User Name"))
+
+ saslAuth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication")
+ saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "EXTERNAL", "SASL Mech"))
+ saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "SASL Cred"))
+
+ pkt.AppendChild(saslAuth)
+
+ envelope.AppendChild(pkt)
+
+ return nil
+})
+
+// ExternalBind performs SASL/EXTERNAL authentication.
+//
+// Use ldap.DialURL("ldapi://") to connect to the Unix socket before ExternalBind.
+//
+// See https://tools.ietf.org/html/rfc4422#appendix-A
+func (l *Conn) ExternalBind() error {
+ msgCtx, err := l.doRequest(externalBindRequest)
+ if err != nil {
+ return err
+ }
+ defer l.finishMessage(msgCtx)
+
+ packet, err := l.readPacket(msgCtx)
+ if err != nil {
+ return err
+ }
+
+ return GetLDAPError(packet)
+}