lib/ldap/server/operation.rb in ruby-ldapserver-0.5.3 vs lib/ldap/server/operation.rb in ruby-ldapserver-0.7.0

- old
+ new

@@ -1,6 +1,7 @@ require 'timeout' +require 'openssl' require 'ldap/server/result' require 'ldap/server/filter' module LDAP class Server @@ -34,22 +35,23 @@ # protocolOp, # controls [0] OPTIONAL, ]) @schema = @connection.opt[:schema] @server = @connection.opt[:server] + @attribute_range_limit = @connection.opt[:attribute_range_limit] end def log msg, severity = Logger::INFO @connection.log msg, severity end def debug msg @connection.debug msg end - + # Send an exception report to the log - + def log_exception msg @connection.log_exception msg end ################################################## @@ -82,11 +84,11 @@ if opt[:referral] rs = opt[:referral].collect { |r| OpenSSL::ASN1::OctetString(r) } seq << OpenSSL::ASN1::Sequence(rs, 3, :IMPLICIT, :APPLICATION) end yield seq if block_given? # opportunity to add more elements - + send_LDAPMessage(OpenSSL::ASN1::Sequence(seq, tag, :IMPLICIT, :APPLICATION), opt) end def send_BindResponse(resultCode, opt={}) send_LDAPResult(1, resultCode, opt) do |resp| @@ -94,10 +96,13 @@ resp << OpenSSL::ASN1::OctetString(opt[:serverSaslCreds], 7, :IMPLICIT, :APPLICATION) end end end + + AttributeRange = Struct.new :start, :end + # Send a found entry. Avs are {attr1=>val1, attr2=>[val2,val3]} # If schema given, return operational attributes only if # explicitly requested def send_SearchResultEntry(dn, avs, opt={}) @@ -112,27 +117,47 @@ end sendall = @attributes == [] || @attributes.include?("*") avseq = [] - avs.each do |attr, vals| - if !@attributes.include?(attr) + avs.each_with_index do |(attr, vals), aidx| + query_attr_idx = @attributes.index(attr) + if !query_attr_idx next unless sendall if @schema a = @schema.find_attrtype(attr) next unless a and (a.usage.nil? or a.usage == :userApplications) end end + query_attr = query_attr_idx && @attribute_ranges[query_attr_idx] if @typesOnly - vals = [] + vals = [] else vals = [vals] unless vals.kind_of?(Array) # FIXME: optionally do a value_to_s conversion here? # FIXME: handle attribute;binary end + if (@attribute_range_limit && vals.size > @attribute_range_limit) || query_attr&.start + if query_attr&.start + range_start = query_attr.start.to_i + range_end = query_attr.end == "*" ? -1 : query_attr.end.to_i + else + range_start = 0 + range_end = @attribute_range_limit ? @attribute_range_limit - 1 : -1 + end + range_end = range_start + @attribute_range_limit - 1 if @attribute_range_limit && (vals.size - range_start > @attribute_range_limit) + range_end = -1 if vals.size <= range_end + rvals = vals[range_start .. range_end] + vals = [] + avseq << OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::OctetString("#{attr};range=#{range_start}-#{range_end == -1 ? "*" : range_end}"), + OpenSSL::ASN1::Set(rvals.collect { |v| OpenSSL::ASN1::OctetString(v.to_s) }) + ]) + end + avseq << OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::OctetString(attr), OpenSSL::ASN1::Set(vals.collect { |v| OpenSSL::ASN1::OctetString(v.to_s) }) ]) end @@ -198,12 +223,12 @@ case authentication.tag # tag_class == :CONTEXT_SPECIFIC (check why) when 0 simple_bind(version, dn, authentication.value) when 3 - mechanism = authentication.value[0].value - credentials = authentication.value[1].value + # mechanism = authentication.value[0].value + # credentials = authentication.value[1].value # sasl_bind(version, dn, mechanism, credentials) # FIXME: needs to exchange further BindRequests raise LDAP::ResultError::AuthMethodNotSupported else raise LDAP::ResultError::ProtocolError, "BindRequest bad AuthenticationChoice" @@ -244,10 +269,23 @@ deref = protocolOp.value[2].value client_sizelimit = protocolOp.value[3].value client_timelimit = protocolOp.value[4].value.to_i @typesOnly = protocolOp.value[5].value filter = Filter::parse(protocolOp.value[6], @schema) - @attributes = protocolOp.value[7].value.collect {|x| x.value} + attributes = protocolOp.value[7].value.collect {|x| x.value} + attributes = attributes.map do |attr| + if attr =~ /(.*);range=(\d+)-(\d+|\*)\z/ + [$1, $2, $3] + else + attr + end + end + @attributes = attributes.map do |name, | + name + end + @attribute_ranges = attributes.map do |_, range_start, range_end| + range_start && AttributeRange.new(range_start, range_end) + end @rescount = 0 @sizelimit = server_sizelimit @sizelimit = client_sizelimit if client_sizelimit > 0 and (@sizelimit.nil? or client_sizelimit < @sizelimit)