mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	* [Vendor] update go-ldap to v3.0.3 * update go-ldap to v3.2.4 Co-authored-by: techknowlogick <techknowlogick@gitea.io>
		
			
				
	
	
		
			411 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			411 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
package ldap
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	ber "github.com/go-asn1-ber/asn1-ber"
 | 
						|
)
 | 
						|
 | 
						|
// scope choices
 | 
						|
const (
 | 
						|
	ScopeBaseObject   = 0
 | 
						|
	ScopeSingleLevel  = 1
 | 
						|
	ScopeWholeSubtree = 2
 | 
						|
)
 | 
						|
 | 
						|
// ScopeMap contains human readable descriptions of scope choices
 | 
						|
var ScopeMap = map[int]string{
 | 
						|
	ScopeBaseObject:   "Base Object",
 | 
						|
	ScopeSingleLevel:  "Single Level",
 | 
						|
	ScopeWholeSubtree: "Whole Subtree",
 | 
						|
}
 | 
						|
 | 
						|
// derefAliases
 | 
						|
const (
 | 
						|
	NeverDerefAliases   = 0
 | 
						|
	DerefInSearching    = 1
 | 
						|
	DerefFindingBaseObj = 2
 | 
						|
	DerefAlways         = 3
 | 
						|
)
 | 
						|
 | 
						|
// DerefMap contains human readable descriptions of derefAliases choices
 | 
						|
var DerefMap = map[int]string{
 | 
						|
	NeverDerefAliases:   "NeverDerefAliases",
 | 
						|
	DerefInSearching:    "DerefInSearching",
 | 
						|
	DerefFindingBaseObj: "DerefFindingBaseObj",
 | 
						|
	DerefAlways:         "DerefAlways",
 | 
						|
}
 | 
						|
 | 
						|
// 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 NewEntry(dn string, attributes map[string][]string) *Entry {
 | 
						|
	var attributeNames []string
 | 
						|
	for attributeName := range attributes {
 | 
						|
		attributeNames = append(attributeNames, attributeName)
 | 
						|
	}
 | 
						|
	sort.Strings(attributeNames)
 | 
						|
 | 
						|
	var encodedAttributes []*EntryAttribute
 | 
						|
	for _, attributeName := range attributeNames {
 | 
						|
		encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
 | 
						|
	}
 | 
						|
	return &Entry{
 | 
						|
		DN:         dn,
 | 
						|
		Attributes: encodedAttributes,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Entry represents a single search result entry
 | 
						|
type Entry struct {
 | 
						|
	// DN is the distinguished name of the entry
 | 
						|
	DN string
 | 
						|
	// Attributes are the returned attributes for the entry
 | 
						|
	Attributes []*EntryAttribute
 | 
						|
}
 | 
						|
 | 
						|
// GetAttributeValues returns the values for the named attribute, or an empty list
 | 
						|
func (e *Entry) GetAttributeValues(attribute string) []string {
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		if attr.Name == attribute {
 | 
						|
			return attr.Values
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return []string{}
 | 
						|
}
 | 
						|
 | 
						|
// GetEqualFoldAttributeValues returns the values for the named attribute, or an
 | 
						|
// empty list. Attribute matching is done with strings.EqualFold.
 | 
						|
func (e *Entry) GetEqualFoldAttributeValues(attribute string) []string {
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		if strings.EqualFold(attribute, attr.Name) {
 | 
						|
			return attr.Values
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return []string{}
 | 
						|
}
 | 
						|
 | 
						|
// GetRawAttributeValues returns the byte values for the named attribute, or an empty list
 | 
						|
func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		if attr.Name == attribute {
 | 
						|
			return attr.ByteValues
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return [][]byte{}
 | 
						|
}
 | 
						|
 | 
						|
// GetEqualFoldRawAttributeValues returns the byte values for the named attribute, or an empty list
 | 
						|
func (e *Entry) GetEqualFoldRawAttributeValues(attribute string) [][]byte {
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		if strings.EqualFold(attr.Name, attribute) {
 | 
						|
			return attr.ByteValues
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return [][]byte{}
 | 
						|
}
 | 
						|
 | 
						|
// GetAttributeValue returns the first value for the named attribute, or ""
 | 
						|
func (e *Entry) GetAttributeValue(attribute string) string {
 | 
						|
	values := e.GetAttributeValues(attribute)
 | 
						|
	if len(values) == 0 {
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
	return values[0]
 | 
						|
}
 | 
						|
 | 
						|
// GetEqualFoldAttributeValue returns the first value for the named attribute, or "".
 | 
						|
// Attribute comparison is done with strings.EqualFold.
 | 
						|
func (e *Entry) GetEqualFoldAttributeValue(attribute string) string {
 | 
						|
	values := e.GetEqualFoldAttributeValues(attribute)
 | 
						|
	if len(values) == 0 {
 | 
						|
		return ""
 | 
						|
	}
 | 
						|
	return values[0]
 | 
						|
}
 | 
						|
 | 
						|
// GetRawAttributeValue returns the first value for the named attribute, or an empty slice
 | 
						|
func (e *Entry) GetRawAttributeValue(attribute string) []byte {
 | 
						|
	values := e.GetRawAttributeValues(attribute)
 | 
						|
	if len(values) == 0 {
 | 
						|
		return []byte{}
 | 
						|
	}
 | 
						|
	return values[0]
 | 
						|
}
 | 
						|
 | 
						|
// GetEqualFoldRawAttributeValue returns the first value for the named attribute, or an empty slice
 | 
						|
func (e *Entry) GetEqualFoldRawAttributeValue(attribute string) []byte {
 | 
						|
	values := e.GetEqualFoldRawAttributeValues(attribute)
 | 
						|
	if len(values) == 0 {
 | 
						|
		return []byte{}
 | 
						|
	}
 | 
						|
	return values[0]
 | 
						|
}
 | 
						|
 | 
						|
// Print outputs a human-readable description
 | 
						|
func (e *Entry) Print() {
 | 
						|
	fmt.Printf("DN: %s\n", e.DN)
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		attr.Print()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// PrettyPrint outputs a human-readable description indenting
 | 
						|
func (e *Entry) PrettyPrint(indent int) {
 | 
						|
	fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
 | 
						|
	for _, attr := range e.Attributes {
 | 
						|
		attr.PrettyPrint(indent + 2)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
 | 
						|
func NewEntryAttribute(name string, values []string) *EntryAttribute {
 | 
						|
	var bytes [][]byte
 | 
						|
	for _, value := range values {
 | 
						|
		bytes = append(bytes, []byte(value))
 | 
						|
	}
 | 
						|
	return &EntryAttribute{
 | 
						|
		Name:       name,
 | 
						|
		Values:     values,
 | 
						|
		ByteValues: bytes,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// EntryAttribute holds a single attribute
 | 
						|
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
 | 
						|
}
 | 
						|
 | 
						|
// Print outputs a human-readable description
 | 
						|
func (e *EntryAttribute) Print() {
 | 
						|
	fmt.Printf("%s: %s\n", e.Name, e.Values)
 | 
						|
}
 | 
						|
 | 
						|
// PrettyPrint outputs a human-readable description with indenting
 | 
						|
func (e *EntryAttribute) PrettyPrint(indent int) {
 | 
						|
	fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
 | 
						|
}
 | 
						|
 | 
						|
// SearchResult holds the server's response to a search request
 | 
						|
type SearchResult struct {
 | 
						|
	// Entries are the returned entries
 | 
						|
	Entries []*Entry
 | 
						|
	// Referrals are the returned referrals
 | 
						|
	Referrals []string
 | 
						|
	// Controls are the returned controls
 | 
						|
	Controls []Control
 | 
						|
}
 | 
						|
 | 
						|
// Print outputs a human-readable description
 | 
						|
func (s *SearchResult) Print() {
 | 
						|
	for _, entry := range s.Entries {
 | 
						|
		entry.Print()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// PrettyPrint outputs a human-readable description with indenting
 | 
						|
func (s *SearchResult) PrettyPrint(indent int) {
 | 
						|
	for _, entry := range s.Entries {
 | 
						|
		entry.PrettyPrint(indent)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// SearchRequest represents a search request to send to the server
 | 
						|
type SearchRequest struct {
 | 
						|
	BaseDN       string
 | 
						|
	Scope        int
 | 
						|
	DerefAliases int
 | 
						|
	SizeLimit    int
 | 
						|
	TimeLimit    int
 | 
						|
	TypesOnly    bool
 | 
						|
	Filter       string
 | 
						|
	Attributes   []string
 | 
						|
	Controls     []Control
 | 
						|
}
 | 
						|
 | 
						|
func (req *SearchRequest) appendTo(envelope *ber.Packet) error {
 | 
						|
	pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
 | 
						|
	pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.BaseDN, "Base DN"))
 | 
						|
	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.Scope), "Scope"))
 | 
						|
	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.DerefAliases), "Deref Aliases"))
 | 
						|
	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.SizeLimit), "Size Limit"))
 | 
						|
	pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.TimeLimit), "Time Limit"))
 | 
						|
	pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.TypesOnly, "Types Only"))
 | 
						|
	// compile and encode filter
 | 
						|
	filterPacket, err := CompileFilter(req.Filter)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	pkt.AppendChild(filterPacket)
 | 
						|
	// encode attributes
 | 
						|
	attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
 | 
						|
	for _, attribute := range req.Attributes {
 | 
						|
		attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
 | 
						|
	}
 | 
						|
	pkt.AppendChild(attributesPacket)
 | 
						|
 | 
						|
	envelope.AppendChild(pkt)
 | 
						|
	if len(req.Controls) > 0 {
 | 
						|
		envelope.AppendChild(encodeControls(req.Controls))
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// NewSearchRequest creates a new search request
 | 
						|
func NewSearchRequest(
 | 
						|
	BaseDN string,
 | 
						|
	Scope, DerefAliases, SizeLimit, TimeLimit int,
 | 
						|
	TypesOnly bool,
 | 
						|
	Filter string,
 | 
						|
	Attributes []string,
 | 
						|
	Controls []Control,
 | 
						|
) *SearchRequest {
 | 
						|
	return &SearchRequest{
 | 
						|
		BaseDN:       BaseDN,
 | 
						|
		Scope:        Scope,
 | 
						|
		DerefAliases: DerefAliases,
 | 
						|
		SizeLimit:    SizeLimit,
 | 
						|
		TimeLimit:    TimeLimit,
 | 
						|
		TypesOnly:    TypesOnly,
 | 
						|
		Filter:       Filter,
 | 
						|
		Attributes:   Attributes,
 | 
						|
		Controls:     Controls,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// 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 (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
 | 
						|
	var pagingControl *ControlPaging
 | 
						|
 | 
						|
	control := FindControl(searchRequest.Controls, ControlTypePaging)
 | 
						|
	if control == nil {
 | 
						|
		pagingControl = NewControlPaging(pagingSize)
 | 
						|
		searchRequest.Controls = append(searchRequest.Controls, pagingControl)
 | 
						|
	} else {
 | 
						|
		castControl, ok := control.(*ControlPaging)
 | 
						|
		if !ok {
 | 
						|
			return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
 | 
						|
		}
 | 
						|
		if castControl.PagingSize != pagingSize {
 | 
						|
			return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
 | 
						|
		}
 | 
						|
		pagingControl = castControl
 | 
						|
	}
 | 
						|
 | 
						|
	searchResult := new(SearchResult)
 | 
						|
	for {
 | 
						|
		result, err := l.Search(searchRequest)
 | 
						|
		l.Debug.Printf("Looking for Paging Control...")
 | 
						|
		if err != nil {
 | 
						|
			return searchResult, err
 | 
						|
		}
 | 
						|
		if result == nil {
 | 
						|
			return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
 | 
						|
		}
 | 
						|
 | 
						|
		for _, entry := range result.Entries {
 | 
						|
			searchResult.Entries = append(searchResult.Entries, entry)
 | 
						|
		}
 | 
						|
		for _, referral := range result.Referrals {
 | 
						|
			searchResult.Referrals = append(searchResult.Referrals, referral)
 | 
						|
		}
 | 
						|
		for _, control := range result.Controls {
 | 
						|
			searchResult.Controls = append(searchResult.Controls, control)
 | 
						|
		}
 | 
						|
 | 
						|
		l.Debug.Printf("Looking for Paging Control...")
 | 
						|
		pagingResult := FindControl(result.Controls, ControlTypePaging)
 | 
						|
		if pagingResult == nil {
 | 
						|
			pagingControl = nil
 | 
						|
			l.Debug.Printf("Could not find paging control.  Breaking...")
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		cookie := pagingResult.(*ControlPaging).Cookie
 | 
						|
		if len(cookie) == 0 {
 | 
						|
			pagingControl = nil
 | 
						|
			l.Debug.Printf("Could not find cookie.  Breaking...")
 | 
						|
			break
 | 
						|
		}
 | 
						|
		pagingControl.SetCookie(cookie)
 | 
						|
	}
 | 
						|
 | 
						|
	if pagingControl != nil {
 | 
						|
		l.Debug.Printf("Abandoning Paging...")
 | 
						|
		pagingControl.PagingSize = 0
 | 
						|
		l.Search(searchRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	return searchResult, nil
 | 
						|
}
 | 
						|
 | 
						|
// Search performs the given search request
 | 
						|
func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
 | 
						|
	msgCtx, err := l.doRequest(searchRequest)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer l.finishMessage(msgCtx)
 | 
						|
 | 
						|
	result := &SearchResult{
 | 
						|
		Entries:   make([]*Entry, 0),
 | 
						|
		Referrals: make([]string, 0),
 | 
						|
		Controls:  make([]Control, 0)}
 | 
						|
 | 
						|
	for {
 | 
						|
		packet, err := l.readPacket(msgCtx)
 | 
						|
		if err != nil {
 | 
						|
			return result, err
 | 
						|
		}
 | 
						|
 | 
						|
		switch packet.Children[1].Tag {
 | 
						|
		case 4:
 | 
						|
			entry := new(Entry)
 | 
						|
			entry.DN = packet.Children[1].Children[0].Value.(string)
 | 
						|
			for _, child := range packet.Children[1].Children[1].Children {
 | 
						|
				attr := new(EntryAttribute)
 | 
						|
				attr.Name = child.Children[0].Value.(string)
 | 
						|
				for _, value := range child.Children[1].Children {
 | 
						|
					attr.Values = append(attr.Values, value.Value.(string))
 | 
						|
					attr.ByteValues = append(attr.ByteValues, value.ByteValue)
 | 
						|
				}
 | 
						|
				entry.Attributes = append(entry.Attributes, attr)
 | 
						|
			}
 | 
						|
			result.Entries = append(result.Entries, entry)
 | 
						|
		case 5:
 | 
						|
			err := GetLDAPError(packet)
 | 
						|
			if err != nil {
 | 
						|
				return result, err
 | 
						|
			}
 | 
						|
			if len(packet.Children) == 3 {
 | 
						|
				for _, child := range packet.Children[2].Children {
 | 
						|
					decodedChild, err := DecodeControl(child)
 | 
						|
					if err != nil {
 | 
						|
						return result, fmt.Errorf("failed to decode child control: %s", err)
 | 
						|
					}
 | 
						|
					result.Controls = append(result.Controls, decodedChild)
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return result, nil
 | 
						|
		case 19:
 | 
						|
			result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |