本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

451 lines
15KB

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