dm-ldap-adapter 0.4.3-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ require "dm-core"
2
+
3
+ module Ldap
4
+ class NoopTransaction
5
+
6
+ def close ; end
7
+ def begin ; end
8
+ def prepare ; end
9
+ def commit ; end
10
+ def rollback ; end
11
+ def rollback_prepared ; end
12
+
13
+ end
14
+ end
15
+
16
+ module DataMapper
17
+ module Adapters
18
+ class LdapAdapter
19
+ def transaction_primitive
20
+ ::Ldap::NoopTransaction.new
21
+ end
22
+ def push_transaction(transaction)
23
+ @transaction = transaction
24
+ end
25
+
26
+ def pop_transaction
27
+ @transaction
28
+ end
29
+
30
+ def current_transaction
31
+ @transaction
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1 @@
1
+ require 'adapter/ldap-adapter'
@@ -0,0 +1,60 @@
1
+ require 'slf4r/logger'
2
+ require 'ldap/digest'
3
+
4
+ # dummy implementation which turns the extra ldap configuration noops
5
+ module DataMapper
6
+ module Resource
7
+
8
+ module ClassMethods
9
+
10
+ include ::Slf4r::Logger
11
+
12
+ def ldap_properties(resource = nil, &block)
13
+ if block
14
+ @ldap_properties = block
15
+ elsif resource.instance_of? Hash
16
+ @ldap_properties = resource
17
+ logger.debug { "ldap_properties=#{@ldap_properties.inspect}" }
18
+ elsif resource
19
+ logger.debug { "ldap_properties=#{@ldap_properties.call(resource).inspect}" }
20
+ else
21
+ logger.debug { "ldap_properties=#{@ldap_properties.inspect}" }
22
+ end
23
+ end
24
+
25
+ def treebase(resource = nil, &block)
26
+ if block
27
+ @treebase = block
28
+ elsif resource.instance_of? String
29
+ @treebase = resource
30
+ logger.debug { "treebase=#{@treebase.inspect}" }
31
+ elsif resource
32
+ logger.debug { "treebase=#{@treebase.call(resource).inspect}" }
33
+ else
34
+ logger.debug { "treebase=#{@treebase}" }
35
+ end
36
+ end
37
+
38
+ def dn_prefix(resource = nil, &block)
39
+ if block
40
+ @dn_prefix = block
41
+ elsif resource.instance_of? Hash
42
+ @dn_prefix = resource
43
+ logger.debug { "dn_prefix=#{@dn_prefix.inspect}" }
44
+ elsif resource
45
+ logger.debug { "dn_prefix=#{@dn_prefix.call(resource).inspect}" }
46
+ else
47
+ logger.debug { "dn_prefix=#{dn_prefix}" }
48
+ end
49
+ end
50
+
51
+ def multivalue_field(field = nil)
52
+ logger.debug { "multivalue_field = #{field}" } if field
53
+ end
54
+ end
55
+
56
+ def authenticate(password)
57
+ raise "NotImplemented"
58
+ end
59
+ end
60
+ end
data/lib/ldap/array.rb ADDED
@@ -0,0 +1,122 @@
1
+ require 'dm-core'
2
+ module Ldap
3
+ class Array < ::Array
4
+
5
+ def initialize(resource, property, *args)
6
+ setup(resource, property)
7
+ super(args)
8
+ end
9
+
10
+ def setup(resource, property)
11
+ @resource = resource
12
+ @property = property
13
+ self
14
+ end
15
+
16
+ alias :push! :push
17
+
18
+ def []=(k, v)
19
+ ar = [self].flatten
20
+ ar[k] = v
21
+ @resource.send("#{@property.name}=".to_sym, ar)
22
+ super
23
+ end
24
+
25
+ def <<(element)
26
+ push(element)
27
+ end
28
+
29
+ def push(element)
30
+ ar = [self].flatten
31
+ ar.push(element)
32
+ @resource.send("#{@property.name}=".to_sym, ar)
33
+ super
34
+ end
35
+
36
+ alias :delete! :delete
37
+
38
+ def delete(element)
39
+ ar = [self].flatten
40
+ ar.delete(element)
41
+ @resource.send(:"#{@property.name}=", ar)
42
+ super
43
+ end
44
+ end
45
+
46
+ class LdapArray < ::DataMapper::Property::Text
47
+
48
+ default Proc.new { |r,p| Ldap::Array.new(r,p) }
49
+
50
+ def custom?
51
+ true
52
+ end
53
+
54
+ def primitive?(value)
55
+ super || value.kind_of?(::Array)
56
+ end
57
+
58
+ def load(value)
59
+ result = case value
60
+ when ::String then value[1, value.size-2].split('","').to_a.freeze
61
+ when ::Array then value.freeze
62
+ else
63
+ []
64
+ end
65
+ end
66
+
67
+ def dump(value)
68
+ result = case value
69
+ when LdapArray then '"' + value.join('","') + '"'
70
+ when ::Array then '"' + value.join('","') + '"'
71
+ when ::String then '"' + value.to_s + '"'
72
+ else
73
+ nil
74
+ end
75
+ end
76
+
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)
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
89
+ model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
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
100
+ end
101
+ RUBY
102
+ end
103
+
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
109
+ when Ldap::Array
110
+ input.setup(self, properties[:#{name}])
111
+ else
112
+ new_ldap_array = Ldap::Array.new(self, properties[:#{name}])
113
+ new_ldap_array.replace(input || [])
114
+ end
115
+
116
+ attribute_set(:#{name}, data)
117
+ end
118
+ RUBY
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,95 @@
1
+ require 'net/ldap'
2
+
3
+ module Ldap
4
+ class Conditions2Filter
5
+
6
+ @@logger = ::Slf4r::LoggerFacade.new(::Ldap::Conditions2Filter)
7
+
8
+ # @param Array of conditions for the search
9
+ # @return Array of Hashes with a name/values pair for each attribute
10
+ def self.convert(conditions)
11
+ @@logger.debug { "conditions #{conditions.inspect}" }
12
+ filters = []
13
+ conditions.each do |cond|
14
+ c = cond[2]
15
+ case cond[0]
16
+ when :or_operator
17
+ f = nil
18
+ cond[1].each do |cc|
19
+ ff = case cc[0]
20
+ when :eql
21
+ Net::LDAP::Filter.eq( cc[1].to_s, cc[2].to_s )
22
+ when :gte
23
+ Net::LDAP::Filter.ge( cc[1].to_s, cc[2].to_s )
24
+ when :lte
25
+ Net::LDAP::Filter.le( cc[1].to_s, cc[2].to_s )
26
+ when :like
27
+ Net::LDAP::Filter.eq( cc[1].to_s, cc[2].to_s.gsub(/%/, "*").gsub(/_/, "*").gsub(/\*\*/, "*") )
28
+ else
29
+ logger.error(cc[0].to_s + " needs coding")
30
+ end
31
+ if f
32
+ f = f | ff
33
+ else
34
+ f = ff
35
+ end
36
+ end
37
+ when :eql
38
+ if c.nil?
39
+ f = ~ Net::LDAP::Filter.pres( cond[1].to_s )
40
+ elsif c.respond_to? :each
41
+ f = nil
42
+ c.each do |cc|
43
+ if f
44
+ f = f | Net::LDAP::Filter.eq( cond[1].to_s, cc.to_s )
45
+ else
46
+ f = Net::LDAP::Filter.eq( cond[1].to_s, cc.to_s )
47
+ end
48
+ end
49
+ #elsif c.class == Range
50
+ # p c
51
+ # f = Net::LDAP::Filter.ge( cond[1].to_s, c.begin.to_s ) & Net::LDAP::Filter.le( cond[1].to_s, c.end.to_s )
52
+ else
53
+ f = Net::LDAP::Filter.eq( cond[1].to_s, c.to_s )
54
+ end
55
+ when :gte
56
+ f = Net::LDAP::Filter.ge( cond[1].to_s, c.to_s )
57
+ when :lte
58
+ f = Net::LDAP::Filter.le( cond[1].to_s, c.to_s )
59
+ when :not
60
+ if c.nil?
61
+ f = Net::LDAP::Filter.pres( cond[1].to_s )
62
+ elsif c.respond_to? :each
63
+ f = nil
64
+ c.each do |cc|
65
+ if f
66
+ f = f | Net::LDAP::Filter.eq( cond[1].to_s, cc.to_s )
67
+ else
68
+ f = Net::LDAP::Filter.eq( cond[1].to_s, cc.to_s )
69
+ end
70
+ end
71
+ f = ~ f
72
+ else
73
+ f = ~ Net::LDAP::Filter.eq( cond[1].to_s, c.to_s )
74
+ end
75
+ when :like
76
+ f = Net::LDAP::Filter.eq( cond[1].to_s, c.to_s.gsub(/%/, "*").gsub(/_/, "*").gsub(/\*\*/, "*") )
77
+ else
78
+ logger.error(cond[0].to_s + " needs coding")
79
+ end
80
+ filters << f if f
81
+ end
82
+
83
+ filter = nil
84
+ filters.each do |f|
85
+ if filter.nil?
86
+ filter = f
87
+ else
88
+ filter = filter & f
89
+ end
90
+ end
91
+ @@logger.debug { "search filter: (#{filter.to_s})" }
92
+ filter
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,30 @@
1
+ begin
2
+ require 'sha1'
3
+ rescue LoadError
4
+ # ruby1.9.x
5
+ require 'digest/sha1'
6
+ SHA1 = Digest::SHA1
7
+ end
8
+
9
+ require 'base64'
10
+ module Ldap
11
+ class Digest
12
+ # method from openldap faq which produces the userPassword attribute
13
+ # for the ldap
14
+ # @param secret String the password
15
+ # @param salt String the salt for the password digester
16
+ # @return the encoded password/salt
17
+ def self.ssha(secret, salt)
18
+ (salt.empty? ? "{SHA}": "{SSHA}") +
19
+ Base64.encode64(::Digest::SHA1.digest(secret + salt) + salt).gsub(/\n/, '')
20
+ end
21
+
22
+ # method from openldap faq which produces the userPassword attribute
23
+ # for the ldap
24
+ # @param secret String the password
25
+ # @return the encoded password
26
+ def self.sha(secret)
27
+ ssha(secret, "")
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,161 @@
1
+ require 'net/ldap'
2
+ require 'ldap/conditions_2_filter'
3
+
4
+ module Ldap
5
+ class NetLdapFacade
6
+
7
+ # @param config Hash for the ldap connection
8
+ def self.open(config)
9
+ Net::LDAP.open( config ) do |ldap|
10
+ yield ldap
11
+ end
12
+ end
13
+
14
+ include ::Slf4r::Logger
15
+
16
+ # @param config Hash for the ldap connection
17
+ def initialize(config)
18
+ if config.is_a? Hash
19
+ @ldap = Net::LDAP.new( config )
20
+ else
21
+ @ldap = config
22
+ end
23
+ end
24
+
25
+ def retrieve_next_id(treebase, key_field)
26
+ base = "#{treebase},#{@ldap.base}"
27
+ id_sym = key_field.downcase.to_sym
28
+ max = 0
29
+ @ldap.search( :base => base,
30
+ :attributes => [key_field],
31
+ :return_result => false ) do |entry|
32
+ n = entry[id_sym].first.to_i
33
+ max = n if max < n
34
+ end
35
+ max + 1
36
+ end
37
+
38
+ # @param dn_prefix String the prefix of the dn
39
+ # @param treebase the treebase of the dn or any search
40
+ # @param key_field field which carries the integer unique id of the entity
41
+ # @param props Hash of the ldap attributes of the new ldap object
42
+ # @return nil in case of an error or the new id of the created object
43
+ def create_object(dn_prefix, treebase, key_field, props, silence = false)
44
+ base = "#{treebase},#{@ldap.base}"
45
+ if @ldap.add( :dn => dn(dn_prefix, treebase),
46
+ :attributes => props) || @ldap.get_operation_result.code.to_s == "0"
47
+ props[key_field.to_sym]
48
+ else
49
+ unless silence
50
+ msg = ldap_error("create",
51
+ dn(dn_prefix, treebase)) + "\n\t#{props.inspect}"
52
+ # TODO maybe raise always an error
53
+ if @ldap.get_operation_result.code.to_s == "68"
54
+ raise ::DataMapper::PersistenceError.new(msg)
55
+ else
56
+ logger.warn(msg)
57
+ end
58
+ end
59
+ nil
60
+ end
61
+ end
62
+
63
+ # @param treebase the treebase of the search
64
+ # @param key_fields Array of fields which carries the integer unique id(s) of the entity
65
+ # @param Array of conditions for the search
66
+ # @return Array of Hashes with a name/values pair for each attribute
67
+ def read_objects(treebase, key_fields, conditions, field_names, order_field = nil)
68
+ result = []
69
+ filter = Conditions2Filter.convert(conditions)
70
+ @ldap.search( :base => "#{treebase},#{@ldap.base}",
71
+ :attributes => field_names,
72
+ :filter => filter ) do |res|
73
+ mapp = to_map(field_names, res)
74
+
75
+ #puts map[key_field.to_sym]
76
+ # TODO maybe make filter which removes this unless
77
+ # TODO move this into the ldap_Adapter to make it more general, so that
78
+ # all field with Integer gets converted, etc
79
+ result << mapp if key_fields.detect do |key_field|
80
+ mapp.keys.detect {|k| k.to_s.downcase == key_field.downcase }
81
+ end
82
+ end
83
+ result
84
+ end
85
+
86
+
87
+ # @param dn_prefix String the prefix of the dn
88
+ # @param treebase the treebase of the dn or any search
89
+ # @param actions the add/replace/delete actions on the attributes
90
+ # @return nil in case of an error or true
91
+ def update_object(dn_prefix, treebase, actions)
92
+ if @ldap.modify( :dn => dn(dn_prefix, treebase),
93
+ :operations => actions ) || @ldap.get_operation_result.code.to_s == "0"
94
+ true
95
+ else
96
+ logger.warn(ldap_error("update",
97
+ dn(dn_prefix, treebase) + "\n\t#{actions.inspect}"))
98
+ nil
99
+ end
100
+ end
101
+
102
+ # @param dn_prefix String the prefix of the dn
103
+ # @param treebase the treebase of the dn or any search
104
+ # @return nil in case of an error or true
105
+ def delete_object(dn_prefix, treebase)
106
+ if @ldap.delete( :dn => dn(dn_prefix, treebase) )
107
+ true
108
+ else
109
+ logger.warn(ldap_error("delete",
110
+ dn(dn_prefix, treebase)))
111
+
112
+ nil
113
+ end
114
+ end
115
+
116
+
117
+ # @param dn String for identifying the ldap object
118
+ # @param password String to be used for authenticate to the dn
119
+ def authenticate(dn, password)
120
+ Net::LDAP.new( { :host => @ldap.host,
121
+ :port => @ldap.port,
122
+ :auth => {
123
+ :method => :simple,
124
+ :username => dn,
125
+ :password => password
126
+ },
127
+ :base => @ldap.base
128
+ } ).bind
129
+ end
130
+
131
+ # helper to concat the dn from the various parts
132
+ # @param dn_prefix String the prefix of the dn
133
+ # @param treebase the treebase of the dn or any search
134
+ # @return the complete dn String
135
+ def dn(dn_prefix, treebase)
136
+ "#{dn_prefix},#{treebase},#{@ldap.base}"
137
+ end
138
+
139
+ private
140
+
141
+ # helper to extract the Hash from the ldap search result
142
+ # @param Entry from the ldap_search
143
+ # @return Hash with name/value pairs of the entry
144
+ def to_map(field_names, entry)
145
+ fields = {:dn => :dn}
146
+ field_names.each { |f| fields[f.downcase.to_sym] = f.to_sym }
147
+ def entry.map
148
+ @myhash
149
+ end
150
+ result = {}
151
+ entry.map.each do |k,v|
152
+ result[fields[k]] = v
153
+ end
154
+ result
155
+ end
156
+
157
+ def ldap_error(method, dn)
158
+ "#{method} error: (#{@ldap.get_operation_result.code}) #{@ldap.get_operation_result.message}\n\tDN: #{dn}"
159
+ end
160
+ end
161
+ end