search.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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. const (
  68. ScopeBaseObject = 0
  69. ScopeSingleLevel = 1
  70. ScopeWholeSubtree = 2
  71. )
  72. var ScopeMap = map[int]string{
  73. ScopeBaseObject: "Base Object",
  74. ScopeSingleLevel: "Single Level",
  75. ScopeWholeSubtree: "Whole Subtree",
  76. }
  77. const (
  78. NeverDerefAliases = 0
  79. DerefInSearching = 1
  80. DerefFindingBaseObj = 2
  81. DerefAlways = 3
  82. )
  83. var DerefMap = map[int]string{
  84. NeverDerefAliases: "NeverDerefAliases",
  85. DerefInSearching: "DerefInSearching",
  86. DerefFindingBaseObj: "DerefFindingBaseObj",
  87. DerefAlways: "DerefAlways",
  88. }
  89. // NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
  90. // The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
  91. // same input map of attributes, the output entry will contain the same order of attributes
  92. func NewEntry(dn string, attributes map[string][]string) *Entry {
  93. var attributeNames []string
  94. for attributeName := range attributes {
  95. attributeNames = append(attributeNames, attributeName)
  96. }
  97. sort.Strings(attributeNames)
  98. var encodedAttributes []*EntryAttribute
  99. for _, attributeName := range attributeNames {
  100. encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
  101. }
  102. return &Entry{
  103. DN: dn,
  104. Attributes: encodedAttributes,
  105. }
  106. }
  107. type Entry struct {
  108. DN string
  109. Attributes []*EntryAttribute
  110. }
  111. func (e *Entry) GetAttributeValues(attribute string) []string {
  112. for _, attr := range e.Attributes {
  113. if attr.Name == attribute {
  114. return attr.Values
  115. }
  116. }
  117. return []string{}
  118. }
  119. func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
  120. for _, attr := range e.Attributes {
  121. if attr.Name == attribute {
  122. return attr.ByteValues
  123. }
  124. }
  125. return [][]byte{}
  126. }
  127. func (e *Entry) GetAttributeValue(attribute string) string {
  128. values := e.GetAttributeValues(attribute)
  129. if len(values) == 0 {
  130. return ""
  131. }
  132. return values[0]
  133. }
  134. func (e *Entry) GetRawAttributeValue(attribute string) []byte {
  135. values := e.GetRawAttributeValues(attribute)
  136. if len(values) == 0 {
  137. return []byte{}
  138. }
  139. return values[0]
  140. }
  141. func (e *Entry) Print() {
  142. fmt.Printf("DN: %s\n", e.DN)
  143. for _, attr := range e.Attributes {
  144. attr.Print()
  145. }
  146. }
  147. func (e *Entry) PrettyPrint(indent int) {
  148. fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
  149. for _, attr := range e.Attributes {
  150. attr.PrettyPrint(indent + 2)
  151. }
  152. }
  153. // NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
  154. func NewEntryAttribute(name string, values []string) *EntryAttribute {
  155. var bytes [][]byte
  156. for _, value := range values {
  157. bytes = append(bytes, []byte(value))
  158. }
  159. return &EntryAttribute{
  160. Name: name,
  161. Values: values,
  162. ByteValues: bytes,
  163. }
  164. }
  165. type EntryAttribute struct {
  166. Name string
  167. Values []string
  168. ByteValues [][]byte
  169. }
  170. func (e *EntryAttribute) Print() {
  171. fmt.Printf("%s: %s\n", e.Name, e.Values)
  172. }
  173. func (e *EntryAttribute) PrettyPrint(indent int) {
  174. fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
  175. }
  176. type SearchResult struct {
  177. Entries []*Entry
  178. Referrals []string
  179. Controls []Control
  180. }
  181. func (s *SearchResult) Print() {
  182. for _, entry := range s.Entries {
  183. entry.Print()
  184. }
  185. }
  186. func (s *SearchResult) PrettyPrint(indent int) {
  187. for _, entry := range s.Entries {
  188. entry.PrettyPrint(indent)
  189. }
  190. }
  191. type SearchRequest struct {
  192. BaseDN string
  193. Scope int
  194. DerefAliases int
  195. SizeLimit int
  196. TimeLimit int
  197. TypesOnly bool
  198. Filter string
  199. Attributes []string
  200. Controls []Control
  201. }
  202. func (s *SearchRequest) encode() (*ber.Packet, error) {
  203. request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
  204. request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN"))
  205. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope"))
  206. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases"))
  207. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit"))
  208. request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit"))
  209. request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only"))
  210. // compile and encode filter
  211. filterPacket, err := CompileFilter(s.Filter)
  212. if err != nil {
  213. return nil, err
  214. }
  215. request.AppendChild(filterPacket)
  216. // encode attributes
  217. attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
  218. for _, attribute := range s.Attributes {
  219. attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
  220. }
  221. request.AppendChild(attributesPacket)
  222. return request, nil
  223. }
  224. func NewSearchRequest(
  225. BaseDN string,
  226. Scope, DerefAliases, SizeLimit, TimeLimit int,
  227. TypesOnly bool,
  228. Filter string,
  229. Attributes []string,
  230. Controls []Control,
  231. ) *SearchRequest {
  232. return &SearchRequest{
  233. BaseDN: BaseDN,
  234. Scope: Scope,
  235. DerefAliases: DerefAliases,
  236. SizeLimit: SizeLimit,
  237. TimeLimit: TimeLimit,
  238. TypesOnly: TypesOnly,
  239. Filter: Filter,
  240. Attributes: Attributes,
  241. Controls: Controls,
  242. }
  243. }
  244. // SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the
  245. // search request. All paged LDAP query responses will be buffered and the final result will be returned atomically.
  246. // The following four cases are possible given the arguments:
  247. // - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
  248. // - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
  249. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
  250. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
  251. // A requested pagingSize of 0 is interpreted as no limit by LDAP servers.
  252. func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
  253. var pagingControl *ControlPaging
  254. control := FindControl(searchRequest.Controls, ControlTypePaging)
  255. if control == nil {
  256. pagingControl = NewControlPaging(pagingSize)
  257. searchRequest.Controls = append(searchRequest.Controls, pagingControl)
  258. } else {
  259. castControl, ok := control.(*ControlPaging)
  260. if !ok {
  261. return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
  262. }
  263. if castControl.PagingSize != pagingSize {
  264. return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
  265. }
  266. pagingControl = castControl
  267. }
  268. searchResult := new(SearchResult)
  269. for {
  270. result, err := l.Search(searchRequest)
  271. l.Debug.Printf("Looking for Paging Control...")
  272. if err != nil {
  273. return searchResult, err
  274. }
  275. if result == nil {
  276. return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
  277. }
  278. for _, entry := range result.Entries {
  279. searchResult.Entries = append(searchResult.Entries, entry)
  280. }
  281. for _, referral := range result.Referrals {
  282. searchResult.Referrals = append(searchResult.Referrals, referral)
  283. }
  284. for _, control := range result.Controls {
  285. searchResult.Controls = append(searchResult.Controls, control)
  286. }
  287. l.Debug.Printf("Looking for Paging Control...")
  288. pagingResult := FindControl(result.Controls, ControlTypePaging)
  289. if pagingResult == nil {
  290. pagingControl = nil
  291. l.Debug.Printf("Could not find paging control. Breaking...")
  292. break
  293. }
  294. cookie := pagingResult.(*ControlPaging).Cookie
  295. if len(cookie) == 0 {
  296. pagingControl = nil
  297. l.Debug.Printf("Could not find cookie. Breaking...")
  298. break
  299. }
  300. pagingControl.SetCookie(cookie)
  301. }
  302. if pagingControl != nil {
  303. l.Debug.Printf("Abandoning Paging...")
  304. pagingControl.PagingSize = 0
  305. l.Search(searchRequest)
  306. }
  307. return searchResult, nil
  308. }
  309. func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
  310. messageID := l.nextMessageID()
  311. packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
  312. packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
  313. // encode search request
  314. encodedSearchRequest, err := searchRequest.encode()
  315. if err != nil {
  316. return nil, err
  317. }
  318. packet.AppendChild(encodedSearchRequest)
  319. // encode search controls
  320. if searchRequest.Controls != nil {
  321. packet.AppendChild(encodeControls(searchRequest.Controls))
  322. }
  323. l.Debug.PrintPacket(packet)
  324. channel, err := l.sendMessage(packet)
  325. if err != nil {
  326. return nil, err
  327. }
  328. if channel == nil {
  329. return nil, NewError(ErrorNetwork, errors.New("ldap: could not send message"))
  330. }
  331. defer l.finishMessage(messageID)
  332. result := &SearchResult{
  333. Entries: make([]*Entry, 0),
  334. Referrals: make([]string, 0),
  335. Controls: make([]Control, 0)}
  336. foundSearchResultDone := false
  337. for !foundSearchResultDone {
  338. l.Debug.Printf("%d: waiting for response", messageID)
  339. packet = <-channel
  340. l.Debug.Printf("%d: got response %p", messageID, packet)
  341. if packet == nil {
  342. return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
  343. }
  344. if l.Debug {
  345. if err := addLDAPDescriptions(packet); err != nil {
  346. return nil, err
  347. }
  348. ber.PrintPacket(packet)
  349. }
  350. switch packet.Children[1].Tag {
  351. case 4:
  352. entry := new(Entry)
  353. entry.DN = packet.Children[1].Children[0].Value.(string)
  354. for _, child := range packet.Children[1].Children[1].Children {
  355. attr := new(EntryAttribute)
  356. attr.Name = child.Children[0].Value.(string)
  357. for _, value := range child.Children[1].Children {
  358. attr.Values = append(attr.Values, value.Value.(string))
  359. attr.ByteValues = append(attr.ByteValues, value.ByteValue)
  360. }
  361. entry.Attributes = append(entry.Attributes, attr)
  362. }
  363. result.Entries = append(result.Entries, entry)
  364. case 5:
  365. resultCode, resultDescription := getLDAPResultCode(packet)
  366. if resultCode != 0 {
  367. return result, NewError(resultCode, errors.New(resultDescription))
  368. }
  369. if len(packet.Children) == 3 {
  370. for _, child := range packet.Children[2].Children {
  371. result.Controls = append(result.Controls, DecodeControl(child))
  372. }
  373. }
  374. foundSearchResultDone = true
  375. case 19:
  376. result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
  377. }
  378. }
  379. l.Debug.Printf("%d: returning", messageID)
  380. return result, nil
  381. }