ldap

package module
v2.5.1+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 23, 2017 License: MIT Imports: 17 Imported by: 0

README

GoDoc Build Status

Basic LDAP v3 functionality for the GO programming language.

Install

For the latest version use:

go get gopkg.in/ldap.v2

Import the latest version with:

import "gopkg.in/ldap.v2"

Required Libraries:

  • gopkg.in/asn1-ber.v1

Features:

  • Connecting to LDAP server (non-TLS, TLS, STARTTLS)
  • Binding to LDAP server
  • Searching for entries
  • Filter Compile / Decompile
  • Paging Search Results
  • Modify Requests / Responses
  • Add Requests / Responses
  • Delete Requests / Responses

Examples:

  • search
  • modify

Contributing:

Bug reports and pull requests are welcome!

Before submitting a pull request, please make sure tests and verification scripts pass:

make all

To set up a pre-push hook to run the tests and verify scripts before pushing:

ln -s ../../.githooks/pre-push .git/hooks/pre-push

The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: http://blog.golang.org/gopher

Documentation

Overview

Package ldap provides basic LDAP v3 functionality.

Example (Beherappolicy)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

controls := []ldap.Control{}
controls = append(controls, ldap.NewControlBeheraPasswordPolicy())
bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls)

r, err := l.SimpleBind(bindRequest)
ppolicyControl := ldap.FindControl(r.Controls, ldap.ControlTypeBeheraPasswordPolicy)

var ppolicy *ldap.ControlBeheraPasswordPolicy
if ppolicyControl != nil {
	ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy)
} else {
	log.Printf("ppolicyControl response not available.\n")
}
if err != nil {
	errStr := "ERROR: Cannot bind: " + err.Error()
	if ppolicy != nil && ppolicy.Error >= 0 {
		errStr += ":" + ppolicy.ErrorString
	}
	log.Print(errStr)
} else {
	logStr := "Login Ok"
	if ppolicy != nil {
		if ppolicy.Expire >= 0 {
			logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire)
		} else if ppolicy.Grace >= 0 {
			logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace)
		}
	}
	log.Print(logStr)
}
Output:

Example (UserAuthentication)

Example User Authentication shows how a typical application can verify a login attempt

// The username and password we want to check
username := "someuser"
password := "userpassword"

bindusername := "readonly"
bindpassword := "password"

l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

// Reconnect with TLS
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
if err != nil {
	log.Fatal(err)
}

// First bind with a read only user
err = l.Bind(bindusername, bindpassword)
if err != nil {
	log.Fatal(err)
}

// Search for the given username
searchRequest := ldap.NewSearchRequest(
	"dc=example,dc=com",
	ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
	fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", username),
	[]string{"dn"},
	nil,
)

sr, err := l.Search(searchRequest)
if err != nil {
	log.Fatal(err)
}

if len(sr.Entries) != 1 {
	log.Fatal("User does not exist or too many entries returned")
}

userdn := sr.Entries[0].DN

// Bind as the user to verify their password
err = l.Bind(userdn, password)
if err != nil {
	log.Fatal(err)
}

// Rebind as the read only user for any further queries
err = l.Bind(bindusername, bindpassword)
if err != nil {
	log.Fatal(err)
}
Output:

Example (Vchuppolicy)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()
l.Debug = true

bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil)

r, err := l.SimpleBind(bindRequest)

passwordMustChangeControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordMustChange)
var passwordMustChange *ldap.ControlVChuPasswordMustChange
if passwordMustChangeControl != nil {
	passwordMustChange = passwordMustChangeControl.(*ldap.ControlVChuPasswordMustChange)
}

if passwordMustChange != nil && passwordMustChange.MustChange {
	log.Printf("Password Must be changed.\n")
}

passwordWarningControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordWarning)

var passwordWarning *ldap.ControlVChuPasswordWarning
if passwordWarningControl != nil {
	passwordWarning = passwordWarningControl.(*ldap.ControlVChuPasswordWarning)
} else {
	log.Printf("ppolicyControl response not available.\n")
}
if err != nil {
	log.Print("ERROR: Cannot bind: " + err.Error())
} else {
	logStr := "Login Ok"
	if passwordWarning != nil {
		if passwordWarning.Expire >= 0 {
			logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire)
		}
	}
	log.Print(logStr)
}
Output:

Index

Examples

Constants

View Source
const (
	// MessageQuit causes the processMessages loop to exit
	MessageQuit = 0
	// MessageRequest sends a request to the server
	MessageRequest = 1
	// MessageResponse receives a response from the server
	MessageResponse = 2
	// MessageFinish indicates the client considers a particular message ID to be finished
	MessageFinish = 3
	// MessageTimeout indicates the client-specified timeout for a particular message ID has been reached
	MessageTimeout = 4
)
View Source
const (
	// ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt
	ControlTypePaging = "1.2.840.113556.1.4.319"
	// ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10
	ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1"
	// ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
	ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4"
	// ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
	ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
	// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
	ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
)
View Source
const (
	LDAPResultSuccess                      = 0
	LDAPResultOperationsError              = 1
	LDAPResultProtocolError                = 2
	LDAPResultTimeLimitExceeded            = 3
	LDAPResultSizeLimitExceeded            = 4
	LDAPResultCompareFalse                 = 5
	LDAPResultCompareTrue                  = 6
	LDAPResultAuthMethodNotSupported       = 7
	LDAPResultStrongAuthRequired           = 8
	LDAPResultReferral                     = 10
	LDAPResultAdminLimitExceeded           = 11
	LDAPResultUnavailableCriticalExtension = 12
	LDAPResultConfidentialityRequired      = 13
	LDAPResultSaslBindInProgress           = 14
	LDAPResultNoSuchAttribute              = 16
	LDAPResultUndefinedAttributeType       = 17
	LDAPResultInappropriateMatching        = 18
	LDAPResultConstraintViolation          = 19
	LDAPResultAttributeOrValueExists       = 20
	LDAPResultInvalidAttributeSyntax       = 21
	LDAPResultNoSuchObject                 = 32
	LDAPResultAliasProblem                 = 33
	LDAPResultInvalidDNSyntax              = 34
	LDAPResultAliasDereferencingProblem    = 36
	LDAPResultInappropriateAuthentication  = 48
	LDAPResultInvalidCredentials           = 49
	LDAPResultInsufficientAccessRights     = 50
	LDAPResultBusy                         = 51
	LDAPResultUnavailable                  = 52
	LDAPResultUnwillingToPerform           = 53
	LDAPResultLoopDetect                   = 54
	LDAPResultNamingViolation              = 64
	LDAPResultObjectClassViolation         = 65
	LDAPResultNotAllowedOnNonLeaf          = 66
	LDAPResultNotAllowedOnRDN              = 67
	LDAPResultEntryAlreadyExists           = 68
	LDAPResultObjectClassModsProhibited    = 69
	LDAPResultAffectsMultipleDSAs          = 71
	LDAPResultOther                        = 80

	ErrorNetwork            = 200
	ErrorFilterCompile      = 201
	ErrorFilterDecompile    = 202
	ErrorDebugging          = 203
	ErrorUnexpectedMessage  = 204
	ErrorUnexpectedResponse = 205
)

LDAP Result Codes

View Source
const (
	FilterAnd             = 0
	FilterOr              = 1
	FilterNot             = 2
	FilterEqualityMatch   = 3
	FilterSubstrings      = 4
	FilterGreaterOrEqual  = 5
	FilterLessOrEqual     = 6
	FilterPresent         = 7
	FilterApproxMatch     = 8
	FilterExtensibleMatch = 9
)

Filter choices

View Source
const (
	FilterSubstringsInitial = 0
	FilterSubstringsAny     = 1
	FilterSubstringsFinal   = 2
)

SubstringFilter options

View Source
const (
	MatchingRuleAssertionMatchingRule = 1
	MatchingRuleAssertionType         = 2
	MatchingRuleAssertionMatchValue   = 3
	MatchingRuleAssertionDNAttributes = 4
)

MatchingRuleAssertion choices

View Source
const (
	ApplicationBindRequest           = 0
	ApplicationBindResponse          = 1
	ApplicationUnbindRequest         = 2
	ApplicationSearchRequest         = 3
	ApplicationSearchResultEntry     = 4
	ApplicationSearchResultDone      = 5
	ApplicationModifyRequest         = 6
	ApplicationModifyResponse        = 7
	ApplicationAddRequest            = 8
	ApplicationAddResponse           = 9
	ApplicationDelRequest            = 10
	ApplicationDelResponse           = 11
	ApplicationModifyDNRequest       = 12
	ApplicationModifyDNResponse      = 13
	ApplicationCompareRequest        = 14
	ApplicationCompareResponse       = 15
	ApplicationAbandonRequest        = 16
	ApplicationSearchResultReference = 19
	ApplicationExtendedRequest       = 23
	ApplicationExtendedResponse      = 24
)

LDAP Application Codes

View Source
const (
	BeheraPasswordExpired             = 0
	BeheraAccountLocked               = 1
	BeheraChangeAfterReset            = 2
	BeheraPasswordModNotAllowed       = 3
	BeheraMustSupplyOldPassword       = 4
	BeheraInsufficientPasswordQuality = 5
	BeheraPasswordTooShort            = 6
	BeheraPasswordTooYoung            = 7
	BeheraPasswordInHistory           = 8
)

Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10)

View Source
const (
	AddAttribute     = 0
	DeleteAttribute  = 1
	ReplaceAttribute = 2
)

Change operation choices

View Source
const (
	ScopeBaseObject   = 0
	ScopeSingleLevel  = 1
	ScopeWholeSubtree = 2
)

scope choices

View Source
const (
	NeverDerefAliases   = 0
	DerefInSearching    = 1
	DerefFindingBaseObj = 2
	DerefAlways         = 3
)

derefAliases

Variables

View Source
var ApplicationMap = map[uint8]string{
	ApplicationBindRequest:           "Bind Request",
	ApplicationBindResponse:          "Bind Response",
	ApplicationUnbindRequest:         "Unbind Request",
	ApplicationSearchRequest:         "Search Request",
	ApplicationSearchResultEntry:     "Search Result Entry",
	ApplicationSearchResultDone:      "Search Result Done",
	ApplicationModifyRequest:         "Modify Request",
	ApplicationModifyResponse:        "Modify Response",
	ApplicationAddRequest:            "Add Request",
	ApplicationAddResponse:           "Add Response",
	ApplicationDelRequest:            "Del Request",
	ApplicationDelResponse:           "Del Response",
	ApplicationModifyDNRequest:       "Modify DN Request",
	ApplicationModifyDNResponse:      "Modify DN Response",
	ApplicationCompareRequest:        "Compare Request",
	ApplicationCompareResponse:       "Compare Response",
	ApplicationAbandonRequest:        "Abandon Request",
	ApplicationSearchResultReference: "Search Result Reference",
	ApplicationExtendedRequest:       "Extended Request",
	ApplicationExtendedResponse:      "Extended Response",
}

ApplicationMap contains human readable descriptions of LDAP Application Codes

View Source
var BeheraPasswordPolicyErrorMap = map[int8]string{
	BeheraPasswordExpired:             "Password expired",
	BeheraAccountLocked:               "Account locked",
	BeheraChangeAfterReset:            "Password must be changed",
	BeheraPasswordModNotAllowed:       "Policy prevents password modification",
	BeheraMustSupplyOldPassword:       "Policy requires old password in order to change password",
	BeheraInsufficientPasswordQuality: "Password fails quality checks",
	BeheraPasswordTooShort:            "Password is too short for policy",
	BeheraPasswordTooYoung:            "Password has been changed too recently",
	BeheraPasswordInHistory:           "New password is in list of old passwords",
}

BeheraPasswordPolicyErrorMap contains human readable descriptions of Behera Password Policy error codes

View Source
var ControlTypeMap = map[string]string{
	ControlTypePaging:               "Paging",
	ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
	ControlTypeManageDsaIT:          "Manage DSA IT",
}

ControlTypeMap maps controls to text descriptions

View Source
var DefaultTimeout = 60 * time.Second

DefaultTimeout is a package-level variable that sets the timeout value used for the Dial and DialTLS methods.

WARNING: since this is a package-level variable, setting this value from multiple places will probably result in undesired behaviour.

View Source
var DerefMap = map[int]string{
	NeverDerefAliases:   "NeverDerefAliases",
	DerefInSearching:    "DerefInSearching",
	DerefFindingBaseObj: "DerefFindingBaseObj",
	DerefAlways:         "DerefAlways",
}

DerefMap contains human readable descriptions of derefAliases choices

View Source
var FilterMap = map[uint64]string{
	FilterAnd:             "And",
	FilterOr:              "Or",
	FilterNot:             "Not",
	FilterEqualityMatch:   "Equality Match",
	FilterSubstrings:      "Substrings",
	FilterGreaterOrEqual:  "Greater Or Equal",
	FilterLessOrEqual:     "Less Or Equal",
	FilterPresent:         "Present",
	FilterApproxMatch:     "Approx Match",
	FilterExtensibleMatch: "Extensible Match",
}

FilterMap contains human readable descriptions of Filter choices

View Source
var FilterSubstringsMap = map[uint64]string{
	FilterSubstringsInitial: "Substrings Initial",
	FilterSubstringsAny:     "Substrings Any",
	FilterSubstringsFinal:   "Substrings Final",
}

FilterSubstringsMap contains human readable descriptions of SubstringFilter choices

View Source
var LDAPResultCodeMap = map[uint8]string{
	LDAPResultSuccess:                      "Success",
	LDAPResultOperationsError:              "Operations Error",
	LDAPResultProtocolError:                "Protocol Error",
	LDAPResultTimeLimitExceeded:            "Time Limit Exceeded",
	LDAPResultSizeLimitExceeded:            "Size Limit Exceeded",
	LDAPResultCompareFalse:                 "Compare False",
	LDAPResultCompareTrue:                  "Compare True",
	LDAPResultAuthMethodNotSupported:       "Auth Method Not Supported",
	LDAPResultStrongAuthRequired:           "Strong Auth Required",
	LDAPResultReferral:                     "Referral",
	LDAPResultAdminLimitExceeded:           "Admin Limit Exceeded",
	LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
	LDAPResultConfidentialityRequired:      "Confidentiality Required",
	LDAPResultSaslBindInProgress:           "Sasl Bind In Progress",
	LDAPResultNoSuchAttribute:              "No Such Attribute",
	LDAPResultUndefinedAttributeType:       "Undefined Attribute Type",
	LDAPResultInappropriateMatching:        "Inappropriate Matching",
	LDAPResultConstraintViolation:          "Constraint Violation",
	LDAPResultAttributeOrValueExists:       "Attribute Or Value Exists",
	LDAPResultInvalidAttributeSyntax:       "Invalid Attribute Syntax",
	LDAPResultNoSuchObject:                 "No Such Object",
	LDAPResultAliasProblem:                 "Alias Problem",
	LDAPResultInvalidDNSyntax:              "Invalid DN Syntax",
	LDAPResultAliasDereferencingProblem:    "Alias Dereferencing Problem",
	LDAPResultInappropriateAuthentication:  "Inappropriate Authentication",
	LDAPResultInvalidCredentials:           "Invalid Credentials",
	LDAPResultInsufficientAccessRights:     "Insufficient Access Rights",
	LDAPResultBusy:                         "Busy",
	LDAPResultUnavailable:                  "Unavailable",
	LDAPResultUnwillingToPerform:           "Unwilling To Perform",
	LDAPResultLoopDetect:                   "Loop Detect",
	LDAPResultNamingViolation:              "Naming Violation",
	LDAPResultObjectClassViolation:         "Object Class Violation",
	LDAPResultNotAllowedOnNonLeaf:          "Not Allowed On Non Leaf",
	LDAPResultNotAllowedOnRDN:              "Not Allowed On RDN",
	LDAPResultEntryAlreadyExists:           "Entry Already Exists",
	LDAPResultObjectClassModsProhibited:    "Object Class Mods Prohibited",
	LDAPResultAffectsMultipleDSAs:          "Affects Multiple DSAs",
	LDAPResultOther:                        "Other",

	ErrorNetwork:            "Network Error",
	ErrorFilterCompile:      "Filter Compile Error",
	ErrorFilterDecompile:    "Filter Decompile Error",
	ErrorDebugging:          "Debugging Error",
	ErrorUnexpectedMessage:  "Unexpected Message",
	ErrorUnexpectedResponse: "Unexpected Response",
}

LDAPResultCodeMap contains string descriptions for LDAP error codes

View Source
var MatchingRuleAssertionMap = map[uint64]string{
	MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule",
	MatchingRuleAssertionType:         "Matching Rule Assertion Type",
	MatchingRuleAssertionMatchValue:   "Matching Rule Assertion Match Value",
	MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes",
}

MatchingRuleAssertionMap contains human readable descriptions of MatchingRuleAssertion choices

View Source
var ScopeMap = map[int]string{
	ScopeBaseObject:   "Base Object",
	ScopeSingleLevel:  "Single Level",
	ScopeWholeSubtree: "Whole Subtree",
}

ScopeMap contains human readable descriptions of scope choices

Functions

func CompileFilter

func CompileFilter(filter string) (*ber.Packet, error)

CompileFilter converts a string representation of a filter into a BER-encoded packet

func DebugBinaryFile

func DebugBinaryFile(fileName string) error

DebugBinaryFile reads and prints packets from the given filename

func DecompileFilter

func DecompileFilter(packet *ber.Packet) (ret string, err error)

DecompileFilter converts a packet representation of a filter into a string representation

func EscapeFilter

func EscapeFilter(filter string) string

EscapeFilter escapes from the provided LDAP filter string the special characters in the set `()*\` and those out of the range 0 < c < 0x80, as defined in RFC4515.

func IsErrorWithCode

func IsErrorWithCode(err error, desiredResultCode uint8) bool

IsErrorWithCode returns true if the given error is an LDAP error with the given result code

func NewError

func NewError(resultCode uint8, err error) error

NewError creates an LDAP error with the given code and underlying error

Types

type AddRequest

type AddRequest struct {
	// DN identifies the entry being added
	DN string
	// Attributes list the attributes of the new entry
	Attributes []Attribute
}

AddRequest represents an LDAP AddRequest operation

func NewAddRequest

func NewAddRequest(dn string) *AddRequest

NewAddRequest returns an AddRequest for the given DN, with no attributes

func (*AddRequest) Attribute

func (a *AddRequest) Attribute(attrType string, attrVals []string)

Attribute adds an attribute with the given type and values

type Attribute

type Attribute struct {
	// Type is the name of the LDAP attribute
	Type string
	// Vals are the LDAP attribute values
	Vals []string
}

Attribute represents an LDAP attribute

type AttributeTypeAndValue

type AttributeTypeAndValue struct {
	// Type is the attribute type
	Type string
	// Value is the attribute value
	Value string
}

AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514

func (*AttributeTypeAndValue) Equal

Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue Case of the attribute type is not significant

type Client

type Client interface {
	Start()
	StartTLS(config *tls.Config) error
	Close()
	SetTimeout(time.Duration)

	Bind(username, password string) error
	SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error)

	Add(addRequest *AddRequest) error
	Del(delRequest *DelRequest) error
	Modify(modifyRequest *ModifyRequest) error

	Compare(dn, attribute, value string) (bool, error)
	PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)

	Search(searchRequest *SearchRequest) (*SearchResult, error)
	SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)
}

Client knows how to interact with an LDAP server

type Conn

type Conn struct {
	Debug debugging
	// contains filtered or unexported fields
}

Conn represents an LDAP Connection

func Dial

func Dial(network, addr string) (*Conn, error)

Dial connects to the given address on the given network using net.Dial and then returns a new Conn for the connection.

func DialTLS

func DialTLS(network, addr string, config *tls.Config) (*Conn, error)

DialTLS connects to the given address on the given network using tls.Dial and then returns a new Conn for the connection.

func NewConn

func NewConn(conn net.Conn, isTLS bool) *Conn

NewConn returns a new Conn using conn for network I/O.

func (*Conn) Add

func (l *Conn) Add(addRequest *AddRequest) error

Add performs the given AddRequest

func (*Conn) Bind

func (l *Conn) Bind(username, password string) error

Bind performs a bind with the given username and password

Example

ExampleConn_Bind demonstrates how to bind a connection to an ldap user allowing access to restricted attributes that user has access to

l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
if err != nil {
	log.Fatal(err)
}
Output:

func (*Conn) Close

func (l *Conn) Close()

Close closes the connection.

func (*Conn) Compare

func (l *Conn) Compare(dn, attribute, value string) (bool, error)

Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise false with any error that occurs if any.

Example

ExampleConn_Compare demonstrates how to compare an attribute with a value

l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid")
if err != nil {
	log.Fatal(err)
}

fmt.Println(matched)
Output:

func (*Conn) Del

func (l *Conn) Del(delRequest *DelRequest) error

Del executes the given delete request

func (*Conn) Modify

func (l *Conn) Modify(modifyRequest *ModifyRequest) error

Modify performs the ModifyRequest

Example
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

// Add a description, and replace the mail attributes
modify := ldap.NewModifyRequest("cn=user,dc=example,dc=com")
modify.Add("description", []string{"An example user"})
modify.Replace("mail", []string{"user@example.org"})

err = l.Modify(modify)
if err != nil {
	log.Fatal(err)
}
Output:

func (*Conn) PasswordModify

func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)

PasswordModify performs the modification request

Example (Admin)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

err = l.Bind("cn=admin,dc=example,dc=com", "password")
if err != nil {
	log.Fatal(err)
}

passwordModifyRequest := ldap.NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword")
_, err = l.PasswordModify(passwordModifyRequest)

if err != nil {
	log.Fatalf("Password could not be changed: %s", err.Error())
}
Output:

Example (GeneratedPassword)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

err = l.Bind("cn=user,dc=example,dc=com", "password")
if err != nil {
	log.Fatal(err)
}

passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "")
passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest)
if err != nil {
	log.Fatalf("Password could not be changed: %s", err.Error())
}

generatedPassword := passwordModifyResponse.GeneratedPassword
log.Printf("Generated password: %s\n", generatedPassword)
Output:

Example (SetNewPassword)
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

err = l.Bind("cn=user,dc=example,dc=com", "password")
if err != nil {
	log.Fatal(err)
}

passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "NewPassword")
_, err = l.PasswordModify(passwordModifyRequest)

if err != nil {
	log.Fatalf("Password could not be changed: %s", err.Error())
}
Output:

func (*Conn) Search

func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error)

Search performs the given search request

Example

ExampleConn_Search demonstrates how to use the search interface

l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

searchRequest := ldap.NewSearchRequest(
	"dc=example,dc=com", // The base dn to search
	ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
	"(&(objectClass=organizationalPerson))", // The filter to apply
	[]string{"dn", "cn"},                    // A list attributes to retrieve
	nil,
)

sr, err := l.Search(searchRequest)
if err != nil {
	log.Fatal(err)
}

for _, entry := range sr.Entries {
	fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
}
Output:

func (*Conn) SearchWithPaging

func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)

SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the search request. All paged LDAP query responses will be buffered and the final result will be returned atomically. The following four cases are possible given the arguments:

  • given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
  • given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
  • given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
  • given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries

A requested pagingSize of 0 is interpreted as no limit by LDAP servers.

func (*Conn) SetTimeout

func (l *Conn) SetTimeout(timeout time.Duration)

SetTimeout sets the time after a request is sent that a MessageTimeout triggers

func (*Conn) SimpleBind

func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error)

SimpleBind performs the simple bind operation defined in the given request

func (*Conn) Start

func (l *Conn) Start()

Start initializes goroutines to read responses and process messages

func (*Conn) StartTLS

func (l *Conn) StartTLS(config *tls.Config) error

StartTLS sends the command to start a TLS session and then creates a new TLS Client

Example

ExampleStartTLS demonstrates how to start a TLS connection

l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
if err != nil {
	log.Fatal(err)
}
defer l.Close()

// Reconnect with TLS
err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
if err != nil {
	log.Fatal(err)
}

// Operations via l are now encrypted
Output:

type Control

type Control interface {
	// GetControlType returns the OID
	GetControlType() string
	// Encode returns the ber packet representation
	Encode() *ber.Packet
	// String returns a human-readable description
	String() string
}

Control defines an interface controls provide to encode and describe themselves

func DecodeControl

func DecodeControl(packet *ber.Packet) Control

DecodeControl returns a control read from the given packet, or nil if no recognized control can be made

func FindControl

func FindControl(controls []Control, controlType string) Control

FindControl returns the first control of the given type in the list, or nil

type ControlBeheraPasswordPolicy

type ControlBeheraPasswordPolicy struct {
	// Expire contains the number of seconds before a password will expire
	Expire int64
	// Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password
	Grace int64
	// Error indicates the error code
	Error int8
	// ErrorString is a human readable error
	ErrorString string
}

ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10

func NewControlBeheraPasswordPolicy

func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy

NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy

func (*ControlBeheraPasswordPolicy) Encode

func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlBeheraPasswordPolicy) GetControlType

func (c *ControlBeheraPasswordPolicy) GetControlType() string

GetControlType returns the OID

func (*ControlBeheraPasswordPolicy) String

func (c *ControlBeheraPasswordPolicy) String() string

String returns a human-readable description

type ControlManageDsaIT

type ControlManageDsaIT struct {
	// Criticality indicates if this control is required
	Criticality bool
}

ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296

func NewControlManageDsaIT

func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT

NewControlManageDsaIT returns a ControlManageDsaIT control

func (*ControlManageDsaIT) Encode

func (c *ControlManageDsaIT) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlManageDsaIT) GetControlType

func (c *ControlManageDsaIT) GetControlType() string

GetControlType returns the OID

func (*ControlManageDsaIT) String

func (c *ControlManageDsaIT) String() string

String returns a human-readable description

type ControlPaging

type ControlPaging struct {
	// PagingSize indicates the page size
	PagingSize uint32
	// Cookie is an opaque value returned by the server to track a paging cursor
	Cookie []byte
}

ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt

func NewControlPaging

func NewControlPaging(pagingSize uint32) *ControlPaging

NewControlPaging returns a paging control

func (*ControlPaging) Encode

func (c *ControlPaging) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlPaging) GetControlType

func (c *ControlPaging) GetControlType() string

GetControlType returns the OID

func (*ControlPaging) SetCookie

func (c *ControlPaging) SetCookie(cookie []byte)

SetCookie stores the given cookie in the paging control

func (*ControlPaging) String

func (c *ControlPaging) String() string

String returns a human-readable description

type ControlString

type ControlString struct {
	ControlType  string
	Criticality  bool
	ControlValue string
}

ControlString implements the Control interface for simple controls

func NewControlString

func NewControlString(controlType string, criticality bool, controlValue string) *ControlString

NewControlString returns a generic control

func (*ControlString) Encode

func (c *ControlString) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlString) GetControlType

func (c *ControlString) GetControlType() string

GetControlType returns the OID

func (*ControlString) String

func (c *ControlString) String() string

String returns a human-readable description

type ControlVChuPasswordMustChange

type ControlVChuPasswordMustChange struct {
	// MustChange indicates if the password is required to be changed
	MustChange bool
}

ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00

func (*ControlVChuPasswordMustChange) Encode

func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlVChuPasswordMustChange) GetControlType

func (c *ControlVChuPasswordMustChange) GetControlType() string

GetControlType returns the OID

func (*ControlVChuPasswordMustChange) String

String returns a human-readable description

type ControlVChuPasswordWarning

type ControlVChuPasswordWarning struct {
	// Expire indicates the time in seconds until the password expires
	Expire int64
}

ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00

func (*ControlVChuPasswordWarning) Encode

func (c *ControlVChuPasswordWarning) Encode() *ber.Packet

Encode returns the ber packet representation

func (*ControlVChuPasswordWarning) GetControlType

func (c *ControlVChuPasswordWarning) GetControlType() string

GetControlType returns the OID

func (*ControlVChuPasswordWarning) String

func (c *ControlVChuPasswordWarning) String() string

String returns a human-readable description

type DN

type DN struct {
	RDNs []*RelativeDN
}

DN represents a distinguishedName from https://tools.ietf.org/html/rfc4514

func ParseDN

func ParseDN(str string) (*DN, error)

ParseDN returns a distinguishedName or an error

func (*DN) AncestorOf

func (d *DN) AncestorOf(other *DN) bool

AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN. "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com" "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com" "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com"

func (*DN) Equal

func (d *DN) Equal(other *DN) bool

Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). Returns true if they have the same number of relative distinguished names and corresponding relative distinguished names (by position) are the same.

type DelRequest

type DelRequest struct {
	// DN is the name of the directory entry to delete
	DN string
	// Controls hold optional controls to send with the request
	Controls []Control
}

DelRequest implements an LDAP deletion request

func NewDelRequest

func NewDelRequest(DN string,
	Controls []Control) *DelRequest

NewDelRequest creates a delete request for the given DN and controls

type Entry

type Entry struct {
	// DN is the distinguished name of the entry
	DN string
	// Attributes are the returned attributes for the entry
	Attributes []*EntryAttribute
}

Entry represents a single search result entry

func NewEntry

func NewEntry(dn string, attributes map[string][]string) *Entry

NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs. The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the same input map of attributes, the output entry will contain the same order of attributes

func (*Entry) GetAttributeValue

func (e *Entry) GetAttributeValue(attribute string) string

GetAttributeValue returns the first value for the named attribute, or ""

func (*Entry) GetAttributeValues

func (e *Entry) GetAttributeValues(attribute string) []string

GetAttributeValues returns the values for the named attribute, or an empty list

func (*Entry) GetRawAttributeValue

func (e *Entry) GetRawAttributeValue(attribute string) []byte

GetRawAttributeValue returns the first value for the named attribute, or an empty slice

func (*Entry) GetRawAttributeValues

func (e *Entry) GetRawAttributeValues(attribute string) [][]byte

GetRawAttributeValues returns the byte values for the named attribute, or an empty list

func (*Entry) PrettyPrint

func (e *Entry) PrettyPrint(indent int)

PrettyPrint outputs a human-readable description indenting

func (*Entry) Print

func (e *Entry) Print()

Print outputs a human-readable description

type EntryAttribute

type EntryAttribute struct {
	// Name is the name of the attribute
	Name string
	// Values contain the string values of the attribute
	Values []string
	// ByteValues contain the raw values of the attribute
	ByteValues [][]byte
}

EntryAttribute holds a single attribute

func NewEntryAttribute

func NewEntryAttribute(name string, values []string) *EntryAttribute

NewEntryAttribute returns a new EntryAttribute with the desired key-value pair

func (*EntryAttribute) PrettyPrint

func (e *EntryAttribute) PrettyPrint(indent int)

PrettyPrint outputs a human-readable description with indenting

func (*EntryAttribute) Print

func (e *EntryAttribute) Print()

Print outputs a human-readable description

type Error

type Error struct {
	// Err is the underlying error
	Err error
	// ResultCode is the LDAP error code
	ResultCode uint8
}

Error holds LDAP error information

func (*Error) Error

func (e *Error) Error() string

type ModifyRequest

type ModifyRequest struct {
	// DN is the distinguishedName of the directory entry to modify
	DN string
	// AddAttributes contain the attributes to add
	AddAttributes []PartialAttribute
	// DeleteAttributes contain the attributes to delete
	DeleteAttributes []PartialAttribute
	// ReplaceAttributes contain the attributes to replace
	ReplaceAttributes []PartialAttribute
}

ModifyRequest as defined in https://tools.ietf.org/html/rfc4511

func NewModifyRequest

func NewModifyRequest(
	dn string,
) *ModifyRequest

NewModifyRequest creates a modify request for the given DN

func (*ModifyRequest) Add

func (m *ModifyRequest) Add(attrType string, attrVals []string)

Add inserts the given attribute to the list of attributes to add

func (*ModifyRequest) Delete

func (m *ModifyRequest) Delete(attrType string, attrVals []string)

Delete inserts the given attribute to the list of attributes to delete

func (*ModifyRequest) Replace

func (m *ModifyRequest) Replace(attrType string, attrVals []string)

Replace inserts the given attribute to the list of attributes to replace

type PacketResponse

type PacketResponse struct {
	// Packet is the packet read from the server
	Packet *ber.Packet
	// Error is an error encountered while reading
	Error error
}

PacketResponse contains the packet or error encountered reading a response

func (*PacketResponse) ReadPacket

func (pr *PacketResponse) ReadPacket() (*ber.Packet, error)

ReadPacket returns the packet or an error

type PartialAttribute

type PartialAttribute struct {
	// Type is the type of the partial attribute
	Type string
	// Vals are the values of the partial attribute
	Vals []string
}

PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511

type PasswordModifyRequest

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
}

PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt

func NewPasswordModifyRequest

func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest

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

type PasswordModifyResult

type PasswordModifyResult struct {
	// GeneratedPassword holds a password generated by the server, if present
	GeneratedPassword string
}

PasswordModifyResult holds the server response to a PasswordModifyRequest

type RelativeDN

type RelativeDN struct {
	Attributes []*AttributeTypeAndValue
}

RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514

func (*RelativeDN) Equal

func (r *RelativeDN) Equal(other *RelativeDN) bool

Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type. The order of attributes is not significant. Case of attribute types is not significant.

type SearchRequest

type SearchRequest struct {
	BaseDN       string
	Scope        int
	DerefAliases int
	SizeLimit    int
	TimeLimit    int
	TypesOnly    bool
	Filter       string
	Attributes   []string
	Controls     []Control
}

SearchRequest represents a search request to send to the server

func NewSearchRequest

func NewSearchRequest(
	BaseDN string,
	Scope, DerefAliases, SizeLimit, TimeLimit int,
	TypesOnly bool,
	Filter string,
	Attributes []string,
	Controls []Control,
) *SearchRequest

NewSearchRequest creates a new search request

type SearchResult

type SearchResult struct {
	// Entries are the returned entries
	Entries []*Entry
	// Referrals are the returned referrals
	Referrals []string
	// Controls are the returned controls
	Controls []Control
}

SearchResult holds the server's response to a search request

func (*SearchResult) PrettyPrint

func (s *SearchResult) PrettyPrint(indent int)

PrettyPrint outputs a human-readable description with indenting

func (*SearchResult) Print

func (s *SearchResult) Print()

Print outputs a human-readable description

type SimpleBindRequest

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
}

SimpleBindRequest represents a username/password bind operation

func NewSimpleBindRequest

func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest

NewSimpleBindRequest returns a bind request

type SimpleBindResult

type SimpleBindResult struct {
	Controls []Control
}

SimpleBindResult contains the response from the server

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL