search.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. package ldap
  2. import (
  3. "errors"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. ber "github.com/go-asn1-ber/asn1-ber"
  8. )
  9. // scope choices
  10. const (
  11. ScopeBaseObject = 0
  12. ScopeSingleLevel = 1
  13. ScopeWholeSubtree = 2
  14. )
  15. // ScopeMap contains human readable descriptions of scope choices
  16. var ScopeMap = map[int]string{
  17. ScopeBaseObject: "Base Object",
  18. ScopeSingleLevel: "Single Level",
  19. ScopeWholeSubtree: "Whole Subtree",
  20. }
  21. // derefAliases
  22. const (
  23. NeverDerefAliases = 0
  24. DerefInSearching = 1
  25. DerefFindingBaseObj = 2
  26. DerefAlways = 3
  27. )
  28. // DerefMap contains human readable descriptions of derefAliases choices
  29. var DerefMap = map[int]string{
  30. NeverDerefAliases: "NeverDerefAliases",
  31. DerefInSearching: "DerefInSearching",
  32. DerefFindingBaseObj: "DerefFindingBaseObj",
  33. DerefAlways: "DerefAlways",
  34. }
  35. // NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs.
  36. // The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the
  37. // same input map of attributes, the output entry will contain the same order of attributes
  38. func NewEntry(dn string, attributes map[string][]string) *Entry {
  39. var attributeNames []string
  40. for attributeName := range attributes {
  41. attributeNames = append(attributeNames, attributeName)
  42. }
  43. sort.Strings(attributeNames)
  44. var encodedAttributes []*EntryAttribute
  45. for _, attributeName := range attributeNames {
  46. encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName]))
  47. }
  48. return &Entry{
  49. DN: dn,
  50. Attributes: encodedAttributes,
  51. }
  52. }
  53. // Entry represents a single search result entry
  54. type Entry struct {
  55. // DN is the distinguished name of the entry
  56. DN string
  57. // Attributes are the returned attributes for the entry
  58. Attributes []*EntryAttribute
  59. }
  60. // GetAttributeValues returns the values for the named attribute, or an empty list
  61. func (e *Entry) GetAttributeValues(attribute string) []string {
  62. for _, attr := range e.Attributes {
  63. if attr.Name == attribute {
  64. return attr.Values
  65. }
  66. }
  67. return []string{}
  68. }
  69. // GetRawAttributeValues returns the byte values for the named attribute, or an empty list
  70. func (e *Entry) GetRawAttributeValues(attribute string) [][]byte {
  71. for _, attr := range e.Attributes {
  72. if attr.Name == attribute {
  73. return attr.ByteValues
  74. }
  75. }
  76. return [][]byte{}
  77. }
  78. // GetAttributeValue returns the first value for the named attribute, or ""
  79. func (e *Entry) GetAttributeValue(attribute string) string {
  80. values := e.GetAttributeValues(attribute)
  81. if len(values) == 0 {
  82. return ""
  83. }
  84. return values[0]
  85. }
  86. // GetRawAttributeValue returns the first value for the named attribute, or an empty slice
  87. func (e *Entry) GetRawAttributeValue(attribute string) []byte {
  88. values := e.GetRawAttributeValues(attribute)
  89. if len(values) == 0 {
  90. return []byte{}
  91. }
  92. return values[0]
  93. }
  94. // Print outputs a human-readable description
  95. func (e *Entry) Print() {
  96. fmt.Printf("DN: %s\n", e.DN)
  97. for _, attr := range e.Attributes {
  98. attr.Print()
  99. }
  100. }
  101. // PrettyPrint outputs a human-readable description indenting
  102. func (e *Entry) PrettyPrint(indent int) {
  103. fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN)
  104. for _, attr := range e.Attributes {
  105. attr.PrettyPrint(indent + 2)
  106. }
  107. }
  108. // NewEntryAttribute returns a new EntryAttribute with the desired key-value pair
  109. func NewEntryAttribute(name string, values []string) *EntryAttribute {
  110. var bytes [][]byte
  111. for _, value := range values {
  112. bytes = append(bytes, []byte(value))
  113. }
  114. return &EntryAttribute{
  115. Name: name,
  116. Values: values,
  117. ByteValues: bytes,
  118. }
  119. }
  120. // EntryAttribute holds a single attribute
  121. type EntryAttribute struct {
  122. // Name is the name of the attribute
  123. Name string
  124. // Values contain the string values of the attribute
  125. Values []string
  126. // ByteValues contain the raw values of the attribute
  127. ByteValues [][]byte
  128. }
  129. // Print outputs a human-readable description
  130. func (e *EntryAttribute) Print() {
  131. fmt.Printf("%s: %s\n", e.Name, e.Values)
  132. }
  133. // PrettyPrint outputs a human-readable description with indenting
  134. func (e *EntryAttribute) PrettyPrint(indent int) {
  135. fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values)
  136. }
  137. // SearchResult holds the server's response to a search request
  138. type SearchResult struct {
  139. // Entries are the returned entries
  140. Entries []*Entry
  141. // Referrals are the returned referrals
  142. Referrals []string
  143. // Controls are the returned controls
  144. Controls []Control
  145. }
  146. // Print outputs a human-readable description
  147. func (s *SearchResult) Print() {
  148. for _, entry := range s.Entries {
  149. entry.Print()
  150. }
  151. }
  152. // PrettyPrint outputs a human-readable description with indenting
  153. func (s *SearchResult) PrettyPrint(indent int) {
  154. for _, entry := range s.Entries {
  155. entry.PrettyPrint(indent)
  156. }
  157. }
  158. // SearchRequest represents a search request to send to the server
  159. type SearchRequest struct {
  160. BaseDN string
  161. Scope int
  162. DerefAliases int
  163. SizeLimit int
  164. TimeLimit int
  165. TypesOnly bool
  166. Filter string
  167. Attributes []string
  168. Controls []Control
  169. }
  170. func (req *SearchRequest) appendTo(envelope *ber.Packet) error {
  171. pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request")
  172. pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.BaseDN, "Base DN"))
  173. pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.Scope), "Scope"))
  174. pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(req.DerefAliases), "Deref Aliases"))
  175. pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.SizeLimit), "Size Limit"))
  176. pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(req.TimeLimit), "Time Limit"))
  177. pkt.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, req.TypesOnly, "Types Only"))
  178. // compile and encode filter
  179. filterPacket, err := CompileFilter(req.Filter)
  180. if err != nil {
  181. return err
  182. }
  183. pkt.AppendChild(filterPacket)
  184. // encode attributes
  185. attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
  186. for _, attribute := range req.Attributes {
  187. attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute"))
  188. }
  189. pkt.AppendChild(attributesPacket)
  190. envelope.AppendChild(pkt)
  191. if len(req.Controls) > 0 {
  192. envelope.AppendChild(encodeControls(req.Controls))
  193. }
  194. return nil
  195. }
  196. // NewSearchRequest creates a new search request
  197. func NewSearchRequest(
  198. BaseDN string,
  199. Scope, DerefAliases, SizeLimit, TimeLimit int,
  200. TypesOnly bool,
  201. Filter string,
  202. Attributes []string,
  203. Controls []Control,
  204. ) *SearchRequest {
  205. return &SearchRequest{
  206. BaseDN: BaseDN,
  207. Scope: Scope,
  208. DerefAliases: DerefAliases,
  209. SizeLimit: SizeLimit,
  210. TimeLimit: TimeLimit,
  211. TypesOnly: TypesOnly,
  212. Filter: Filter,
  213. Attributes: Attributes,
  214. Controls: Controls,
  215. }
  216. }
  217. // SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the
  218. // search request. All paged LDAP query responses will be buffered and the final result will be returned atomically.
  219. // The following four cases are possible given the arguments:
  220. // - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size
  221. // - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries
  222. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request
  223. // - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries
  224. // A requested pagingSize of 0 is interpreted as no limit by LDAP servers.
  225. func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) {
  226. var pagingControl *ControlPaging
  227. control := FindControl(searchRequest.Controls, ControlTypePaging)
  228. if control == nil {
  229. pagingControl = NewControlPaging(pagingSize)
  230. searchRequest.Controls = append(searchRequest.Controls, pagingControl)
  231. } else {
  232. castControl, ok := control.(*ControlPaging)
  233. if !ok {
  234. return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
  235. }
  236. if castControl.PagingSize != pagingSize {
  237. return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
  238. }
  239. pagingControl = castControl
  240. }
  241. searchResult := new(SearchResult)
  242. for {
  243. result, err := l.Search(searchRequest)
  244. l.Debug.Printf("Looking for Paging Control...")
  245. if err != nil {
  246. return searchResult, err
  247. }
  248. if result == nil {
  249. return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received"))
  250. }
  251. for _, entry := range result.Entries {
  252. searchResult.Entries = append(searchResult.Entries, entry)
  253. }
  254. for _, referral := range result.Referrals {
  255. searchResult.Referrals = append(searchResult.Referrals, referral)
  256. }
  257. for _, control := range result.Controls {
  258. searchResult.Controls = append(searchResult.Controls, control)
  259. }
  260. l.Debug.Printf("Looking for Paging Control...")
  261. pagingResult := FindControl(result.Controls, ControlTypePaging)
  262. if pagingResult == nil {
  263. pagingControl = nil
  264. l.Debug.Printf("Could not find paging control. Breaking...")
  265. break
  266. }
  267. cookie := pagingResult.(*ControlPaging).Cookie
  268. if len(cookie) == 0 {
  269. pagingControl = nil
  270. l.Debug.Printf("Could not find cookie. Breaking...")
  271. break
  272. }
  273. pagingControl.SetCookie(cookie)
  274. }
  275. if pagingControl != nil {
  276. l.Debug.Printf("Abandoning Paging...")
  277. pagingControl.PagingSize = 0
  278. l.Search(searchRequest)
  279. }
  280. return searchResult, nil
  281. }
  282. // Search performs the given search request
  283. func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
  284. msgCtx, err := l.doRequest(searchRequest)
  285. if err != nil {
  286. return nil, err
  287. }
  288. defer l.finishMessage(msgCtx)
  289. result := &SearchResult{
  290. Entries: make([]*Entry, 0),
  291. Referrals: make([]string, 0),
  292. Controls: make([]Control, 0)}
  293. for {
  294. packet, err := l.readPacket(msgCtx)
  295. if err != nil {
  296. return nil, err
  297. }
  298. switch packet.Children[1].Tag {
  299. case 4:
  300. entry := new(Entry)
  301. entry.DN = packet.Children[1].Children[0].Value.(string)
  302. for _, child := range packet.Children[1].Children[1].Children {
  303. attr := new(EntryAttribute)
  304. attr.Name = child.Children[0].Value.(string)
  305. for _, value := range child.Children[1].Children {
  306. attr.Values = append(attr.Values, value.Value.(string))
  307. attr.ByteValues = append(attr.ByteValues, value.ByteValue)
  308. }
  309. entry.Attributes = append(entry.Attributes, attr)
  310. }
  311. result.Entries = append(result.Entries, entry)
  312. case 5:
  313. err := GetLDAPError(packet)
  314. if err != nil {
  315. return nil, err
  316. }
  317. if len(packet.Children) == 3 {
  318. for _, child := range packet.Children[2].Children {
  319. decodedChild, err := DecodeControl(child)
  320. if err != nil {
  321. return nil, fmt.Errorf("failed to decode child control: %s", err)
  322. }
  323. result.Controls = append(result.Controls, decodedChild)
  324. }
  325. }
  326. return result, nil
  327. case 19:
  328. result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string))
  329. }
  330. }
  331. }