irjudson-dm-ldap-adapter 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+