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.
- data/History.txt +4 -0
- data/LICENSE +20 -0
- data/Manifest.txt +13 -0
- data/README.txt +107 -0
- data/Rakefile +30 -0
- data/TODO +0 -0
- data/lib/ldap_adapter.rb +348 -0
- data/lib/ldap_adapter/version.rb +5 -0
- data/spec/integration/ldap_adapter_spec.rb +6 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/install.rb +13 -0
- data/tasks/spec.rb +25 -0
- metadata +89 -0
data/History.txt
ADDED
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.
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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
|
data/lib/ldap_adapter.rb
ADDED
@@ -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
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
data/tasks/install.rb
ADDED
@@ -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
|
data/tasks/spec.rb
ADDED
@@ -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
|
+
|