ldap

package module
v0.0.0-...-c8393d9 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2016 License: BSD-3-Clause Imports: 19 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

Working:

  • Connecting to LDAP server
  • Binding to LDAP server
  • Searching for entries
  • Compiling string filters to LDAP filters
  • Paging Search Results
  • Modify Requests / Responses
  • Add Requests / Responses
  • Delete Requests / Responses
  • Better Unicode support

Examples:

  • search
  • modify

Tests Implemented:

  • Filter Compile / Decompile

TODO:

  • Add Requests / Responses
  • Delete Requests / Responses
  • Modify DN Requests / Responses
  • Compare Requests / Responses
  • Implement Tests / Benchmarks

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 avaliable.\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 futher 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     = 0
	MessageRequest  = 1
	MessageResponse = 2
	MessageFinish   = 3
	MessageTimeout  = 4
)
View Source
const (
	ControlTypePaging                 = "1.2.840.113556.1.4.319"
	ControlTypeBeheraPasswordPolicy   = "1.3.6.1.4.1.42.2.27.8.5.1"
	ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4"
	ControlTypeVChuPasswordWarning    = "2.16.840.1.113730.3.4.5"
	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
)
View Source
const (
	FilterSubstringsInitial = 0
	FilterSubstringsAny     = 1
	FilterSubstringsFinal   = 2
)
View Source
const (
	MatchingRuleAssertionMatchingRule = 1
	MatchingRuleAssertionType         = 2
	MatchingRuleAssertionMatchValue   = 3
	MatchingRuleAssertionDNAttributes = 4
)
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
)
View Source
const (
	ScopeBaseObject   = 0
	ScopeSingleLevel  = 1
	ScopeWholeSubtree = 2
)
View Source
const (
	NeverDerefAliases   = 0
	DerefInSearching    = 1
	DerefFindingBaseObj = 2
	DerefAlways         = 3
)

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",
}
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",
}
View Source
var CR byte = '\x0D'
View Source
var Comment byte = '#'
View Source
var ControlTypeMap = map[string]string{
	ControlTypePaging:               "Paging",
	ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
	ControlTypeManageDsaIT:          "Manage DSA IT",
}
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",
}
View Source
var (
	// ErrClosed is the error resulting if the pool is closed via pool.Close().
	ErrClosed = errors.New("pool is closed")
)
View Source
var ErrDNNotSubordinate = errors.New("Not a subordinate")
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",
}
View Source
var FilterSubstringsMap = map[uint64]string{
	FilterSubstringsInitial: "Substrings Initial",
	FilterSubstringsAny:     "Substrings Any",
	FilterSubstringsFinal:   "Substrings Final",
}
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",
}
View Source
var LF byte = '\x0A'
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",
}
View Source
var RDNCompareFold bool = true

When true, uses strings.EqualFold to compare the values of an RDN. This is usually needed as true for most values, set to false when your DNs contain case sensitive values.

View Source
var SEP string = string([]byte{CR, LF})
View Source
var SPACE byte = ' '
View Source
var SPACES = string(SPACE)
View Source
var ScopeMap = map[int]string{
	ScopeBaseObject:   "Base Object",
	ScopeSingleLevel:  "Single Level",
	ScopeWholeSubtree: "Whole Subtree",
}

Functions

func CompileFilter

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

func DebugBinaryFile

func DebugBinaryFile(fileName string) error

func DecompileFilter

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

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 EscapeValue

func EscapeValue(value string) (escaped string)

func IsErrorWithCode

func IsErrorWithCode(err error, desiredResultCode uint8) bool

func NewError

func NewError(resultCode uint8, err error) error

Types

type AddRequest

type AddRequest struct {
	DN         string
	Attributes []Attribute
}

func NewAddRequest

func NewAddRequest(dn string) *AddRequest

func (*AddRequest) Attribute

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

type Attribute

type Attribute struct {
	Type string
	Vals []string
}

type AttributeTypeAndValue

type AttributeTypeAndValue struct {
	Type  string
	Value string
}

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

func (*Conn) Alive

func (l *Conn) Alive() bool

func (*Conn) Bind

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

ExampleConn_Bind demonstrates how to bind a connection to an ldap user allowing access to restricted attrabutes 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 comapre 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

func (*Conn) Modify

func (l *Conn) Modify(modifyRequest *ModifyRequest) error
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)
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)
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)

Sets the time after a request is sent that a MessageTimeout triggers

func (*Conn) SimpleBind

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

func (*Conn) Start

func (l *Conn) Start()

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)
}

// Opertations via l are now encrypted
Output:

type Control

type Control interface {
	GetControlType() string
	Encode() *ber.Packet
	String() string
}

func DecodeControl

func DecodeControl(packet *ber.Packet) Control

func FindControl

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

type ControlBeheraPasswordPolicy

type ControlBeheraPasswordPolicy struct {
	Expire      int64
	Grace       int64
	Error       int8
	ErrorString string
}

func NewControlBeheraPasswordPolicy

func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy

func (*ControlBeheraPasswordPolicy) Encode

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

func (*ControlBeheraPasswordPolicy) GetControlType

func (c *ControlBeheraPasswordPolicy) GetControlType() string

func (*ControlBeheraPasswordPolicy) String

func (c *ControlBeheraPasswordPolicy) String() string

type ControlManageDsaIT

type ControlManageDsaIT struct {
	Criticality bool
}

func NewControlManageDsaIT

func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT

func (*ControlManageDsaIT) Encode

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

func (*ControlManageDsaIT) GetControlType

func (c *ControlManageDsaIT) GetControlType() string

func (*ControlManageDsaIT) String

func (c *ControlManageDsaIT) String() string

type ControlPaging

type ControlPaging struct {
	PagingSize uint32
	Cookie     []byte
}

func NewControlPaging

func NewControlPaging(pagingSize uint32) *ControlPaging

func (*ControlPaging) Encode

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

func (*ControlPaging) GetControlType

func (c *ControlPaging) GetControlType() string

func (*ControlPaging) SetCookie

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

func (*ControlPaging) String

func (c *ControlPaging) String() string

type ControlString

type ControlString struct {
	ControlType  string
	Criticality  bool
	ControlValue string
}

func NewControlString

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

func (*ControlString) Encode

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

func (*ControlString) GetControlType

func (c *ControlString) GetControlType() string

func (*ControlString) String

func (c *ControlString) String() string

type ControlVChuPasswordMustChange

type ControlVChuPasswordMustChange struct {
	MustChange bool
}

func (*ControlVChuPasswordMustChange) Encode

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

func (*ControlVChuPasswordMustChange) GetControlType

func (c *ControlVChuPasswordMustChange) GetControlType() string

func (*ControlVChuPasswordMustChange) String

type ControlVChuPasswordWarning

type ControlVChuPasswordWarning struct {
	Expire int64
}

func (*ControlVChuPasswordWarning) Encode

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

func (*ControlVChuPasswordWarning) GetControlType

func (c *ControlVChuPasswordWarning) GetControlType() string

func (*ControlVChuPasswordWarning) String

func (c *ControlVChuPasswordWarning) String() string

type DN

type DN struct {
	RDNs []*RelativeDN
}

func ParseDN

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

func (*DN) Append

func (dn *DN) Append(other *DN)

appends the "other" DN to the "dn", e.g.

dn, err := ldap.ParseDN("CN=Someone")
base, err := ldap.ParseDN("ou=people,dc=example,dc=org")
dn.Append(base) -> "cn=Someone,ou=people,dc=example,dc=org"

func (*DN) Clone

func (dn *DN) Clone() *DN

Returns a clone of the DN

func (*DN) Equal

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

check if all RDNs of both DNs are equal

func (*DN) IsSubordinate

func (dn *DN) IsSubordinate(other *DN) bool

Returns true if the "other" DN is a parent of "dn"

func (*DN) Move

func (dn *DN) Move(newBase *DN)

Moves the first RDN to the new base

func (*DN) Parent

func (dn *DN) Parent() *DN

Returns the parent of the "dn" as a cloned *DN

func (*DN) RDN

func (dn *DN) RDN() string

Returns the value of the first RDN, e.g.

dn, err := ldap.ParseDN("uid=someone,ou=people,dc=example,dc=org")
dn.RDN() -> "someone"

func (*DN) Rename

func (dn *DN) Rename(rdn *RelativeDN)

Changes the first RDN of DN to the given one

func (*DN) String

func (dn *DN) String() string

Returns the stringified version of a *DN, the RDN values are escaped

func (*DN) Strip

func (dn *DN) Strip(base *DN) error

removes the "other" DN from the "dn", e.g.

dn, err := ldap.ParseDN(""cn=Someone,ou=people,dc=example,dc=org")
base, err := ldap.ParseDN("ou=people,dc=example,dc=org")
dn.Strip(base) -> "cn=Someone"

Note: the "other" DN must be a parent of the "dn"

type DNs

type DNs []*DN

Sorting DNs:

all := []*ldap.DN{dn1, dn2, dn3, dn4}
sort.Sort(DNs(all))
for _, dn := range all {
   println(dn.String())
}

The result order from deepest part in tree upwards, so you could easily search for all dns in a base, sort them and then remove every DN in that order to remove the tree (including the search base)

func (DNs) Len

func (d DNs) Len() int

func (DNs) Less

func (d DNs) Less(i, j int) bool

func (DNs) Swap

func (d DNs) Swap(i, j int)

type DelRequest

type DelRequest struct {
	DN       string
	Controls []Control
}

func NewDelRequest

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

type Entry

type Entry struct {
	DN         string
	Attributes []*EntryAttribute
}

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

func (*Entry) GetAttributeValues

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

func (*Entry) GetRawAttributeValue

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

func (*Entry) GetRawAttributeValues

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

func (*Entry) PrettyPrint

func (e *Entry) PrettyPrint(indent int)

func (*Entry) Print

func (e *Entry) Print()

type EntryAttribute

type EntryAttribute struct {
	Name       string
	Values     []string
	ByteValues [][]byte
}

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)

func (*EntryAttribute) Print

func (e *EntryAttribute) Print()

type Error

type Error struct {
	Err        error
	ResultCode uint8
}

func (*Error) Error

func (e *Error) Error() string

type LDIF

type LDIF struct {
	RelaxedParser bool // ignore parsing errors in a line
	Entries       []*Entry
	// contains filtered or unexported fields
}

A basic LDIF parser. This one does currently just support LDIFs like they're generated by tools like ldapsearch(1) / slapcat(8). Change records are not supported.

func (*LDIF) Parse

func (l *LDIF) Parse(r io.Reader) (err error)

Parses the LDIF, the caller is responsible for closing the io.Reader if that's needed. This Parser may be called several times with different io.Readers to combine the files.

type ModifyRequest

type ModifyRequest struct {
	DN                string
	AddAttributes     []PartialAttribute
	DeleteAttributes  []PartialAttribute
	ReplaceAttributes []PartialAttribute
}

func NewModifyRequest

func NewModifyRequest(
	dn string,
) *ModifyRequest

func (*ModifyRequest) Add

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

func (*ModifyRequest) Delete

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

func (*ModifyRequest) Replace

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

type PacketResponse

type PacketResponse struct {
	Packet *ber.Packet
	Error  error
}

func (*PacketResponse) ReadPacket

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

type PartialAttribute

type PartialAttribute struct {
	Type string
	Vals []string
}

type PasswordModifyRequest

type PasswordModifyRequest struct {
	UserIdentity string
	OldPassword  string
	NewPassword  string
}

func NewPasswordModifyRequest

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

Create 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 string
}

type Pool

type Pool interface {
	// Get returns a new connection from the pool. Closing the connections puts
	// it back to the Pool. Closing it when the pool is destroyed or full will
	// be counted as an error.
	Get() (*PoolConn, error)

	// Close closes the pool and all its connections. After Close() the pool is
	// no longer usable.
	Close()

	// Len returns the current number of connections of the pool.
	Len() int
}

Pool interface describes a pool implementation. A pool should have maximum capacity. An ideal pool is threadsafe and easy to use.

func NewChannelPool

func NewChannelPool(initialCap, maxCap int, name string, factory PoolFactory, closeAt []uint8) (Pool, error)

NewChannelPool returns a new pool based on buffered channels with an initial capacity and maximum capacity. Factory is used when initial capacity is greater than zero to fill the pool. A zero initialCap doesn't fill the Pool until a new Get() is called. During a Get(), If there is no new connection available in the pool, a new connection will be created via the Factory() method.

closeAt will automagically mark the connection as unusable if the return code of the call is one of those passed, most likely you want to set this to something like

[]uint8{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork}

type PoolConn

type PoolConn struct {
	Conn Client
	// contains filtered or unexported fields
}

PoolConn implements Client to override the Close() method

func (*PoolConn) Add

func (p *PoolConn) Add(addRequest *AddRequest) error

func (*PoolConn) Alive

func (p *PoolConn) Alive() bool

func (*PoolConn) Bind

func (p *PoolConn) Bind(username, password string) error

func (*PoolConn) Close

func (p *PoolConn) Close()

Close() puts the given connects back to the pool instead of closing it.

func (*PoolConn) Compare

func (p *PoolConn) Compare(dn, attribute, value string) (bool, error)

func (*PoolConn) Del

func (p *PoolConn) Del(delRequest *DelRequest) error

func (*PoolConn) MarkUnusable

func (p *PoolConn) MarkUnusable()

MarkUnusable() marks the connection not usable any more, to let the pool close it instead of returning it to pool.

func (*PoolConn) Modify

func (p *PoolConn) Modify(modifyRequest *ModifyRequest) error

func (*PoolConn) PasswordModify

func (p *PoolConn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)

func (*PoolConn) Search

func (p *PoolConn) Search(searchRequest *SearchRequest) (*SearchResult, error)

func (*PoolConn) SearchWithPaging

func (p *PoolConn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)

func (*PoolConn) SimpleBind

func (p *PoolConn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error)

func (*PoolConn) Start

func (p *PoolConn) Start()

func (*PoolConn) StartTLS

func (p *PoolConn) StartTLS(config *tls.Config) error

type PoolFactory

type PoolFactory func(string) (Client, error)

PoolFactory is a function to create new connections.

type RelativeDN

type RelativeDN struct {
	Attributes []*AttributeTypeAndValue
}

func (*RelativeDN) Equal

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

Check if all types and values of both RDNs are equal, the result may be influenced by the value of RDNCompareFold.

func (*RelativeDN) Less

func (r *RelativeDN) Less(o *RelativeDN) bool

type SearchRequest

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

func NewSearchRequest

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

type SearchResult

type SearchResult struct {
	Entries   []*Entry
	Referrals []string
	Controls  []Control
}

func (*SearchResult) PrettyPrint

func (s *SearchResult) PrettyPrint(indent int)

func (*SearchResult) Print

func (s *SearchResult) Print()

type SimpleBindRequest

type SimpleBindRequest struct {
	Username string
	Password string
	Controls []Control
}

func NewSimpleBindRequest

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

type SimpleBindResult

type SimpleBindResult struct {
	Controls []Control
}

Jump to

Keyboard shortcuts

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