dm-ldap-adapter 0.4.2 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/README-bundler.md +34 -0
- data/{README-example.markdown → README-example.md} +0 -0
- data/{README.txt → README.md} +34 -22
- data/example/posix.rb +1 -5
- data/lib/adapters/ldap_adapter.rb +8 -5
- data/lib/dm-ldap-adapter.rb +1 -0
- data/lib/ldap/array.rb +34 -17
- data/lib/ldap/digest.rb +8 -1
- data/lib/ldap/ruby_ldap_facade.rb +23 -11
- data/lib/ldap/transactions.rb +2 -0
- data/lib/ldap/unboundid_ldap_facade.rb +188 -0
- data/lib/ldap_resource.rb +2 -1
- data/spec/assiociations_ldap_adapter_spec.rb +37 -9
- data/spec/contact.rb +58 -0
- data/spec/ldap_array_spec.rb +119 -0
- data/spec/multi_value_attributes_spec.rb +0 -1
- data/spec/spec_helper.rb +14 -6
- metadata +109 -46
- data/.project +0 -11
- data/.yardoc +0 -0
- data/Manifest.txt +0 -29
- data/Rakefile +0 -38
- data/spec/spec.opts +0 -2
- data/test.ldif +0 -46
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
version 0.4.3
|
2
|
+
=============
|
3
|
+
|
4
|
+
* test several environments: ruby-1.8.7/1.9.2, jruby-1.5.6/1.6.2 (1.8 and 1.9 where possible), DM-1.0.x/1.1.x, net-ldap and ruby-ldap gem as backend. run the specs against all possible combinations.
|
5
|
+
|
6
|
+
* improvements with LdapArray properties
|
7
|
+
|
1
8
|
version 0.4.2
|
2
9
|
=============
|
3
10
|
|
data/README-bundler.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# no Gemfile.lock on git #
|
2
|
+
|
3
|
+
there are two references for different DM versions
|
4
|
+
|
5
|
+
* ~> 1.1.0
|
6
|
+
|
7
|
+
* ~> 1.0.0
|
8
|
+
|
9
|
+
with a simple symbolic link you can switch between these two profiles.
|
10
|
+
|
11
|
+
`$ ln -s Gemfile.lock.1.1.0 Gemfile.lock`
|
12
|
+
|
13
|
+
for that reason Gemfile.lock in not on github, so the script run-all.sh
|
14
|
+
|
15
|
+
# run specs #
|
16
|
+
|
17
|
+
`$ bundle exec spec spec`
|
18
|
+
|
19
|
+
or for some jruby versions (which needs jruby and ruby-maven gem)
|
20
|
+
|
21
|
+
`$ rmvn test`
|
22
|
+
`$ rmvn test --Djruby.versions=1.5.6,1.6.2 -Djruby.18and19
|
23
|
+
|
24
|
+
# build gem
|
25
|
+
|
26
|
+
for the ruby platform
|
27
|
+
|
28
|
+
`$ gem build dm-ldap-adapter.gemspec`
|
29
|
+
|
30
|
+
or for java platform (needs jruby and ruby-maven gem)
|
31
|
+
|
32
|
+
`$ rmvn package`
|
33
|
+
|
34
|
+
gem will be inside target/dm-ldap-adapter directory.
|
File without changes
|
data/{README.txt → README.md}
RENAMED
@@ -1,20 +1,32 @@
|
|
1
|
-
|
1
|
+
# dm-ldap-adapter
|
2
2
|
|
3
|
-
*Homepage*:
|
3
|
+
*Homepage*: [http://github.com/mkristian/dm-ldap-adapter](http://github.com/mkristian/dm-ldap-adapter)
|
4
4
|
|
5
|
-
*Git*:
|
5
|
+
*Git*: [git://github.com/mkristian/dm-ldap-adapter.git](git://github.com/mkristian/dm-ldap-adapter.git)
|
6
6
|
|
7
7
|
*Author*: Kristian Meier
|
8
8
|
|
9
9
|
*Copyright*: 2008-2009
|
10
10
|
|
11
|
-
|
11
|
+
## Note on Patches/Pull Requests
|
12
12
|
|
13
|
-
|
13
|
+
* Fork the project.
|
14
|
+
|
15
|
+
* Make your feature addition or bug fix.
|
16
|
+
|
17
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
18
|
+
|
19
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
20
|
+
|
21
|
+
* Send me a pull request.
|
22
|
+
|
23
|
+
## DESCRIPTION:
|
24
|
+
|
25
|
+
### usecase
|
14
26
|
|
15
27
|
the usecase for that implementation was using an ldap server for user authentication and authorization. the ldap server is configured to have posixAccounts and posixGroups. on the datamapper side these accounts/groups are modeled with many-to-many relationship. further more the model classes should be in such a way that they can be used with another repository as well, i.e. they carry some ldap related configuration but this is only relevant for the ldap-adapter.
|
16
28
|
|
17
|
-
|
29
|
+
### low level ldap library
|
18
30
|
|
19
31
|
the ldap library which does the actual ldap protocol stuff is [http://rubyforge.org/projects/net-ldap] which is the default. the other ldap library is [http://rubyforge.org/projects/ruby-ldap]. just add a facade parameter when setting up DataMapper
|
20
32
|
|
@@ -30,7 +42,7 @@ or
|
|
30
42
|
:facade => :net_ldap,
|
31
43
|
.... })
|
32
44
|
|
33
|
-
|
45
|
+
### setup DataMapper
|
34
46
|
|
35
47
|
DataMapper.setup(:ldap, {
|
36
48
|
:adapter => 'ldap',
|
@@ -42,19 +54,19 @@ or
|
|
42
54
|
:password => "behappy"
|
43
55
|
})
|
44
56
|
|
45
|
-
|
57
|
+
### examples
|
46
58
|
|
47
59
|
see 'example/posix.rb' for user/group setup works with default installation of openldap on ubuntu (just change your password as needed in the code)
|
48
60
|
|
49
|
-
|
61
|
+
## FEATURES/PROBLEMS:
|
50
62
|
|
51
63
|
* the net-ldap has some issues with not closing the connections when an exception/error got raised, with limit the search result to 126 entries which gets fixed by making consecutives searches and collect the result.
|
52
64
|
|
53
65
|
* error from the ldap server are only logged and do not raise any exceptions (to be changed in next release) with one exception: when creating a new ldap entry a duplicated entry will raise DataMapper::PersistenceError
|
54
66
|
|
55
|
-
|
67
|
+
## SYNOPSIS:
|
56
68
|
|
57
|
-
|
69
|
+
### distinguished name (DN) of a model
|
58
70
|
|
59
71
|
there are three parts which makes the DN of a model, the base from the ldap conncetion, the `treebase` of the model and `dn_prefix` of an instance.
|
60
72
|
|
@@ -69,7 +81,7 @@ with a base `dc=example,dc=com` we get a DN like the user 'admin'
|
|
69
81
|
|
70
82
|
uid=admin,ou=people,dc=example,dc=com
|
71
83
|
|
72
|
-
|
84
|
+
### ldap entities are bigger than the model
|
73
85
|
|
74
86
|
for example the ldap posixGroup has more attributes than the model class, it needs the `objectclass` attribute set to `posixGroup`.
|
75
87
|
|
@@ -84,11 +96,11 @@ for example the ldap posixGroup has more attributes than the model class, it nee
|
|
84
96
|
|
85
97
|
so with the help of the `ldap_properties` you can define a block which returns an hash with extra attributes. with such block you can make some calculations if needed, i.e. :homedirectory => "/home/#{login}" for the posixAccount.
|
86
98
|
|
87
|
-
|
99
|
+
### authentication
|
88
100
|
|
89
101
|
this uses the underlying bind of a ldap connection. so on any model where you have the `dn_prefix` and the `treebase` configured, you can call the method `authenticate(password)`. this will forward the request to the ldap server.
|
90
102
|
|
91
|
-
|
103
|
+
### queries
|
92
104
|
|
93
105
|
conditions in ldap depend on the attributes definition in the ldap schema. here is the list of what is working with that ldap adapter side and the usual AND between the conditions:
|
94
106
|
|
@@ -110,13 +122,13 @@ and
|
|
110
122
|
|
111
123
|
gives the same result when *all* names are `NULL` !!!
|
112
124
|
|
113
|
-
|
125
|
+
### OR conditions
|
114
126
|
|
115
127
|
or-conditions can be done with :conditions option but only of the form "<property_name> <comparator> <value> [or <property_name> <comparator> <value>]*" where the comparator is one of "=", "like". it can be also combined with extra ANDs like this example
|
116
128
|
|
117
129
|
Contact.all(:name.like => "A%", :conditions => ["phone like '+49%' or mobile like '+49%'"])
|
118
130
|
|
119
|
-
|
131
|
+
### multiple repositories
|
120
132
|
|
121
133
|
most probably you have to work with ldap as one repository and a database as a second repository. for me it worked best to define the `default_repository` for each model in the model itself:
|
122
134
|
|
@@ -155,13 +167,13 @@ and to let the ldap resources use the ldap respository it is best to bind it to
|
|
155
167
|
end
|
156
168
|
end
|
157
169
|
|
158
|
-
|
170
|
+
### transactions
|
159
171
|
|
160
172
|
the adapter offers a noop transaction, i.e. you can wrap everything into a transaction but the ldap part has no functionality.
|
161
173
|
|
162
174
|
*note*: the ldap protocol does not know transactions
|
163
175
|
|
164
|
-
|
176
|
+
### many-to-many associations
|
165
177
|
|
166
178
|
staying with posix example there the groups has a memberuid attribute BUT unlike with relational databases it can have multiple values. to achieve a relationship with these values the underlying adapter needs to know that this specific attribute needs to be handled differently. for this `multivalue_field` comes into play. the ldap adapter clones the model and places the each memberuid in its own clone.
|
167
179
|
|
@@ -179,7 +191,7 @@ staying with posix example there the groups has a memberuid attribute BUT unlike
|
|
179
191
|
|
180
192
|
end
|
181
193
|
|
182
|
-
|
194
|
+
### ldap attributes with many values
|
183
195
|
|
184
196
|
let's say your LDAP has multiple email values for a users then you can define your resource class like that using the type *LdapArray* for such multivalue fields
|
185
197
|
|
@@ -197,7 +209,7 @@ let's say your LDAP has multiple email values for a users then you can define yo
|
|
197
209
|
end
|
198
210
|
end
|
199
211
|
|
200
|
-
|
212
|
+
## REQUIREMENTS:
|
201
213
|
|
202
214
|
* slf4r the logging facade
|
203
215
|
* net-ldap pure ruby ldap library
|
@@ -205,11 +217,11 @@ let's say your LDAP has multiple email values for a users then you can define yo
|
|
205
217
|
* logging (optional) if logging via logging is desired
|
206
218
|
* log4r (optional) if logging via log4r is desired
|
207
219
|
|
208
|
-
|
220
|
+
## INSTALL:
|
209
221
|
|
210
222
|
* sudo gem install dm-ldap-adapter
|
211
223
|
|
212
|
-
|
224
|
+
## LICENSE:
|
213
225
|
|
214
226
|
(The MIT License)
|
215
227
|
|
data/example/posix.rb
CHANGED
@@ -15,14 +15,10 @@ $LOAD_PATH << Pathname(__FILE__).dirname.parent.expand_path + 'lib'
|
|
15
15
|
# logger.level = :debug
|
16
16
|
# logger.info "initialized logger . . ."
|
17
17
|
|
18
|
-
dummy =
|
19
|
-
dummy = false # uncomment this to use ldap
|
18
|
+
dummy = false # uncomment this to use ldap, dummy = false uses the database
|
20
19
|
unless dummy
|
21
20
|
require 'ldap_resource'
|
22
21
|
|
23
|
-
# comment this out if you want to use "net/ldap"
|
24
|
-
require 'ldap/ruby_ldap_facade'
|
25
|
-
|
26
22
|
require 'adapters/ldap_adapter'
|
27
23
|
|
28
24
|
DataMapper.setup(:default, {
|
@@ -82,8 +82,10 @@ module DataMapper
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def sort_records_case_insensitive(records)
|
85
|
+
#Return unsorted records unless we have order defined
|
86
|
+
return records unless order
|
85
87
|
sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] }
|
86
|
-
|
88
|
+
|
87
89
|
records.sort_by do |record|
|
88
90
|
sort_order.map do |(property, ascending)|
|
89
91
|
SortCaseInsensitive.new(record_value(record, property), ascending)
|
@@ -171,9 +173,7 @@ module DataMapper
|
|
171
173
|
|
172
174
|
def create(resources)
|
173
175
|
resources.select do |resource|
|
174
|
-
|
175
176
|
create_resource(resource)
|
176
|
-
|
177
177
|
end.size # just return the number of create resources
|
178
178
|
end
|
179
179
|
|
@@ -306,6 +306,7 @@ module DataMapper
|
|
306
306
|
# @see AbstractAdapter#read
|
307
307
|
def read(query)
|
308
308
|
result = []
|
309
|
+
#get data values out of the query
|
309
310
|
resources = read_resources(query)
|
310
311
|
resources.each do |resource|
|
311
312
|
map = {}
|
@@ -325,8 +326,10 @@ module DataMapper
|
|
325
326
|
end
|
326
327
|
|
327
328
|
def read_resources(query)
|
328
|
-
|
329
|
-
|
329
|
+
query_order = query.order.first.target.field if query.order
|
330
|
+
#Use empty string as default for order in query
|
331
|
+
order_by = query_order || ''
|
332
|
+
|
330
333
|
field_names = query.fields.collect {|f| f.field }
|
331
334
|
result = ldap.read_objects(query.model.treebase,
|
332
335
|
query.model.key.collect { |k| k.field },
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'adapter/ldap-adapter'
|
data/lib/ldap/array.rb
CHANGED
@@ -74,32 +74,49 @@ module Ldap
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
|
77
|
+
# keep the *args so it works for both DM-1.1.x and DM-1.0.x
|
78
|
+
def initialize(_model = nil, _name = nil, options = {}, *args)
|
78
79
|
super
|
80
|
+
|
81
|
+
add_writer(model,name) unless options[:writer] == :private || options[:accessor] == :private
|
82
|
+
add_reader(model,name) unless options[:reader] == :private || options[:accessor] == :private
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def add_reader(model, name)
|
88
|
+
#Creates instance method for reader
|
79
89
|
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
80
|
-
def #{name
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
+
def #{name}
|
91
|
+
attr_data = attribute_get(:#{name})
|
92
|
+
|
93
|
+
case attr_data
|
94
|
+
when Ldap::Array
|
95
|
+
attr_data.setup(self, properties[:#{name}])
|
96
|
+
else
|
97
|
+
new_ldap_array = Ldap::Array.new(self, properties[:#{name}])
|
98
|
+
new_ldap_array.replace(attr_data || [])
|
99
|
+
end
|
90
100
|
end
|
101
|
+
RUBY
|
102
|
+
end
|
91
103
|
|
92
|
-
|
93
|
-
|
94
|
-
|
104
|
+
def add_writer(model, name)
|
105
|
+
#Creates instance method for writer
|
106
|
+
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
107
|
+
def #{name}=(input)
|
108
|
+
data = case input
|
95
109
|
when Ldap::Array
|
96
|
-
|
110
|
+
input.setup(self, properties[:#{name}])
|
97
111
|
else
|
98
|
-
|
99
|
-
|
112
|
+
new_ldap_array = Ldap::Array.new(self, properties[:#{name}])
|
113
|
+
new_ldap_array.replace(input || [])
|
100
114
|
end
|
115
|
+
|
116
|
+
attribute_set(:#{name}, data)
|
101
117
|
end
|
102
118
|
RUBY
|
103
119
|
end
|
120
|
+
|
104
121
|
end
|
105
122
|
end
|
data/lib/ldap/digest.rb
CHANGED
@@ -83,12 +83,18 @@ module Ldap
|
|
83
83
|
# @param Array of conditions for the search
|
84
84
|
# @return Array of Hashes with a name/values pair for each attribute
|
85
85
|
def read_objects(treebase, key_fields, conditions, field_names, order_field = '')
|
86
|
-
|
86
|
+
|
87
|
+
if !conditions.nil? and conditions.size > 0
|
88
|
+
filter = Conditions2Filter.convert(conditions).to_s
|
89
|
+
else
|
90
|
+
filter = "(objectclass=*)"
|
91
|
+
end
|
92
|
+
|
87
93
|
result = []
|
88
94
|
begin
|
89
95
|
@ldap2.search("#{treebase},#{@ldap2.base}",
|
90
96
|
LDAP::LDAP_SCOPE_SUBTREE,
|
91
|
-
filter
|
97
|
+
filter,
|
92
98
|
field_names, false, 0, 0, order_field) do |res|
|
93
99
|
mapp = to_map(field_names, res)
|
94
100
|
# TODO maybe make filter which removes this unless
|
@@ -148,15 +154,21 @@ module Ldap
|
|
148
154
|
# @param dn String for identifying the ldap object
|
149
155
|
# @param password String to be used for authenticate to the dn
|
150
156
|
def authenticate(dn, password)
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
bound = false
|
158
|
+
ldap_con = LDAP::Conn.new(@ldap2.host, @ldap2.port)
|
159
|
+
ldap_con.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )
|
160
|
+
begin
|
161
|
+
ldap_con.bind(dn, password, LDAP::LDAP_AUTH_SIMPLE) do
|
162
|
+
bound = true
|
163
|
+
end
|
164
|
+
rescue LDAP::ResultError => msg
|
165
|
+
if msg.to_s =~ /Invalid\ credentials/i
|
166
|
+
logger.info("Invalid Credentials: #{dn}")
|
167
|
+
else
|
168
|
+
logger.warn "Authentication Error: #{msg.to_s}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
bound
|
160
172
|
end
|
161
173
|
|
162
174
|
# helper to concat the dn from the various parts
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'ldap'
|
2
|
+
require 'slf4r'
|
3
|
+
require 'ldap/conditions_2_filter'
|
4
|
+
|
5
|
+
module Ldap
|
6
|
+
# class Connection < LDAP::Conn
|
7
|
+
|
8
|
+
# attr_reader :base, :host, :port
|
9
|
+
|
10
|
+
# def initialize(config)
|
11
|
+
# super(config[:host], config[:port])
|
12
|
+
# @base = config[:base]
|
13
|
+
# @port = config[:port]
|
14
|
+
# @host = config[:host]
|
15
|
+
# set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
16
|
+
# end
|
17
|
+
|
18
|
+
# end
|
19
|
+
|
20
|
+
class RubyLdapFacade
|
21
|
+
|
22
|
+
# @param config Hash for the ldap connection
|
23
|
+
def self.open(config)
|
24
|
+
ldap3 = com.unboundid.ldap.sdk.LDAPConnection.new(config[:host], config[:port], config[:base] + "." + config[:auth][:username], config[:auth][:password])
|
25
|
+
|
26
|
+
yield ldap
|
27
|
+
end
|
28
|
+
|
29
|
+
include ::Slf4r::Logger
|
30
|
+
|
31
|
+
# @param config Hash for the ldap connection
|
32
|
+
def initialize(config)
|
33
|
+
if config.is_a? Hash
|
34
|
+
@ldap2 = Connection.new(config)
|
35
|
+
@ldap2.bind(config[:auth][:username], config[:auth][:password])
|
36
|
+
else
|
37
|
+
@ldap2 = config
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def retrieve_next_id(treebase, key_field)
|
42
|
+
max = 0
|
43
|
+
@ldap2.search("#{treebase},#{@ldap2.base}",
|
44
|
+
LDAP::LDAP_SCOPE_SUBTREE,
|
45
|
+
"(objectclass=*)",
|
46
|
+
[key_field]) do |entry|
|
47
|
+
n = (entry.vals(key_field) || [0]).first.to_i
|
48
|
+
max = n if max < n
|
49
|
+
end
|
50
|
+
max + 1
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param dn_prefix String the prefix of the dn
|
54
|
+
# @param treebase the treebase of the dn or any search
|
55
|
+
# @param key_field field which carries the integer unique id of the entity
|
56
|
+
# @param props Hash of the ldap attributes of the new ldap object
|
57
|
+
# @return nil in case of an error or the new id of the created object
|
58
|
+
def create_object(dn_prefix, treebase, key_field, props, silence = false)
|
59
|
+
base = "#{treebase},#{@ldap2.base}"
|
60
|
+
mods = props.collect do |k,v|
|
61
|
+
LDAP.mod(LDAP::LDAP_MOD_ADD, k.to_s, v.is_a?(::Array) ? v : [v.to_s] )
|
62
|
+
end
|
63
|
+
if @ldap2.add( dn(dn_prefix, treebase), mods)
|
64
|
+
# :attributes => props) and @ldap.get_operation_result.code.to_s == "0"
|
65
|
+
props[key_field.downcase.to_sym]
|
66
|
+
else
|
67
|
+
unless silence
|
68
|
+
msg = ldap_error("create",
|
69
|
+
dn(dn_prefix, treebase)) + "\n\t#{props.inspect}"
|
70
|
+
# TODO maybe raise always an error
|
71
|
+
if @ldap2.get_operation_result.code.to_s == "68"
|
72
|
+
raise ::DataMapper::PersistenceError.new(msg)
|
73
|
+
else
|
74
|
+
logger.warn(msg)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param treebase the treebase of the search
|
82
|
+
# @param key_fields Array of fields which carries the integer unique id(s) of the entity
|
83
|
+
# @param Array of conditions for the search
|
84
|
+
# @return Array of Hashes with a name/values pair for each attribute
|
85
|
+
def read_objects(treebase, key_fields, conditions, field_names, order_field = '')
|
86
|
+
filter = Conditions2Filter.convert(conditions)
|
87
|
+
result = []
|
88
|
+
begin
|
89
|
+
@ldap2.search("#{treebase},#{@ldap2.base}",
|
90
|
+
LDAP::LDAP_SCOPE_SUBTREE,
|
91
|
+
filter.to_s == "" ? "(objectclass=*)" : filter.to_s.gsub(/\(\(/, "(").gsub(/\)\)/, ")"),
|
92
|
+
field_names, false, 0, 0, order_field) do |res|
|
93
|
+
|
94
|
+
map = to_map(res)
|
95
|
+
#puts map[key_field.to_sym]
|
96
|
+
# TODO maybe make filter which removes this unless
|
97
|
+
# TODO move this into the ldap_Adapter to make it more general, so that
|
98
|
+
# all field with Integer gets converted, etc
|
99
|
+
result << map if key_fields.detect do |key_field|
|
100
|
+
map.member? key_field.to_sym
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# @param dn_prefix String the prefix of the dn
|
109
|
+
# @param treebase the treebase of the dn or any search
|
110
|
+
# @param actions the add/replace/delete actions on the attributes
|
111
|
+
# @return nil in case of an error or true
|
112
|
+
def update_object(dn_prefix, treebase, actions)
|
113
|
+
mods = actions.collect do |act|
|
114
|
+
mod_op = case act[0]
|
115
|
+
when :add
|
116
|
+
LDAP::LDAP_MOD_ADD
|
117
|
+
when :replace
|
118
|
+
LDAP::LDAP_MOD_REPLACE
|
119
|
+
when :delete
|
120
|
+
LDAP::LDAP_MOD_DELETE
|
121
|
+
end
|
122
|
+
LDAP.mod(mod_op, act[1].to_s, act[2] == [] ? [] : [act[2].to_s])
|
123
|
+
end
|
124
|
+
if @ldap2.modify( dn(dn_prefix, treebase),
|
125
|
+
mods )
|
126
|
+
true
|
127
|
+
else
|
128
|
+
logger.warn(ldap_error("update",
|
129
|
+
dn(dn_prefix, treebase) + "\n\t#{actions.inspect}"))
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param dn_prefix String the prefix of the dn
|
135
|
+
# @param treebase the treebase of the dn or any search
|
136
|
+
# @return nil in case of an error or true
|
137
|
+
def delete_object(dn_prefix, treebase)
|
138
|
+
if @ldap2.delete( dn(dn_prefix, treebase) )
|
139
|
+
true
|
140
|
+
else
|
141
|
+
logger.warn(ldap_error("delete",
|
142
|
+
dn(dn_prefix, treebase)))
|
143
|
+
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# @param dn String for identifying the ldap object
|
150
|
+
# @param password String to be used for authenticate to the dn
|
151
|
+
def authenticate(dn, password)
|
152
|
+
Net::LDAP.new( { :host => @ldap2.host,
|
153
|
+
:port => @ldap2.port,
|
154
|
+
:auth => {
|
155
|
+
:method => :simple,
|
156
|
+
:username => dn,
|
157
|
+
:password => password
|
158
|
+
},
|
159
|
+
:base => @ldap2.base
|
160
|
+
} ).bind
|
161
|
+
end
|
162
|
+
|
163
|
+
# helper to concat the dn from the various parts
|
164
|
+
# @param dn_prefix String the prefix of the dn
|
165
|
+
# @param treebase the treebase of the dn or any search
|
166
|
+
# @return the complete dn String
|
167
|
+
def dn(dn_prefix, treebase)
|
168
|
+
"#{dn_prefix},#{treebase},#{@ldap2.base}"
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
# helper to extract the Hash from the ldap search result
|
174
|
+
# @param Entry from the ldap_search
|
175
|
+
# @return Hash with name/value pairs of the entry
|
176
|
+
def to_map(entry)
|
177
|
+
map = {}
|
178
|
+
LDAP::entry2hash(entry).each do |k,v|
|
179
|
+
map[k.downcase.to_sym] = v
|
180
|
+
end
|
181
|
+
map
|
182
|
+
end
|
183
|
+
|
184
|
+
def ldap_error(method, dn)
|
185
|
+
"#{method} error: (#{@ldap2.get_operation_result.code}) #{@ldap2.get_operation_result.message}\n\tDN: #{dn}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
data/lib/ldap_resource.rb
CHANGED
@@ -12,7 +12,8 @@ module DataMapper
|
|
12
12
|
discriminator = properties(repository_name).discriminator
|
13
13
|
no_reload = !query.reload?
|
14
14
|
|
15
|
-
field_map =
|
15
|
+
field_map = {}
|
16
|
+
fields.each { |property| field_map[property] = property.field }
|
16
17
|
|
17
18
|
records.map do |record|
|
18
19
|
identity_map = nil
|
@@ -4,18 +4,42 @@ require 'spec_helper'
|
|
4
4
|
describe DataMapper::Adapters::LdapAdapter do
|
5
5
|
|
6
6
|
before do
|
7
|
-
|
8
7
|
DataMapper.repository(:ldap) do
|
9
8
|
User.all(:login.like => "b%").destroy!
|
10
9
|
Group.all(:name.like => "test_%").destroy!
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
|
11
|
+
#First we create some items.
|
12
|
+
user1 = User.create(:login => "black", :name => 'Black', :age => 0)
|
13
|
+
user2 = User.create(:login => "brown", :name => 'Brown', :age => 25)
|
14
|
+
user3 = User.create(:login => "blue", :name => 'Blue', :age => nil)
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
group1 = Group.create(:name => "test_root_group")
|
17
|
+
group2 = Group.create(:name => "test_admin_group")
|
18
|
+
|
19
|
+
#Then we retrive the items we created earlier and use them for tests.
|
20
|
+
@user1 = User.get!(user1.id)
|
21
|
+
@user2 = User.get!(user2.id)
|
22
|
+
@user3 = User.get!(user3.id)
|
23
|
+
|
24
|
+
@group1 = Group.get!(group1.id)
|
25
|
+
@group2 = Group.get!(group2.id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
after(:all) do
|
30
|
+
DataMapper.repository(:ldap) do
|
31
|
+
User.all(:login.like => "b%").destroy!
|
32
|
+
Group.all(:name.like => "test_%").destroy!
|
17
33
|
end
|
18
34
|
end
|
35
|
+
|
36
|
+
it 'should have valid testing data' do
|
37
|
+
@user1.should be_a_kind_of(User)
|
38
|
+
@user2.should be_a_kind_of(User)
|
39
|
+
@user3.should be_a_kind_of(User)
|
40
|
+
@group1.should be_a_kind_of(Group)
|
41
|
+
@group2.should be_a_kind_of(Group)
|
42
|
+
end
|
19
43
|
|
20
44
|
it 'should successfully save an object' do
|
21
45
|
DataMapper.repository(:ldap) do
|
@@ -129,12 +153,16 @@ describe DataMapper::Adapters::LdapAdapter do
|
|
129
153
|
|
130
154
|
it 'should be able to delete a user from a group' do
|
131
155
|
DataMapper.repository(:ldap) do
|
132
|
-
|
133
|
-
|
156
|
+
size_before = GroupUser.all.size
|
157
|
+
|
134
158
|
@user1.groups << @group1
|
159
|
+
GroupUser.all.size.should == size_before+1
|
160
|
+
|
135
161
|
@user1.groups << @group2
|
162
|
+
GroupUser.all.size.should == size_before+2
|
163
|
+
|
136
164
|
@user2.groups << @group1
|
137
|
-
GroupUser.all.size.should ==
|
165
|
+
GroupUser.all.size.should == size_before+3
|
138
166
|
end
|
139
167
|
DataMapper.repository(:ldap) do
|
140
168
|
@user1 = User.get!(@user1.id)
|
data/spec/contact.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
class Contact
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
def self.auto_upgrade!(args = nil)
|
5
|
+
DataMapper.logger.warn("Skipping #{self.name}.auto_upgrade!")
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.default_repository_name
|
9
|
+
:ldap
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.repository_name
|
13
|
+
:ldap
|
14
|
+
end
|
15
|
+
|
16
|
+
property :id, Serial, :field => 'uid'
|
17
|
+
property :cn, String, :required => true
|
18
|
+
property :salutation, String, :lazy => [:view]
|
19
|
+
property :title, String, :lazy => [:view]
|
20
|
+
property :givenname, String
|
21
|
+
property :sn, String, :required => true
|
22
|
+
property :o, String
|
23
|
+
property :postaladdress, String, :lazy => [:view]
|
24
|
+
property :postalcode, String, :lazy => [:view]
|
25
|
+
property :l, String
|
26
|
+
property :st, String, :lazy => [:view]
|
27
|
+
property :c, String, :lazy => [:view]
|
28
|
+
property :telephonenumber, String
|
29
|
+
property :facsimiletelephonenumber, String, :lazy => [:view]
|
30
|
+
property :pager, String, :lazy => [:view]
|
31
|
+
property :jpegphoto, LdapArray, :lazy => true
|
32
|
+
property :mobile, String, :lazy => [:view]
|
33
|
+
property :anniversary, String, :lazy => [:view]
|
34
|
+
property :mail, LdapArray
|
35
|
+
property :labeleduri, LdapArray, :lazy => [:view]
|
36
|
+
property :marker, LdapArray, :lazy => [:view]
|
37
|
+
property :description, LdapArray, :lazy => [:view]
|
38
|
+
|
39
|
+
dn_prefix do |u|
|
40
|
+
"uid=#{u.id}"
|
41
|
+
end
|
42
|
+
|
43
|
+
ldap_properties do |u|
|
44
|
+
properties = { :objectclass => ['inetOrgPerson']}#, "posixAccount", "shadowAccount"]}#'contactPerson'] }
|
45
|
+
properties
|
46
|
+
end
|
47
|
+
|
48
|
+
treebase 'ou=people'
|
49
|
+
|
50
|
+
before :save, :fix_object
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def fix_object
|
55
|
+
self.cn = "#{self.givenname} #{self.sn}".strip
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
$LOAD_PATH << Pathname(__FILE__).dirname.parent.expand_path + 'lib'
|
2
|
+
|
3
|
+
require 'ldap/array'
|
4
|
+
require 'dm-migrations'
|
5
|
+
require 'dm-sqlite-adapter'
|
6
|
+
|
7
|
+
class A
|
8
|
+
|
9
|
+
include DataMapper::Resource
|
10
|
+
|
11
|
+
property :id, Serial
|
12
|
+
property :list, ::Ldap::LdapArray, :accessor => :public
|
13
|
+
property :hidden_list, ::Ldap::LdapArray, :accessor => :private
|
14
|
+
property :write_list, ::Ldap::LdapArray, :reader => :private, :writer => :public
|
15
|
+
property :read_list, ::Ldap::LdapArray, :reader => :public, :writer => :private
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'fileutils'
|
19
|
+
FileUtils.mkdir_p("target")
|
20
|
+
DataMapper.setup(:default, 'sqlite3:target/test.sqlite3')
|
21
|
+
DataMapper.finalize
|
22
|
+
DataMapper.auto_migrate!(:default)
|
23
|
+
|
24
|
+
describe Ldap::LdapArray do
|
25
|
+
before { @resource = A.new }
|
26
|
+
|
27
|
+
it 'should create new with array' do
|
28
|
+
@resource.list = ["1", "2"]
|
29
|
+
@resource.dirty?.should be_true
|
30
|
+
@resource.save
|
31
|
+
resource = A.first(:id => @resource.id)
|
32
|
+
resource.list.should == ["1", "2"]
|
33
|
+
resource.list.class.should == Ldap::Array
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should have empty array on new resource' do
|
37
|
+
@resource.list << "1"
|
38
|
+
@resource.dirty?.should be_true
|
39
|
+
@resource.save
|
40
|
+
resource = A.first(:id => @resource.id)
|
41
|
+
resource.list.should == ["1"]
|
42
|
+
resource.list.class.should == Ldap::Array
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should save after adding an element' do
|
46
|
+
@resource.list = ["1", "2"]
|
47
|
+
@resource.save
|
48
|
+
@resource.list << "4"
|
49
|
+
@resource.save
|
50
|
+
resource = A.first(:id => @resource.id)
|
51
|
+
resource.list.should == ["1", "2", "4"]
|
52
|
+
resource.list.class.should == Ldap::Array
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should save after changing an element' do
|
56
|
+
@resource.list = ["1", "2"]
|
57
|
+
@resource.save
|
58
|
+
@resource.list[1] = "4"
|
59
|
+
@resource.save
|
60
|
+
resource = A.first(:id => @resource.id)
|
61
|
+
resource.list.should == ["1", "4"]
|
62
|
+
resource.list.class.should == Ldap::Array
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should save after deleting element from list' do
|
66
|
+
@resource.list = ["1", "2"]
|
67
|
+
@resource.save
|
68
|
+
@resource.list.delete("1")
|
69
|
+
@resource.save
|
70
|
+
resource = A.first(:id => @resource.id)
|
71
|
+
resource.list.should == ["2"]
|
72
|
+
resource.list.class.should == Ldap::Array
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when :accessor property is set to :private' do
|
76
|
+
it 'should not create a write accessor' do
|
77
|
+
@resource.should_not respond_to(:hidden_list=)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should not create a reade accessor' do
|
81
|
+
@resource.should_not respond_to(:hidden_list)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when :accessor property is set to :public' do
|
86
|
+
it 'should create a write accessor' do
|
87
|
+
@resource.should respond_to(:list=)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should create a reade accessor' do
|
91
|
+
@resource.should respond_to(:list)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when :writer property is set to :public' do
|
96
|
+
it 'should create a write accessor' do
|
97
|
+
@resource.should respond_to(:write_list=)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when :writer property is set to :private' do
|
102
|
+
it 'should not create a write accessor' do
|
103
|
+
@resource.should_not respond_to(:read_list=)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when :reader property is set to :public' do
|
108
|
+
it 'should create a read accessor' do
|
109
|
+
@resource.should respond_to(:read_list)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when :reader property is set to :private' do
|
114
|
+
it 'should not create a read accessor' do
|
115
|
+
@resource.should_not respond_to(:write_list)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -151,7 +151,6 @@ describe DataMapper.repository(:ldap).adapter.class do
|
|
151
151
|
end
|
152
152
|
|
153
153
|
it 'should be able to use multilines with LdapArray' do
|
154
|
-
pending "not working for net-ldap" if DataMapper.repository(:ldap).adapter.ldap.class.to_s == 'Ldap::NetLdapFacade'
|
155
154
|
DataMapper.repository(:ldap) do
|
156
155
|
@contact.mail = ["email1\nmail2\nmail2\nmail4", "email1"]
|
157
156
|
@contact.save
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
3
|
require 'slf4r/ruby_logger'
|
4
|
-
Slf4r::LoggerFacade4RubyLogger.level = :
|
4
|
+
Slf4r::LoggerFacade4RubyLogger.level = :warn
|
5
5
|
|
6
6
|
require 'dm-sqlite-adapter'
|
7
7
|
require 'dm-migrations'
|
@@ -26,6 +26,8 @@ DataMapper.setup(:ldap, {
|
|
26
26
|
:password => "behappy"
|
27
27
|
})
|
28
28
|
|
29
|
+
puts "using facade #{(ENV['FACADE'] || :net_ldap).to_sym}"
|
30
|
+
|
29
31
|
module DataMapper
|
30
32
|
module Resource
|
31
33
|
class State
|
@@ -55,25 +57,30 @@ class User
|
|
55
57
|
has n, :group_users
|
56
58
|
|
57
59
|
def groups
|
58
|
-
groups = GroupUser.all(:user_id =>
|
60
|
+
groups = GroupUser.all(:user_id => login).collect{ |gu| gu.group }
|
61
|
+
|
59
62
|
def groups.user=(user)
|
60
63
|
@user = user
|
61
64
|
end
|
65
|
+
|
62
66
|
groups.user = self
|
67
|
+
|
63
68
|
def groups.<<(group)
|
64
69
|
unless member? group
|
65
|
-
GroupUser.create(:user_id => @user.
|
70
|
+
GroupUser.create(:user_id => @user.login, :group_id => group.id)
|
66
71
|
super
|
67
72
|
end
|
68
73
|
self
|
69
74
|
end
|
75
|
+
|
70
76
|
def groups.delete(group)
|
71
|
-
gu = GroupUser.first(:user_id => @user.
|
77
|
+
gu = GroupUser.first(:user_id => @user.login, :group_id => group.id)
|
72
78
|
if gu
|
73
79
|
gu.destroy
|
74
80
|
super
|
75
81
|
end
|
76
82
|
end
|
83
|
+
|
77
84
|
groups
|
78
85
|
end
|
79
86
|
|
@@ -90,7 +97,8 @@ class User
|
|
90
97
|
end
|
91
98
|
|
92
99
|
def password=(password)
|
93
|
-
|
100
|
+
salt = "--#{Time.now}--#{login}--"
|
101
|
+
attribute_set(:hashed_password, Ldap::Digest.ssha(password, salt)) if password
|
94
102
|
end
|
95
103
|
end
|
96
104
|
|
@@ -133,7 +141,7 @@ class GroupUser
|
|
133
141
|
{:cn=>"#{group_user.group.name}", :objectclass => "posixGroup"}
|
134
142
|
end
|
135
143
|
|
136
|
-
property :user_id,
|
144
|
+
property :user_id, String, :key => true, :field => "memberUid"
|
137
145
|
property :group_id, Integer, :key => true, :field => "gidNumber"
|
138
146
|
|
139
147
|
def group
|
metadata
CHANGED
@@ -1,37 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-ldap-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 3
|
10
|
+
version: 0.4.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- mkristian
|
14
|
+
- xertres
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2011-
|
19
|
+
date: 2011-06-06 00:00:00 +05:30
|
19
20
|
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
23
|
+
name: net-ldap
|
23
24
|
prerelease: false
|
24
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
26
|
none: false
|
26
27
|
requirements:
|
27
|
-
- -
|
28
|
+
- - ~>
|
28
29
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
30
|
+
hash: 19
|
30
31
|
segments:
|
31
32
|
- 0
|
32
|
-
-
|
33
|
-
-
|
34
|
-
version: 0.
|
33
|
+
- 2
|
34
|
+
- 2
|
35
|
+
version: 0.2.2
|
35
36
|
type: :runtime
|
36
37
|
version_requirements: *id001
|
37
38
|
- !ruby/object:Gem::Dependency
|
@@ -40,12 +41,14 @@ dependencies:
|
|
40
41
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
42
|
none: false
|
42
43
|
requirements:
|
43
|
-
- -
|
44
|
+
- - ~>
|
44
45
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
46
|
+
hash: 11
|
46
47
|
segments:
|
47
48
|
- 0
|
48
|
-
|
49
|
+
- 4
|
50
|
+
- 2
|
51
|
+
version: 0.4.2
|
49
52
|
type: :runtime
|
50
53
|
version_requirements: *id002
|
51
54
|
- !ruby/object:Gem::Dependency
|
@@ -56,74 +59,134 @@ dependencies:
|
|
56
59
|
requirements:
|
57
60
|
- - ~>
|
58
61
|
- !ruby/object:Gem::Version
|
59
|
-
hash:
|
62
|
+
hash: 15
|
60
63
|
segments:
|
61
64
|
- 1
|
62
65
|
- 0
|
63
|
-
|
64
|
-
version: 1.0.0
|
66
|
+
version: "1.0"
|
65
67
|
type: :runtime
|
66
68
|
version_requirements: *id003
|
67
69
|
- !ruby/object:Gem::Dependency
|
68
|
-
name:
|
70
|
+
name: dm-transactions
|
69
71
|
prerelease: false
|
70
72
|
requirement: &id004 !ruby/object:Gem::Requirement
|
71
73
|
none: false
|
72
74
|
requirements:
|
73
|
-
- -
|
75
|
+
- - ~>
|
74
76
|
- !ruby/object:Gem::Version
|
75
|
-
hash:
|
77
|
+
hash: 15
|
78
|
+
segments:
|
79
|
+
- 1
|
80
|
+
- 0
|
81
|
+
version: "1.0"
|
82
|
+
type: :runtime
|
83
|
+
version_requirements: *id004
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: dm-sqlite-adapter
|
86
|
+
prerelease: false
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ~>
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 15
|
93
|
+
segments:
|
94
|
+
- 1
|
95
|
+
- 0
|
96
|
+
version: "1.0"
|
97
|
+
type: :development
|
98
|
+
version_requirements: *id005
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: dm-migrations
|
101
|
+
prerelease: false
|
102
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ~>
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 15
|
108
|
+
segments:
|
109
|
+
- 1
|
110
|
+
- 0
|
111
|
+
version: "1.0"
|
112
|
+
type: :development
|
113
|
+
version_requirements: *id006
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
name: rspec
|
116
|
+
prerelease: false
|
117
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ~>
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
hash: 23
|
76
123
|
segments:
|
77
124
|
- 2
|
78
|
-
-
|
125
|
+
- 6
|
79
126
|
- 0
|
80
|
-
version: 2.
|
127
|
+
version: 2.6.0
|
81
128
|
type: :development
|
82
|
-
version_requirements: *
|
129
|
+
version_requirements: *id007
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: ruby-ldap
|
132
|
+
prerelease: false
|
133
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 45
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
- 9
|
142
|
+
- 11
|
143
|
+
version: 0.9.11
|
144
|
+
type: :development
|
145
|
+
version_requirements: *id008
|
83
146
|
description: ldap adapter for datamapper which uses either net-ldap or ruby-ldap
|
84
147
|
email:
|
85
148
|
- m.kristian@web.de
|
149
|
+
- ""
|
86
150
|
executables: []
|
87
151
|
|
88
152
|
extensions: []
|
89
153
|
|
90
154
|
extra_rdoc_files:
|
91
155
|
- History.txt
|
92
|
-
-
|
93
|
-
- README.txt
|
156
|
+
- README.md
|
94
157
|
- ldap-commands.txt
|
95
158
|
files:
|
96
|
-
- .project
|
97
|
-
- .yardoc
|
98
159
|
- History.txt
|
99
160
|
- MIT-LICENSE
|
100
|
-
- Manifest.txt
|
101
|
-
- README-example.markdown
|
102
|
-
- README.txt
|
103
|
-
- Rakefile
|
104
|
-
- example/posix.rb
|
105
161
|
- ldap-commands.txt
|
162
|
+
- README.md
|
163
|
+
- README-example.md
|
164
|
+
- README-bundler.md
|
106
165
|
- lib/adapters/ldap_adapter.rb
|
107
166
|
- lib/adapters/noop_transaction.rb
|
167
|
+
- lib/dm-ldap-adapter.rb
|
168
|
+
- lib/ldap_resource.rb
|
108
169
|
- lib/dummy_ldap_resource.rb
|
109
|
-
- lib/ldap/
|
110
|
-
- lib/ldap/
|
170
|
+
- lib/ldap/version.rb
|
171
|
+
- lib/ldap/unboundid_ldap_facade.rb
|
172
|
+
- lib/ldap/transactions.rb
|
173
|
+
- lib/ldap/ruby_ldap_facade.rb
|
111
174
|
- lib/ldap/digest.rb
|
112
175
|
- lib/ldap/net_ldap_facade.rb
|
113
|
-
- lib/ldap/
|
114
|
-
- lib/ldap/
|
115
|
-
- lib/ldap_resource.rb
|
116
|
-
- spec/assiociations_ldap_adapter_spec.rb
|
117
|
-
- spec/authentication_ldap_adapter_spec.rb
|
118
|
-
- spec/ldap_adapter_spec.rb
|
119
|
-
- spec/multi_repository_spec.rb
|
176
|
+
- lib/ldap/conditions_2_filter.rb
|
177
|
+
- lib/ldap/array.rb
|
120
178
|
- spec/multi_value_attributes_spec.rb
|
121
179
|
- spec/sorting_spec.rb
|
122
|
-
- spec/
|
180
|
+
- spec/multi_repository_spec.rb
|
181
|
+
- spec/contact.rb
|
123
182
|
- spec/spec_helper.rb
|
124
|
-
-
|
183
|
+
- spec/ldap_adapter_spec.rb
|
184
|
+
- spec/authentication_ldap_adapter_spec.rb
|
185
|
+
- spec/assiociations_ldap_adapter_spec.rb
|
186
|
+
- spec/ldap_array_spec.rb
|
187
|
+
- example/posix.rb
|
125
188
|
has_rdoc: true
|
126
|
-
homepage: http://dm-ldap-adapter
|
189
|
+
homepage: http://github.com/mkristian/dm-ldap-adapter
|
127
190
|
licenses: []
|
128
191
|
|
129
192
|
post_install_message:
|
@@ -152,8 +215,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
215
|
version: "0"
|
153
216
|
requirements: []
|
154
217
|
|
155
|
-
rubyforge_project:
|
156
|
-
rubygems_version: 1.3
|
218
|
+
rubyforge_project:
|
219
|
+
rubygems_version: 1.5.3
|
157
220
|
signing_key:
|
158
221
|
specification_version: 3
|
159
222
|
summary: ""
|
data/.project
DELETED
data/.yardoc
DELETED
Binary file
|
data/Manifest.txt
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
.project
|
2
|
-
.yardoc
|
3
|
-
History.txt
|
4
|
-
MIT-LICENSE
|
5
|
-
Manifest.txt
|
6
|
-
README-example.markdown
|
7
|
-
README.txt
|
8
|
-
Rakefile
|
9
|
-
example/posix.rb
|
10
|
-
ldap-commands.txt
|
11
|
-
lib/adapters/ldap_adapter.rb
|
12
|
-
lib/adapters/noop_transaction.rb
|
13
|
-
lib/dummy_ldap_resource.rb
|
14
|
-
lib/ldap/array.rb
|
15
|
-
lib/ldap/conditions_2_filter.rb
|
16
|
-
lib/ldap/digest.rb
|
17
|
-
lib/ldap/net_ldap_facade.rb
|
18
|
-
lib/ldap/ruby_ldap_facade.rb
|
19
|
-
lib/ldap/version.rb
|
20
|
-
lib/ldap_resource.rb
|
21
|
-
spec/assiociations_ldap_adapter_spec.rb
|
22
|
-
spec/authentication_ldap_adapter_spec.rb
|
23
|
-
spec/ldap_adapter_spec.rb
|
24
|
-
spec/multi_repository_spec.rb
|
25
|
-
spec/multi_value_attributes_spec.rb
|
26
|
-
spec/sorting_spec.rb
|
27
|
-
spec/spec.opts
|
28
|
-
spec/spec_helper.rb
|
29
|
-
test.ldif
|
data/Rakefile
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# -*- ruby -*-
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'hoe'
|
5
|
-
require './lib/ldap/version.rb'
|
6
|
-
|
7
|
-
require 'spec'
|
8
|
-
require 'spec/rake/spectask'
|
9
|
-
require 'pathname'
|
10
|
-
|
11
|
-
Hoe.spec('dm-ldap-adapter') do |p|
|
12
|
-
p.version = "0.4.2"
|
13
|
-
p.description = "ldap adapter for datamapper which uses either net-ldap or ruby-ldap"
|
14
|
-
p.developer('mkristian', 'm.kristian@web.de')
|
15
|
-
p.url = "http://dm-ldap-adapter.rubyforge.org"
|
16
|
-
p.extra_deps = [['ruby-net-ldap', '=0.0.4'],['slf4r', '>=0'], ['dm-core', '~>1.0.0']]
|
17
|
-
p.remote_rdoc_dir = '' # Release to root
|
18
|
-
end
|
19
|
-
|
20
|
-
desc 'Install the package as a gem.'
|
21
|
-
task :install => [:clean, :package] do
|
22
|
-
gem = Dir['pkg/*.gem'].first
|
23
|
-
sh "gem install --local #{gem} --no-ri --no-rdoc"
|
24
|
-
end
|
25
|
-
|
26
|
-
desc 'Run specifications'
|
27
|
-
Spec::Rake::SpecTask.new(:spec) do |t|
|
28
|
-
if File.exists?('spec/spec.opts')
|
29
|
-
t.spec_opts << '--options' << 'spec/spec.opts'
|
30
|
-
end
|
31
|
-
t.spec_files = Pathname.glob('./spec/**/*_spec.rb')
|
32
|
-
end
|
33
|
-
|
34
|
-
#require 'yard'
|
35
|
-
|
36
|
-
#YARD::Rake::YardocTask.new
|
37
|
-
|
38
|
-
# vim: syntax=Ruby
|
data/spec/spec.opts
DELETED
data/test.ldif
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
dn: ou=people,dc=example,dc=com
|
2
|
-
objectClass: organizationalUnit
|
3
|
-
ou: people
|
4
|
-
|
5
|
-
dn: ou=groups,dc=example,dc=com
|
6
|
-
objectClass: organizationalUnit
|
7
|
-
ou: groups
|
8
|
-
|
9
|
-
dn: uid=kristian,ou=people,dc=example,dc=com
|
10
|
-
objectClass: inetOrgPerson
|
11
|
-
objectClass: posixAccount
|
12
|
-
uid: kristian
|
13
|
-
sn: Meier
|
14
|
-
givenName: Kristian
|
15
|
-
cn: Kristian Meier
|
16
|
-
uidNumber: 1000
|
17
|
-
gidNumber: 10000
|
18
|
-
userPassword: {SSHA}/o6oa2GOphls/lzOFCwVkw9ARWEEiw+x
|
19
|
-
mail: m.kristian@web.de
|
20
|
-
loginShell: /bin/false
|
21
|
-
homeDirectory:
|
22
|
-
|
23
|
-
dn: cn=manager,ou=groups,dc=example,dc=com
|
24
|
-
objectClass: posixGroup
|
25
|
-
cn: manager
|
26
|
-
gidNumber: 10000
|
27
|
-
|
28
|
-
dn: cn=admin,ou=groups,dc=example,dc=com
|
29
|
-
objectClass: posixGroup
|
30
|
-
cn: admin
|
31
|
-
gidNumber: 10001
|
32
|
-
memberUid: kristian
|
33
|
-
|
34
|
-
dn: uid=bill,ou=people,dc=example,dc=com
|
35
|
-
objectClass: inetOrgPerson
|
36
|
-
objectClass: posixAccount
|
37
|
-
uid: bill
|
38
|
-
sn: bill
|
39
|
-
givenName: bill
|
40
|
-
cn: bill
|
41
|
-
uidNumber: 1001
|
42
|
-
gidNumber: 10000
|
43
|
-
userPassword: {SSHA}/o6oa2GOphls/lzOFCwVkw9ARWEEiw+x
|
44
|
-
mail: bill@web.de
|
45
|
-
loginShell: /bin/false
|
46
|
-
homeDirectory: /root
|