Class: ActiveLdap::Adapter::Base — activeldap - ActiveLdap

Class: ActiveLdap::Adapter::Base

Inherits:
Object
  • Object
show all
Includes:
GetTextSupport
Defined in:
lib/active_ldap/adapter/base.rb,
lib/active_ldap/adapter/jndi.rb,
lib/active_ldap/adapter/ldap.rb,
lib/active_ldap/adapter/net_ldap.rb

Direct Known Subclasses

Jndi, Ldap, NetLdap

Constant Summary

VALID_ADAPTER_CONFIGURATION_KEYS =
[
  :host,
  :port,
  :method,
  :timeout,
  :retry_on_timeout,
  :retry_limit,
  :retry_wait,
  :bind_dn,
  :password,
  :password_block,
  :try_sasl,
  :sasl_mechanisms,
  :sasl_quiet,
  :allow_anonymous,
  :store_password,
  :scope,
  :sasl_options,
  :follow_referrals,
]
@@row_even =
true

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Base) initialize(configuration = {})

Returns a new instance of Base



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/active_ldap/adapter/base.rb', line 34

def initialize(configuration={})
  @connection = nil
  @disconnected = false
  @bound = false
  @bind_tried = false
  @entry_attributes = {}
  @follow_referrals = nil
  @configuration = configuration.dup
  @logger = @configuration.delete(:logger)
  @configuration.assert_valid_keys(VALID_ADAPTER_CONFIGURATION_KEYS)
  VALID_ADAPTER_CONFIGURATION_KEYS.each do |name|
    instance_variable_set("@#{name}", configuration[name])
  end
  @follow_referrals = true if @follow_referrals.nil?
  @instrumenter = ActiveSupport::Notifications.instrumenter
end

Class Method Details

+ (Object) jndi_connection(options)



7
8
9
10
# File 'lib/active_ldap/adapter/jndi.rb', line 7

def jndi_connection(options)
  require 'active_ldap/adapter/jndi_connection'
  Jndi.new(options)
end

+ (Object) ldap_connection(options)



7
8
9
10
# File 'lib/active_ldap/adapter/ldap.rb', line 7

def ldap_connection(options)
  require 'active_ldap/adapter/ldap_ext'
  Ldap.new(options)
end

+ (Object) net_ldap_connection(options)



9
10
11
12
# File 'lib/active_ldap/adapter/net_ldap.rb', line 9

def net_ldap_connection(options)
  require 'active_ldap/adapter/net_ldap_ext'
  NetLdap.new(options)
end

Instance Method Details

- (Object) add(dn, entries, options = {})



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/active_ldap/adapter/base.rb', line 210

def add(dn, entries, options={})
  dn = ensure_dn_string(dn)
  begin
    operation(options) do
      yield(dn, entries)
    end
  rescue LdapError::NoSuchObject
    raise EntryNotFound, _("No such entry: %s") % dn
  rescue LdapError::InvalidDnSyntax
    raise DistinguishedNameInvalid.new(dn)
  rescue LdapError::AlreadyExists
    raise EntryAlreadyExist, _("%s: %s") % [$!.message, dn]
  rescue LdapError::StrongAuthRequired
    raise StrongAuthenticationRequired, _("%s: %s") % [$!.message, dn]
  rescue LdapError::ObjectClassViolation
    raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn]
  rescue LdapError::UnwillingToPerform
    raise OperationNotPermitted, _("%s: %s") % [$!.message, dn]
  end
end

- (Object) bind(options = {})



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/active_ldap/adapter/base.rb', line 75

def bind(options={})
  @bind_tried = true

  bind_dn = ensure_dn_string(options[:bind_dn] || @bind_dn)
  try_sasl = options.has_key?(:try_sasl) ? options[:try_sasl] : @try_sasl
  if options.has_key?(:allow_anonymous)
    allow_anonymous = options[:allow_anonymous]
  else
    allow_anonymous = @allow_anonymous
  end
  options = options.merge(:allow_anonymous => allow_anonymous)

  # Rough bind loop:
  # Attempt 1: SASL if available
  # Attempt 2: SIMPLE with credentials if password block
  # Attempt 3: SIMPLE ANONYMOUS if 1 and 2 fail (or pwblock returns '')
  if try_sasl and sasl_bind(bind_dn, options)
    @logger.info {_('Bound to %s by SASL as %s') % [target, bind_dn]}
  elsif simple_bind(bind_dn, options)
    @logger.info {_('Bound to %s by simple as %s') % [target, bind_dn]}
  elsif allow_anonymous and bind_as_anonymous(options)
    @logger.info {_('Bound to %s as anonymous') % target}
  else
    message = yield if block_given?
    message ||= _('All authentication methods for %s exhausted.') % target
    raise AuthenticationError, message
  end

  @bound = true
  @bound
end

- (Object) bind_as_anonymous(options = {})



112
113
114
# File 'lib/active_ldap/adapter/base.rb', line 112

def bind_as_anonymous(options={})
  yield
end

- (Boolean) bound?

Returns:

  • (Boolean)


120
121
122
# File 'lib/active_ldap/adapter/base.rb', line 120

def bound?
  connecting? and @bound
end

- (Object) connect(options = {})



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/active_ldap/adapter/base.rb', line 51

def connect(options={})
  host = options[:host] || @host
  method = options[:method] || @method || :plain
  port = options[:port] || @port || ensure_port(method)
  method = ensure_method(method)
  @disconnected = false
  @bound = false
  @bind_tried = false
  @connection, @uri, @with_start_tls = yield(host, port, method)
  prepare_connection(options)
  bind(options)
end

- (Boolean) connecting?

Returns:

  • (Boolean)


116
117
118
# File 'lib/active_ldap/adapter/base.rb', line 116

def connecting?
  !@connection.nil? and !@disconnected
end

- (Object) delete(targets, options = {})



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/active_ldap/adapter/base.rb', line 191

def delete(targets, options={})
  targets = [targets] unless targets.is_a?(Array)
  return if targets.empty?
  begin
    operation(options) do
      targets.each do |target|
        target = ensure_dn_string(target)
        begin
          yield(target)
        rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess
          raise OperationNotPermitted, _("%s: %s") % [$!.message, target]
        end
      end
    end
  rescue LdapError::NoSuchObject
    raise EntryNotFound, _("No such entry: %s") % target
  end
end

- (Object) disconnect!(options = {})



64
65
66
67
68
# File 'lib/active_ldap/adapter/base.rb', line 64

def disconnect!(options={})
  unbind(options)
  @connection = @uri = @with_start_tls = nil
  @disconnected = true
end

- (Object) entry_attribute(object_classes)



163
164
165
166
# File 'lib/active_ldap/adapter/base.rb', line 163

def entry_attribute(object_classes)
  @entry_attributes[object_classes.uniq.sort] ||=
    EntryAttribute.new(schema, object_classes)
end

- (Object) modify(dn, entries, options = {})



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/active_ldap/adapter/base.rb', line 231

def modify(dn, entries, options={})
  dn = ensure_dn_string(dn)
  begin
    operation(options) do
      begin
        yield(dn, entries)
      rescue LdapError::UnwillingToPerform, LdapError::InsufficientAccess
        raise OperationNotPermitted, _("%s: %s") % [$!.message, target]
      end
    end
  rescue LdapError::UndefinedType
    raise
  rescue LdapError::ObjectClassViolation
    raise RequiredAttributeMissed, _("%s: %s") % [$!.message, dn]
  end
end

- (Object) modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options = {})



248
249
250
251
252
253
# File 'lib/active_ldap/adapter/base.rb', line 248

def modify_rdn(dn, new_rdn, delete_old_rdn, new_superior, options={})
  dn = ensure_dn_string(dn)
  operation(options) do
    yield(dn, new_rdn, delete_old_rdn, new_superior)
  end
end

- (Object) naming_contexts



154
155
156
# File 'lib/active_ldap/adapter/base.rb', line 154

def naming_contexts
  root_dse_values('namingContexts')
end

- (Object) rebind(options = {})



70
71
72
73
# File 'lib/active_ldap/adapter/base.rb', line 70

def rebind(options={})
  unbind(options) if bound?
  connect(options)
end

- (Object) schema(options = {})



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/active_ldap/adapter/base.rb', line 124

def schema(options={})
  @schema ||= operation(options) do
    base = options[:base]
    attrs = options[:attributes]

    attrs ||= [
      'objectClasses',
      'attributeTypes',
      'matchingRules',
      'matchingRuleUse',
      'dITStructureRules',
      'dITContentRules',
      'nameForms',
      'ldapSyntaxes',
      #'extendedAttributeInfo', # if we need RANGE-LOWER/UPPER.
    ]
    base ||= root_dse_values('subschemaSubentry', options)[0]
    base ||= 'cn=schema'
    schema = nil
    search(:base => base,
           :scope => :base,
           :filter => '(objectClass=subschema)',
           :attributes => attrs,
           :limit => 1) do |dn, attributes|
      schema = Schema.new(attributes)
    end
    schema || Schema.new([])
  end
end

- (Object) search(options = {})



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/active_ldap/adapter/base.rb', line 168

def search(options={})
  filter = parse_filter(options[:filter]) || 'objectClass=*'
  attrs = options[:attributes] || []
  scope = ensure_scope(options[:scope] || @scope)
  base = options[:base]
  limit = options[:limit] || 0
  limit = nil if limit <= 0

  attrs = attrs.to_a # just in case
  base = ensure_dn_string(base)
  begin
    operation(options) do
      yield(base, scope, filter, attrs, limit)
    end
  rescue LdapError::NoSuchObject, LdapError::InvalidDnSyntax
    # Do nothing on failure
    @logger.info do
      args = [$!.class, $!.message, filter, attrs.inspect]
      _("Ignore error %s(%s): filter %s: attributes: %s") % args
    end
  end
end

- (Object) supported_control



158
159
160
161
# File 'lib/active_ldap/adapter/base.rb', line 158

def supported_control
  @supported_control ||=
    SupportedControl.new(root_dse_values("supportedControl"))
end

- (Object) unbind(options = {})



107
108
109
110
# File 'lib/active_ldap/adapter/base.rb', line 107

def unbind(options={})
  yield if @connection and (@bind_tried or bound?)
  @bind_tried = @bound = false
end