search.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //
  5. // File contains Search functionality
  6. //
  7. // https://tools.ietf.org/html/rfc4511
  8. //
  9. // SearchRequest ::= [APPLICATION 3] SEQUENCE {
  10. // baseObject LDAPDN,
  11. // scope ENUMERATED {
  12. // baseObject (0),
  13. // singleLevel (1),
  14. // wholeSubtree (2),
  15. // ... },
  16. // derefAliases ENUMERATED {
  17. // neverDerefAliases (0),
  18. // derefInSearching (1),
  19. // derefFindingBaseObj (2),
  20. // derefAlways (3) },
  21. // sizeLimit INTEGER (0 .. maxInt),
  22. // timeLimit INTEGER (0 .. maxInt),
  23. // typesOnly BOOLEAN,
  24. // filter Filter,
  25. // attributes AttributeSelection }
  26. //
  27. // AttributeSelection ::= SEQUENCE OF selector LDAPString
  28. // -- The LDAPString is constrained to
  29. // -- <attributeSelector> in Section 4.5.1.8
  30. //
  31. // Filter ::= CHOICE {
  32. // and [0] SET SIZE (1..MAX) OF filter Filter,
  33. // or [1] SET SIZE (1..MAX) OF filter Filter,
  34. // not [2] Filter,
  35. // equalityMatch [3] AttributeValueAssertion,
  36. // substrings [4] SubstringFilter,
  37. // greaterOrEqual [5] AttributeValueAssertion,
  38. // lessOrEqual [6] AttributeValueAssertion,
  39. // present [7] AttributeDescription,
  40. // approxMatch [8] AttributeValueAssertion,
  41. // extensibleMatch [9] MatchingRuleAssertion,
  42. // ... }
  43. //
  44. // SubstringFilter ::= SEQUENCE {
  45. // type AttributeDescription,
  46. // substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
  47. // initial [0] AssertionValue, -- can occur at most once
  48. // any [1] AssertionValue,
  49. // final [2] AssertionValue } -- can occur at most once
  50. // }
  51. //
  52. // MatchingRuleAssertion ::= SEQUENCE {
  53. // matchingRule [1] MatchingRuleId OPTIONAL,
  54. // type [2] AttributeDescription OPTIONAL,
  55. // matchValue [3] AssertionValue,
  56. // dnAttributes [4] BOOLEAN DEFAULT FALSE }
  57. //
  58. //
  59. package ldap
  60. import (
  61. "errors"
  62. "fmt"
  63. "sort"
  64. "strings"
  65. "gopkg.in/asn1-ber.v1"
  66. )
  67. // scope choices
  68. const (
  69. ScopeBaseObject = 0
  70. ScopeSingleLevel = 1
  71. ScopeWholeSubtree = 2
  72. )
  73. // ScopeMap contains human readable descriptions of scope choices
  74. var ScopeMap = map[int]string{
  75. ScopeBaseObject: "Base Object",
  76. ScopeSingleLevel: "Single Level",
  77. ScopeWholeSubtree: "Whole Subtree",
  78. }
  79. // derefAliases
  80. const (
  81. NeverDerefAliases = 0
  82. DerefInSearching = 1
  83. DerefFindingBaseObj = 2
  84. DerefAlways = 3
  85. )
  86. // DerefMap contains human readable descriptions of derefAliases choices
  87. var DerefMap = map[int]string{
  88. NeverDerefAliases: "NeverDerefAliases",
  89. DerefInSearching: "DerefInSearching",
  90. DerefFindingBaseObj: "DerefFindingBaseObj",
  91. DerefAlways: "DerefAlways",
  92. }
  93. // NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
  94. // The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
  95. // same input map of attributes, the output entry will contain the same order of attributes
  96. func NewEntry(dn string, attributes map[string][]string) *Entry {
  97. var attributeNames []string
  98. for attributeName := range attributes {
  99. attributeNames = append(attributeNames, attributeName)
  100. }
  101. sort.Strings(attributeNames)
  102. var encodedAttributes []*EntryAttribute
  103. for _, attributeName := range attributeNames {
  104. encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
  105. }
  106. return &Entry{
  107. DN: dn,
  108. Attributes: encodedAttributes,
  109. }
  110. }
  111. // Entry represents a single search result entry
  112. type Entry struct {
  113. // DN is the distinguished name of the entry
  114. DN string
  115. // Attributes are the returned attributes for the entry
  116. Attributes []*EntryAttribute
  117. }
  118. // GetAttributeValues returns the values for the named attribute, or an empty list
  119. func (e *Entry) GetAttributeValues(attribute string) []string {
  120. for _, attr := range e.Attributes {
  121. if attr.Name == attribute {
  122. return attr.Values
  123. }
  124. }
  125. return []string{}
  126. }
  127. // GetRawAttributeValues returns the byte values for the named attribute, or an empty list
  128. func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
  129. for _, attr := range e.Attributes {
  130. if attr.Name == attribute {
  131. return attr.ByteValues
  132. }
  133. }
  134. return [][]byte{}
  135. }
  136. // GetAttributeValue returns the first value for the named attribute, or ""
  137. func (e *Entry) GetAttributeValue(attribute string) string {
  138. values := e.GetAttributeValues(attribute)
  139. if len(values) == 0 {
  140. return ""
  141. }
  142. return values[0]
  143. }
  144. // GetRawAttributeValue returns the first value for the named attribute, or an empty slice
  145. func (e *Entry) GetRawAttributeValue(attribute string) []byte {
  146. values := e.GetRawAttributeValues(attribute)
  147. if len(values) == 0 {
  148. return []byte{}
  149. }
  150. return values[0]
  151. }
  152. // Print outputs a human-readable description
  153. func (e *Entry) Print() {
  154. fmt.Printf("DN: %s\n", e.DN)
  155. for _, attr := range e.Attributes {
  156. attr.Print()
  157. }
  158. }
  159. // PrettyPrint outputs a human-readable description indenting
  160. func (e *Entry) PrettyPrint(indent int) {
  161. fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
  162. for _, attr := range e.Attributes {
  163. attr.PrettyPrint(indent + 2)
  164. }
  165. }
  166. // NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
  167. func NewEntryAttribute(name string, values []string) *EntryAttribute {
  168. var bytes [][]byte
  169. for _, value := range values {
  170. bytes = append(bytes, []byte(value))
  171. }
  172. return &EntryAttribute{
  173. Name: name,
  174. Values: values,
  175. ByteValues: bytes,
  176. }
  177. }
  178. // EntryAttribute holds a single attribute
  179. type EntryAttribute struct {
  180. // Name is the name of the attribute
  181. Name string
  182. // Values contain the string values of the attribute
  183. Values []string
  184. // ByteValues contain the raw values of the attribute
  185. ByteValues [][]byte
  186. }
  187. // Print outputs a human-readable description
  188. func (e *EntryAttribute) Print() {
  189. fmt.Printf("%s: %s\n", e.Name, e.Values)
  190. }
  191. // PrettyPrint outputs a human-readable description with indenting
  192. func (e *EntryAttribute) PrettyPrint(indent int) {
  193. fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
  194. }
  195. // SearchResult holds the server's response to a search request
  196. type SearchResult struct {
  197. // Entries are the returned entries
  198. Entries []*Entry
  199. // Referrals are the returned referrals
  200. Referrals []string
  201. // Controls are the returned controls
  202. Controls []Control
  203. }
  204. // Print outputs a human-readable description
  205. func (s *SearchResult) Print() {
  206. for _, entry := range s.Entries {
  207. entry.Print()
  208. }
  209. }
  210. // PrettyPrint outputs a human-readable description with indenting
  211. func (s *SearchResult) PrettyPrint(indent int) {
  212. for _, entry := range s.Entries {
  213. entry.PrettyPrint(indent)
  214. }
  215. }
  216. // SearchRequest represents a search request to send to the server
  217. type SearchRequest struct {
  218. BaseDN string
  219. Scope int
  220. DerefAliases int
  221. SizeLimit int
  222. TimeLimit int
  223. TypesOnly bool
  224. Filter string
  225. Attributes []string
  226. Controls []Control
  227. }
  228. func (s *SearchRequest) encode() (*ber.Packet, error) {
  229. request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
  230. request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN"))
  231. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope"))
  232. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases"))
  233. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit"))
  234. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit"))
  235. request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only"))
  236. // compile and encode filter
  237. filterPacket, err := CompileFilter(s.Filter)
  238. if err != nil {
  239. return nil, err
  240. }
  241. request.AppendChild(filterPacket)
  242. // encode attributes
  243. attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
  244. for _, attribute := range s.Attributes {
  245. attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
  246. }
  247. request.AppendChild(attributesPacket)
  248. return request, nil
  249. }
  250. // NewSearchRequest creates a new search request
  251. func NewSearchRequest(
  252. BaseDN string,
  253. Scope, DerefAliases, SizeLimit, TimeLimit int,
  254. TypesOnly bool,
  255. Filter string,
  256. Attributes []string,
  257. Controls []Control,
  258. ) *SearchRequest {
  259. return &SearchRequest{
  260. BaseDN: BaseDN,
  261. Scope: Scope,
  262. DerefAliases: DerefAliases,
  263. SizeLimit: SizeLimit,
  264. TimeLimit: TimeLimit,
  265. TypesOnly: TypesOnly,
  266. Filter: Filter,
  267. Attributes: Attributes,
  268. Controls: Controls,
  269. }
  270. }
  271. // SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the
  272. // search request. All paged LDAP query responses will be buffered and the final result will be returned atomically.
  273. // The following four cases are possible given the arguments:
  274. // - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
  275. // - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
  276. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
  277. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
  278. // A requested pagingSize of 0 is interpreted as no limit by LDAP servers.
  279. func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
  280. var pagingControl *ControlPaging
  281. control := FindControl(searchRequest.Controls, ControlTypePaging)
  282. if control == nil {
  283. pagingControl = NewControlPaging(pagingSize)
  284. searchRequest.Controls = append(searchRequest.Controls, pagingControl)
  285. } else {
  286. castControl, ok := control.(*ControlPaging)
  287. if !ok {
  288. return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
  289. }
  290. if castControl.PagingSize != pagingSize {
  291. return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
  292. }
  293. pagingControl = castControl
  294. }
  295. searchResult := new(SearchResult)
  296. for {
  297. result, err := l.Search(searchRequest)
  298. l.Debug.Printf("Looking for Paging Control...")
  299. if err != nil {
  300. return searchResult, err
  301. }
  302. if result == nil {
  303. return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
  304. }
  305. for _, entry := range result.Entries {
  306. searchResult.Entries = append(searchResult.Entries, entry)
  307. }
  308. for _, referral := range result.Referrals {
  309. searchResult.Referrals = append(searchResult.Referrals, referral)
  310. }
  311. for _, control := range result.Controls {
  312. searchResult.Controls = append(searchResult.Controls, control)
  313. }
  314. l.Debug.Printf("Looking for Paging Control...")
  315. pagingResult := FindControl(result.Controls, ControlTypePaging)
  316. if pagingResult == nil {
  317. pagingControl = nil
  318. l.Debug.Printf("Could not find paging control. Breaking...")
  319. break
  320. }
  321. cookie := pagingResult.(*ControlPaging).Cookie
  322. if len(cookie) == 0 {
  323. pagingControl = nil
  324. l.Debug.Printf("Could not find cookie. Breaking...")
  325. break
  326. }
  327. pagingControl.SetCookie(cookie)
  328. }
  329. if pagingControl != nil {
  330. l.Debug.Printf("Abandoning Paging...")
  331. pagingControl.PagingSize = 0
  332. l.Search(searchRequest)
  333. }
  334. return searchResult, nil
  335. }
  336. // Search performs the given search request
  337. func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
  338. packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
  339. packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
  340. // encode search request
  341. encodedSearchRequest, err := searchRequest.encode()
  342. if err != nil {
  343. return nil, err
  344. }
  345. packet.AppendChild(encodedSearchRequest)
  346. // encode search controls
  347. if searchRequest.Controls != nil {
  348. packet.AppendChild(encodeControls(searchRequest.Controls))
  349. }
  350. l.Debug.PrintPacket(packet)
  351. msgCtx, err := l.sendMessage(packet)
  352. if err != nil {
  353. return nil, err
  354. }
  355. defer l.finishMessage(msgCtx)
  356. result := &SearchResult{
  357. Entries: make([]*Entry, 0),
  358. Referrals: make([]string, 0),
  359. Controls: make([]Control, 0)}
  360. foundSearchResultDone := false
  361. for !foundSearchResultDone {
  362. l.Debug.Printf("%d: waiting for response", msgCtx.id)
  363. packetResponse, ok := <-msgCtx.responses
  364. if !ok {
  365. return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
  366. }
  367. packet, err = packetResponse.ReadPacket()
  368. l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
  369. if err != nil {
  370. return nil, err
  371. }
  372. if l.Debug {
  373. if err := addLDAPDescriptions(packet); err != nil {
  374. return nil, err
  375. }
  376. ber.PrintPacket(packet)
  377. }
  378. switch packet.Children[1].Tag {
  379. case 4:
  380. entry := new(Entry)
  381. entry.DN = packet.Children[1].Children[0].Value.(string)
  382. for _, child := range packet.Children[1].Children[1].Children {
  383. attr := new(EntryAttribute)
  384. attr.Name = child.Children[0].Value.(string)
  385. for _, value := range child.Children[1].Children {
  386. attr.Values = append(attr.Values, value.Value.(string))
  387. attr.ByteValues = append(attr.ByteValues, value.ByteValue)
  388. }
  389. entry.Attributes = append(entry.Attributes, attr)
  390. }
  391. result.Entries = append(result.Entries, entry)
  392. case 5:
  393. resultCode, resultDescription := getLDAPResultCode(packet)
  394. if resultCode != 0 {
  395. return result, NewError(resultCode, errors.New(resultDescription))
  396. }
  397. if len(packet.Children) == 3 {
  398. for _, child := range packet.Children[2].Children {
  399. result.Controls = append(result.Controls, DecodeControl(child))
  400. }
  401. }
  402. foundSearchResultDone = true
  403. case 19:
  404. result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
  405. }
  406. }
  407. l.Debug.Printf("%d: returning", msgCtx.id)
  408. return result, nil
  409. }