irjudson-dm-ldap-adapter 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ === 0.0.1 / 2009-05-22
2
+
3
+ * Release!
4
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Montana State University
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ TODO
7
+ lib/ldap_adapter.rb
8
+ lib/ldap_adapter/version.rb
9
+ spec/integration/ldap_adapter_spec.rb
10
+ spec/spec.opts
11
+ spec/spec_helper.rb
12
+ tasks/install.rb
13
+ tasks/spec.rb
@@ -0,0 +1,107 @@
1
+ = dm-ldap-adapter
2
+
3
+ A DataMapper adapter for Lightweight Directory Access Protocol (LDAP) servers.
4
+
5
+ == Usage
6
+
7
+ DM LDAP Adapter enables the creation of application objects that map
8
+ against an existing LDAP server. For example, a "user" can map against
9
+ the posixAccount schema in an LDAP server providing uidNumber,
10
+ gidNumber, uid, homeDirectory and userPassword. These are intended to
11
+ map to unix accounts so that authentication on unix systems can be
12
+ centrally managed by the LDAP server.
13
+
14
+ Currently, mapping LDAP schemas to application objects must be done
15
+ manually by the developer, but the intent is to create a set of
16
+ objects corresponding to the set of most commonly used LDAP schemas so
17
+ application developers can leverage them with less effort.
18
+
19
+ DataMapper.setup(:default, {
20
+ :adapter => 'ldap',
21
+ :host => 'localhost',
22
+ :port => '389',
23
+ :base => "ou=people,dc=example,dc=com",
24
+ :username => "cn=admin,dc=example,dc=com",
25
+ :password => "exPa5$w0rd"
26
+ })
27
+
28
+
29
+ class User
30
+ include DataMapper::Resource
31
+
32
+ @@base = "ou=people,dc=example,dc=com"
33
+
34
+ @@objectclass = [ "top", "person", "organizationalPerson", "inetOrgPerson",
35
+ "extensibleObject", "shadowAccount", "posixAccount" ]
36
+
37
+ property :username, String, :field => "uid", :key => true
38
+ property :uuid, String, :field => "uniqueidentifier"
39
+ property :name, String, :field => "cn"
40
+ property :first_name, String, :field => "givenname"
41
+ property :last_name, String, :field => "sn"
42
+ property :mail, String, :field => "mail"
43
+ property :groupid, Integer, :field => "gidnumber"
44
+ property :userid, Integer, :field => "uidnumber"
45
+ property :homedirectory, String, :field => "homedirectory"
46
+
47
+ def objectclass
48
+ @@objectclass
49
+ end
50
+
51
+ def make_dn
52
+ "uid=#{netid},#{@@base}"
53
+ end
54
+ end
55
+
56
+ This is exactly like normal datamapper models, with a couple of extras
57
+ to make LDAP function.
58
+
59
+ @@base is a class variable that defines where in the LDAP hierarchy
60
+ this class of objects reside, it represents a path from the root. This
61
+ is important because each piece of ldap data is uniquely identified by
62
+ a distinguisedName which is the key attribute + @@base. For example,
63
+ the distinguishedName "uid=testuser,ou=people,dc=example,dc=com"
64
+ uniquely identifies the test user in the LDAP server.
65
+
66
+ @@objectclass is the list of LDAP schemas that are required to define
67
+ this particular LDAP object. Each schema contributes some set of
68
+ attributes that, when taken together, define all the objects at that
69
+ location in the LDAP tree. This list is required when new resources
70
+ are created in LDAP, but ideally should be hidden from the application
71
+ developer.
72
+
73
+ == Code
74
+
75
+ # Create
76
+ user = User.new(:username => "dmtest", :uuid => UUID.random_create().to_s,
77
+ :name => "DataMapper Test", :homedirectory => "/home/dmtest",
78
+ :first_name => "DataMapperTest", :last_name => "User",
79
+ :userid => 3, :groupid => 500)
80
+
81
+ user.save
82
+
83
+ # Retrieve
84
+ user = User.first(:username => 'dmtest')
85
+ puts user
86
+
87
+ # Modify
88
+ user.update_attributes(:name => 'DM Test')
89
+ user.save
90
+ puts user
91
+
92
+ # Delete
93
+ result = user.destroy
94
+ puts "Result: #{result}"
95
+
96
+ == TODO:
97
+
98
+ - Figure out a good testing strategy, get standard adapter tests in place
99
+
100
+ - Finish query implementation (limit, order, etc)
101
+
102
+ - Consider making pre-mapped resources corresponding to the most
103
+ commonly used LDAP object types so applications can use them without
104
+ duplication of effort for each application.
105
+
106
+ - Documentation clean up
107
+
@@ -0,0 +1,30 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+ require 'hoe'
4
+
5
+ ROOT = Pathname(__FILE__).dirname.expand_path
6
+ JRUBY = RUBY_PLATFORM =~ /java/
7
+ WINDOWS = Gem.win_platform?
8
+ SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
9
+
10
+ require ROOT + 'lib/ldap_adapter/version'
11
+
12
+ # define some constants to help with task files
13
+ GEM_NAME = 'dm-ldap-adapter'
14
+ GEM_VERSION = DataMapper::LdapAdapter::VERSION
15
+
16
+ Hoe.spec(GEM_NAME) do |p|
17
+ p.developer('Ivan R. Judson', 'ivan.judson [a] montana [d] edu')
18
+
19
+ p.description = 'A DataMapper Adapter for LDAP.'
20
+ p.summary = 'A DataMapper Adapter for LDAP (The Lightweight Directory Access Protocol)'
21
+ p.url = 'http://github.com/irjudson/dm-ldap-adapter'
22
+
23
+ p.clean_globs |= %w[ log pkg coverage ]
24
+ p.spec_extras = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO History.txt ] }
25
+
26
+ p.extra_deps << ['dm-core', "0.9.11"]
27
+
28
+ end
29
+
30
+ Pathname.glob(ROOT.join('tasks/**/*.rb').to_s).each { |f| require f }
data/TODO ADDED
File without changes
@@ -0,0 +1,348 @@
1
+ require 'dm-core'
2
+ require 'net/ldap'
3
+
4
+ module DataMapper
5
+ module Adapters
6
+ # The documentation for this adapter was taken from
7
+ #
8
+ # lib/dm-core/adapters/in_memory_adapter.rb
9
+ #
10
+ # Which is intended as a general source of documentation for the
11
+ # implementation to be followed by all DataMapper adapters. The
12
+ # implementor is well advised to read over the adapter before
13
+ # implementing their own.
14
+ #
15
+ class LdapAdapter < AbstractAdapter
16
+ ##
17
+ # Used by DataMapper to put records into a data-store: "INSERT"
18
+ # in SQL-speak. It takes an array of the resources (model
19
+ # instances) to be saved. Resources each have a key that can be
20
+ # used to quickly look them up later without searching, if the
21
+ # adapter supports it.
22
+ #
23
+ # @param [Array<DataMapper::Resource>] resources
24
+ # The set of resources (model instances)
25
+ #
26
+ # @return [Integer]
27
+ # The number of records that were actually saved into the
28
+ # data-store
29
+ #
30
+ # @api semipublic
31
+ def create(resources)
32
+
33
+ created = 0
34
+ resources.each do |resource|
35
+ # Convert resources into LDAP (which just takes a hash!)
36
+ ldap_obj = convert_resource_to_hash(resource)
37
+ dn = resource.make_dn
38
+ ldap_obj[:objectclass] = resource.objectclass
39
+
40
+ if ldap_obj.nil? || dn.nil?
41
+ puts "Problem converting resource to hash for LdapAdapter"
42
+ return -1
43
+ end
44
+
45
+ # Call LDAP create
46
+ begin
47
+ @ldap.add(:dn => dn, :attributes => ldap_obj)
48
+ rescue Net::LDAP::LdapError => e
49
+ puts "There was an error adding the ldap object: ", e
50
+ puts " => #{@ldap.get_operation_result.message}"
51
+ return -1
52
+ end
53
+
54
+ # Accumulate successful create calls to return
55
+ if @ldap.get_operation_result.code == 0
56
+ created = created + 1
57
+ else
58
+ puts "LDAP Add Error: #{@ldap.get_operation_result.message}"
59
+ end
60
+ end
61
+
62
+ # Return number created
63
+ return created
64
+ end
65
+
66
+ ##
67
+ # Used by DataMapper to update the attributes on existing
68
+ # records in a data-store: "UPDATE" in SQL-speak. It takes a
69
+ # hash of the attributes to update with, as well as a query
70
+ # object that specifies which resources should be updated.
71
+ #
72
+ # @param [Hash] attributes
73
+ # A set of key-value pairs of the attributes to update the
74
+ # resources with.
75
+ # @param [DataMapper::Query] query
76
+ # The query that should be used to find the resource(s) to update.
77
+ #
78
+ # @return [Integer]
79
+ # the number of records that were successfully updated
80
+ #
81
+ # @api semipublic
82
+ def update(attributes, query)
83
+ updated = 0
84
+
85
+ # Convert query conditions to ldap filter
86
+ filter = convert_conditions(query.conditions)
87
+
88
+ # Convert attributes/query into LDAP
89
+ entries = @ldap.search(:filter => filter)
90
+
91
+ # Process updates (being careful to distinguish between add and update
92
+ entries.each do |entry|
93
+ existing = entry.attribute_names.map { |a| a.to_s }
94
+ attributes.each do |attribute, value|
95
+ property = attribute.field.to_s
96
+
97
+ ops = []
98
+ if existing.include?(property)
99
+ ops << [:replace, attribute.field.to_sym, value]
100
+ else
101
+ ops << [:add, attribute.field.to_sym, value]
102
+ end
103
+
104
+ @ldap.modify(:dn => entry.dn, :operations => ops)
105
+
106
+ if @ldap.get_operation_result.code == 0
107
+ updated = updated + 1
108
+ else
109
+ puts "LDAP Modify Error: #{@ldap.get_operation_result.message}"
110
+ end
111
+ end
112
+ end
113
+
114
+ # Return Number updated
115
+ return updated
116
+ end
117
+
118
+ ##
119
+ # Look up a single record from the data-store. "SELECT ... LIMIT
120
+ # 1" in SQL. Used by Model#get to find a record by its
121
+ # identifier(s), and Model#first to find a single record by some
122
+ # search query.
123
+ #
124
+ # @param [DataMapper::Query] query
125
+ # The query to be used to locate the resource.
126
+ #
127
+ # @return [DataMapper::Resource]
128
+ # A Resource object representing the record that was found, or
129
+ # nil for no matching records.
130
+ #
131
+ # @api semipublic
132
+ def read_one(query)
133
+ # Call read_many(query)
134
+ all_results = self.read_many(query)
135
+
136
+ # Return first result
137
+ return all_results.first
138
+ end
139
+
140
+ ##
141
+ # Looks up a collection of records from the data-store: "SELECT" in SQL.
142
+ # Used by Model#all to search for a set of records; that set is in a
143
+ # DataMapper::Collection object.
144
+ #
145
+ # @param [DataMapper::Query] query
146
+ # The query to be used to seach for the resources
147
+ #
148
+ # @return [DataMapper::Collection]
149
+ # A collection of all the resources found by the query.
150
+ #
151
+ # @api semipublic
152
+ def read_many(query)
153
+ resources = Array.new
154
+
155
+ # Convert query conditions to ldap filter
156
+ filter = convert_conditions(query.conditions)
157
+
158
+ # Convert attributes/query into LDAP
159
+ @ldap.search(:filter => filter, :return_result => false) do |entry|
160
+ values = query.fields.collect do |field|
161
+ entry[field.field.to_sym].first
162
+ end
163
+ resources << query.model.load(values, query)
164
+ end
165
+
166
+ # Return Results
167
+ resources
168
+ end
169
+
170
+ alias :read :read_many
171
+
172
+ ##
173
+ # Destroys all the records matching the given query. "DELETE" in SQL.
174
+ #
175
+ # @param [DataMapper::Query] query
176
+ # The query used to locate the resources to be deleted.
177
+ #
178
+ # @return [Integer]
179
+ # The number of records that were deleted.
180
+ #
181
+ # @api semipublic
182
+ def delete(query)
183
+
184
+ deleted = 0
185
+
186
+ # Convert query conditions to ldap filter
187
+ filter = convert_conditions(query.conditions)
188
+
189
+ # Convert attributes/query into LDAP
190
+ entries = @ldap.search(:filter => filter)
191
+
192
+ # Call LDAP Delete
193
+ entries.each do |entry|
194
+ result = @ldap.delete(:dn => entry.dn)
195
+
196
+ if @ldap.get_operation_result.code == 0
197
+ deleted = deleted + 1
198
+ else
199
+ puts "LDAP Delete Error: #{@ldap.get_operation_result.message}"
200
+ end
201
+ end
202
+
203
+ # Return number successfully deleted
204
+ return deleted
205
+ end
206
+
207
+ private
208
+
209
+ ##
210
+ # Make a new instance of the adapter. The @model_records ivar is
211
+ # the 'data-store' for this adapter. It is not shared amongst
212
+ # multiple incarnations of this adapter, eg
213
+ # DataMapper.setup(:default, :adapter => :in_memory);
214
+ # DataMapper.setup(:alternate, :adapter => :in_memory) do not
215
+ # share the data-store between them.
216
+ #
217
+ # @param [String, Symbol] name
218
+ # The name of the DataMapper::Repository using this adapter.
219
+ # @param [String, Hash] uri_or_options
220
+ # The connection uri string, or a hash of options to set up
221
+ # the adapter
222
+ #
223
+ # @api semipublic
224
+ def initialize(name, uri_or_options)
225
+ super
226
+
227
+ if uri_or_options.class
228
+ @identity_maps = {}
229
+ end
230
+
231
+ @options = Hash.new
232
+
233
+ # Let's play with Options
234
+ @options[:attributes] = nil
235
+ @options[:scope] = Net::LDAP::SearchScope_WholeSubtree
236
+ @options[:filter] = nil
237
+ @options[:auth] = { :method => :simple }
238
+
239
+ uri_or_options.each do |k,v|
240
+ @options[k] = v
241
+ end
242
+
243
+ # if uri_or_options.is_a?(String)
244
+ # begin
245
+ # opt_array = URI.split(uri_or_options)
246
+ # @options[:scheme] = opt_array[0]
247
+ # @options[:auth][:username],@options[:auth][:password] = opt_array[1].split(':')
248
+ # @options[:host] = opt_array[2]
249
+ # @options[:port] = opt_array[3]
250
+
251
+ # # Registry from URI not used
252
+ # # @options[:registry] = opt_array[4]
253
+
254
+ # @options[:base] = opt_array[5]
255
+
256
+ # # Opaque from URI not used
257
+ # # @options[:opaque] = opt_array[6]
258
+
259
+ # # This is where the rest of the string is kept
260
+ # # According to the LDAP url spec it should look like
261
+ # # ?attributes?scope?filter, e.g.
262
+ # # ?uid?sub?(uid=username), however
263
+ # # URI strip appears to lose the first ?
264
+ # # So we parse it all out
265
+ # @options[:attributes],@options[:scope],@options[:filter] = opt_array[7].split('?')
266
+ # @options[:fragment] = opt_array[8]
267
+ # rescue InvalidURIError => e
268
+ # puts "Error parsing options for ldap adapter"
269
+ # end
270
+ # else
271
+ # @options.merge!(uri_or_options.dup)
272
+
273
+ # @options[:auth][:username] = @options[:username]
274
+ # @options[:auth][:password] = @options[:password]
275
+
276
+ # @options.delete(:adapter)
277
+ # @options.delete(:username)
278
+ # @options.delete(:password)
279
+ # @options.delete(:attributes)
280
+ # @options.delete(:filter)
281
+ # end
282
+
283
+ # Deal with SSL stuff
284
+ if @options[:scheme] == "ldaps" || @options[:port] == "636"
285
+ @options[:encryption] = { :method => :simple_tls }
286
+ end
287
+
288
+ puts "Options: #{@options.inspect}"
289
+
290
+ # Create the new LDAP client stub
291
+ @ldap = Net::LDAP.new(@options)
292
+
293
+ if ! @ldap.bind
294
+ puts "Tried to bind with options: #{@options.inspect}"
295
+ puts "Result: #{@ldap.get_operation_result.code}"
296
+ puts "Message: #{@ldap.get_operation_result.message}"
297
+ end
298
+ end
299
+
300
+ def convert_resource_to_hash(resource)
301
+ result = Hash.new
302
+ resource.send(:properties).each do |p|
303
+ result[p.field.to_sym] = p.get!(resource) unless p.get!(resource).nil?
304
+ end
305
+ result
306
+ end
307
+
308
+ def convert_conditions(conditions)
309
+ filters = Array.new
310
+ conditions.each do |condition|
311
+ case condition[0]
312
+ when :eql
313
+ filters << Net::LDAP::Filter.eq(condition[1].field(), condition[2].to_s)
314
+ when :lt
315
+ fle = Net::LDAP::Filter.le(condition[1].field(), condition[2].to_s)
316
+ fe = Net::LDAP::Filter.eq(condition[1].field(), condition[2].to_s)
317
+ filters << fle & ! fe
318
+ when :gt
319
+ fge = Net::LDAP::Filter.ge(condition[1].field(), condition[2].to_s)
320
+ fe = Net::LDAP::Filter.eq(condition[1].field(), condition[2].to_s)
321
+ filters << fge & ! fe
322
+ when :lte
323
+ filters << Net::LDAP::Filter.le(condition[1].field(), condition[2].to_s)
324
+ when :gte
325
+ filters << Net::LDAP::Filter.ge(condition[1].field(), condition[2].to_s)
326
+ when :not : puts "!"
327
+ filters << Net::LDAP::Filter.ne(condition[1].field(), condition[2].to_s)
328
+ when :like
329
+ filters << Net::LDAP::Filter.eq(condition[1].field(), condition[2].to_s)
330
+ else
331
+ puts "Unknown condition: #{condition[0]}"
332
+ end
333
+ end
334
+
335
+ # Put them all together with an AND
336
+ ldap_filter = nil
337
+ filters.each do |filter|
338
+ if ldap_filter.nil?
339
+ ldap_filter = filter
340
+ else
341
+ ldap_filter = ldap_filter & filter
342
+ end
343
+ end
344
+ ldap_filter
345
+ end
346
+ end
347
+ end
348
+ end
@@ -0,0 +1,5 @@
1
+ module DataMapper
2
+ module LdapAdapter
3
+ VERSION = '0.0.9'
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe 'DataMapper::Adapters::LdapAdapter' do
5
+
6
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,13 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+
4
+ gem 'addressable', '~>2.0'
5
+ gem 'rspec', '>1.1.2'
6
+
7
+ require 'addressable/uri'
8
+ require 'spec'
9
+
10
+ require 'dm-core'
11
+
12
+ require Pathname(__FILE__).dirname.expand_path.parent + 'lib/ldap_adapter'
13
+
@@ -0,0 +1,13 @@
1
+ def sudo_gem(cmd)
2
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
3
+ end
4
+
5
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
6
+ task :install => [ :package ] do
7
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
8
+ end
9
+
10
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
11
+ task :uninstall => [ :clobber ] do
12
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
13
+ end
@@ -0,0 +1,25 @@
1
+ begin
2
+ gem 'rspec', '~>1.1.11'
3
+ require 'spec'
4
+ require 'spec/rake/spectask'
5
+
6
+ task :default => [ :spec ]
7
+
8
+ desc 'Run specifications'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
11
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
12
+
13
+ begin
14
+ gem 'rcov', '~>0.8'
15
+ t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
16
+ t.rcov_opts << '--exclude' << 'spec'
17
+ t.rcov_opts << '--text-summary'
18
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
19
+ rescue LoadError
20
+ # rcov not installed
21
+ end
22
+ end
23
+ rescue LoadError
24
+ # rspec not installed
25
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: irjudson-dm-ldap-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ platform: ruby
6
+ authors:
7
+ - Ivan R. Judson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-25 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core~
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.10
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.11.0
34
+ version:
35
+ description: A DataMapper Adapter for LDAP, as simply as possible.
36
+ email:
37
+ - ivan.judson [a] montana [d] edu
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - README.txt
44
+ - LICENSE
45
+ - TODO
46
+ - History.txt
47
+ files:
48
+ - History.txt
49
+ - LICENSE
50
+ - Manifest.txt
51
+ - README.txt
52
+ - Rakefile
53
+ - TODO
54
+ - lib/ldap_adapter.rb
55
+ - lib/ldap_adapter/version.rb
56
+ - spec/integration/ldap_adapter_spec.rb
57
+ - spec/spec.opts
58
+ - spec/spec_helper.rb
59
+ - tasks/install.rb
60
+ - tasks/spec.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/irjudson/dm-ldap-adapter
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --main
66
+ - README.txt
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project: dm-ldap-adapter
84
+ rubygems_version: 1.2.0
85
+ signing_key:
86
+ specification_version: 2
87
+ summary: A DataMapper Adapter for LDAP
88
+ test_files: []
89
+