@@ -336,6 +336,8 @@ class LdapError < StandardError; end
336336
337337 module LDAPControls
338338 PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
339+ SORT_REQUEST = "1.2.840.113556.1.4.473"
340+ SORT_RESPONSE = "1.2.840.113556.1.4.474"
339341 DELETE_TREE = "1.2.840.113556.1.4.805"
340342 end
341343
@@ -1328,6 +1330,35 @@ def bind_gss_spnego(auth)
13281330 end
13291331 private :bind_gss_spnego
13301332
1333+
1334+ #--
1335+ # Allow the caller to specify a sort control
1336+ #
1337+ # The format of the sort control needs to be:
1338+ #
1339+ # :sort_control => ["cn"] # just a string
1340+ # or
1341+ # :sort_control => [["cn", "matchingRule", true]] #attribute, matchingRule, direction (true / false)
1342+ # or
1343+ # :sort_control => ["givenname","sn"] #multiple strings or arrays
1344+ #
1345+ def encode_sort_controls ( sort_definitions )
1346+ return sort_definitions unless sort_definitions
1347+
1348+ sort_control_values = sort_definitions . map do |control |
1349+ control = Array ( control ) # if there is only an attribute name as a string then infer the orderinrule and reverseorder
1350+ control [ 0 ] = String ( control [ 0 ] ) . to_ber ,
1351+ control [ 1 ] = String ( control [ 1 ] ) . to_ber ,
1352+ control [ 2 ] = ( control [ 2 ] == true ) . to_ber
1353+ control . to_ber_sequence
1354+ end
1355+ sort_control = [
1356+ Net ::LDAP ::LDAPControls ::SORT_REQUEST . to_ber ,
1357+ false . to_ber ,
1358+ sort_control_values . to_ber_sequence . to_s . to_ber
1359+ ] . to_ber_sequence
1360+ end
1361+
13311362 #--
13321363 # Alternate implementation, this yields each search entry to the caller as
13331364 # it are received.
@@ -1353,6 +1384,7 @@ def search(args = {})
13531384 scope = args [ :scope ] || Net ::LDAP ::SearchScope_WholeSubtree
13541385 raise Net ::LDAP ::LdapError , "invalid search scope" unless Net ::LDAP ::SearchScopes . include? ( scope )
13551386
1387+ sort_control = encode_sort_controls ( args . fetch ( :sort_controls ) { false } )
13561388 # An interesting value for the size limit would be close to A/D's
13571389 # built-in page limit of 1000 records, but openLDAP newer than version
13581390 # 2.2.0 chokes on anything bigger than 126. You get a silent error that
@@ -1408,6 +1440,8 @@ def search(args = {})
14081440 false . to_ber ,
14091441 rfc2696_cookie . map { |v | v . to_ber } . to_ber_sequence . to_s . to_ber
14101442 ] . to_ber_sequence if paged_searches_supported
1443+
1444+ controls << sort_control if sort_control
14111445 controls = controls . to_ber_contextspecific ( 0 )
14121446
14131447 pkt = [ next_msgid . to_ber , request , controls ] . to_ber_sequence
0 commit comments