summaryrefslogtreecommitdiffstats
path: root/vendor/gems/net-ldap-0.2.2/lib/net/ldap/dataset.rb
blob: 363d25971b419c2b22d9624d64cbecc6c817bd9b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# -*- ruby encoding: utf-8 -*-
##
# An LDAP Dataset. Used primarily as an intermediate format for converting
# to and from LDIF strings and Net::LDAP::Entry objects.
class Net::LDAP::Dataset < Hash
  ##
  # Dataset object comments.
  attr_reader :comments

  def initialize(*args, &block) # :nodoc:
    super
    @comments = []
  end

  ##
  # Outputs an LDAP Dataset as an array of strings representing LDIF
  # entries.
  def to_ldif
    ary = []
    ary += @comments unless @comments.empty?
    keys.sort.each do |dn|
      ary << "dn: #{dn}"

      attributes = self[dn].keys.map { |attr| attr.to_s }.sort
      attributes.each do |attr|
        self[dn][attr.to_sym].each do |value|
          if attr == "userpassword" or value_is_binary?(value)
            value = [value].pack("m").chomp.gsub(/\n/m, "\n ")
            ary << "#{attr}:: #{value}"
          else
            ary << "#{attr}: #{value}"
          end
        end
      end

      ary << ""
    end
    block_given? and ary.each { |line| yield line}

    ary
  end

  ##
  # Outputs an LDAP Dataset as an LDIF string.
  def to_ldif_string
    to_ldif.join("\n")
  end

  ##
  # Convert the parsed LDIF objects to Net::LDAP::Entry objects.
  def to_entries
    ary = []
    keys.each do |dn|
      entry = Net::LDAP::Entry.new(dn)
      self[dn].each do |attr, value|
        entry[attr] = value
      end
      ary << entry
    end
    ary
  end

  ##
  # This is an internal convenience method to determine if a value requires
  # base64-encoding before conversion to LDIF output. The standard approach
  # in most LDAP tools is to check whether the value is a password, or if
  # the first or last bytes are non-printable. Microsoft Active Directory,
  # on the other hand, sometimes sends values that are binary in the middle.
  #
  # In the worst cases, this could be a nasty performance killer, which is
  # why we handle the simplest cases first. Ideally, we would also test the
  # first/last byte, but it's a bit harder to do this in a way that's
  # compatible with both 1.8.6 and 1.8.7.
  def value_is_binary?(value) # :nodoc:
    value = value.to_s
    return true if value[0] == ?: or value[0] == ?<
    value.each_byte { |byte| return true if (byte < 32) || (byte > 126) }
    false
  end
  private :value_is_binary?

  class << self
    class ChompedIO # :nodoc:
      def initialize(io)
        @io = io
      end
      def gets
        s = @io.gets
        s.chomp if s
      end
    end

    ##
    # Creates a Dataset object from an Entry object. Used mostly to assist
    # with the conversion of
    def from_entry(entry)
      dataset = Net::LDAP::Dataset.new
      hash = { }
      entry.each_attribute do |attribute, value|
        next if attribute == :dn
        hash[attribute] = value
      end
      dataset[entry.dn] = hash
      dataset
    end

    ##
    # Reads an object that returns data line-wise (using #gets) and parses
    # LDIF data into a Dataset object.
    def read_ldif(io)
      ds = Net::LDAP::Dataset.new
      io = ChompedIO.new(io)

      line = io.gets
      dn = nil

      while line
        new_line = io.gets

        if new_line =~ /^[\s]+/
          line << " " << $'
        else
          nextline = new_line

          if line =~ /^#/
            ds.comments << line
            yield :comment, line if block_given?
          elsif line =~ /^dn:[\s]*/i
            dn = $'
            ds[dn] = Hash.new { |k,v| k[v] = [] }
            yield :dn, dn if block_given?
          elsif line.empty?
            dn = nil
            yield :end, nil if block_given?
          elsif line =~ /^([^:]+):([\:]?)[\s]*/
            # $1 is the attribute name
            # $2 is a colon iff the attr-value is base-64 encoded
            # $' is the attr-value
            # Avoid the Base64 class because not all Ruby versions have it.
            attrvalue = ($2 == ":") ? $'.unpack('m').shift : $'
            ds[dn][$1.downcase.to_sym] << attrvalue
            yield :attr, [$1.downcase.to_sym, attrvalue] if block_given?
          end

          line = nextline
        end
      end

      ds
    end
  end
end

require 'net/ldap/entry' unless defined? Net::LDAP::Entry