Class: ActiveLdap::Base

Inherits:
Object
  • Object
show all
Includes:
GetTextSupport, Enumerable, Reloadable::Deprecated, Reloadable::Subclasses
Defined in:
lib/active_ldap/base.rb

Overview

Base

Base is the primary class which contains all of the core ActiveLdap functionality. It is meant to only ever be subclassed by extension classes.

Direct Known Subclasses

Entry

Constant Summary collapse

VALID_LDAP_MAPPING_OPTIONS =
[:dn_attribute, :prefix, :scope,
:classes, :recommended_classes,
:excluded_classes, :sort_by, :order]
@@configurations =
{}

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GetTextSupport

included

Constructor Details

#initialize(attributes = nil) {|_self| ... } ⇒ Base

new

Creates a new instance of Base initializing all class and all initialization. Defines local defaults. See examples If multiple values exist for dn_attribute, the first one put here will be authoritative

Yields:

  • (_self)

Yield Parameters:



668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
# File 'lib/active_ldap/base.rb', line 668

def initialize(attributes=nil)
  init_base
  @new_entry = true
  initial_classes = required_classes | recommended_classes
  case attributes
  when nil
    self.classes = initial_classes
  when String, Array, DN
    self.classes = initial_classes
    self.dn = attributes
  when Hash
    attributes = attributes.clone
    classes = extract_object_class!(attributes)
    self.classes = classes | initial_classes
    self.attributes = attributes
  else
    format = _("'%s' must be either nil, DN value as ActiveLdap::DN, " \
               "String or Array or attributes as Hash")
    raise ArgumentError, format % attributes.inspect
  end
  yield self if block_given?
  run_callbacks :initialize unless _initialize_callbacks.empty?
end

Class Attribute Details

.abstract_classObject

Returns the value of attribute abstract_class.



511
512
513
# File 'lib/active_ldap/base.rb', line 511

def abstract_class
  @abstract_class
end

Class Method Details

.abstract_class?Boolean

Returns:

  • (Boolean)


512
513
514
# File 'lib/active_ldap/base.rb', line 512

def abstract_class?
  defined?(@abstract_class) && @abstract_class
end

.baseObject

Base.base

This method when included into Base provides an inheritable, overwritable configuration setting

This should be a string with the base of the ldap server such as ‘dc=example,dc=com’, and it should be overwritten by including configuration.rb into this class. When subclassing, the specified prefix will be concatenated.



439
440
441
# File 'lib/active_ldap/base.rb', line 439

def base
  @base ||= compute_base
end

.base=(value) ⇒ Object



444
445
446
447
# File 'lib/active_ldap/base.rb', line 444

def base=(value)
  self.inheritable_base = value
  @base = nil
end

.base_classObject



472
473
474
475
476
477
478
# File 'lib/active_ldap/base.rb', line 472

def base_class
  if self == Base or superclass == Base
    self
  else
    superclass.base_class
  end
end

.class_local_attr_accessor(search_ancestors, *syms) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/active_ldap/base.rb', line 303

def self.class_local_attr_accessor(search_ancestors, *syms)
  syms.flatten.each do |sym|
    class_eval(<<-EOS, __FILE__, __LINE__ + 1)
      def self.#{sym}(search_superclasses=#{search_ancestors})
        @#{sym} ||= nil
        return @#{sym} if @#{sym}
        if search_superclasses
          target = superclass
          value = nil
          loop do
            break nil unless target.respond_to?(:#{sym})
            value = target.#{sym}
            break if value
            target = target.superclass
          end
          value
        else
          nil
        end
      end
      def #{sym}; self.class.#{sym}; end
      def self.#{sym}=(value); @#{sym} = value; end
    EOS
  end
end

.class_of_active_ldap_descendant(klass) ⇒ Object



516
517
518
519
520
521
522
523
524
525
# File 'lib/active_ldap/base.rb', line 516

def class_of_active_ldap_descendant(klass)
  if klass.superclass == Base or klass.superclass.abstract_class?
    klass
  elsif klass.superclass.nil?
    raise Error, _("%s doesn't belong in a hierarchy descending " \
                   "from ActiveLdap") % (name || to_s)
  else
    class_of_active_ldap_descendant(klass.superclass)
  end
end

.create(attributes = nil, &block) ⇒ Object



395
396
397
398
399
400
401
402
403
# File 'lib/active_ldap/base.rb', line 395

def create(attributes=nil, &block)
  if attributes.is_a?(Array)
    attributes.collect {|attrs| create(attrs, &block)}
  else
    object = new(attributes, &block)
    object.save
    object
  end
end

.default_search_attributeObject



480
481
482
# File 'lib/active_ldap/base.rb', line 480

def default_search_attribute
  dn_attribute
end

.establish_connection(config = nil) ⇒ Object

establish_connection is deprecated since 1.1.0. Please use setup_connection() instead.



386
387
388
389
390
391
392
393
# File 'lib/active_ldap/base.rb', line 386

def establish_connection(config=nil)
  message =
    _("ActiveLdap::Base.establish_connection has been deprecated " \
      "since 1.1.0. " \
      "Please use ActiveLdap::Base.setup_connection instead.")
  ActiveSupport::Deprecation.warn(message)
  setup_connection(config)
end

.human_name(options = {}) ⇒ Object



538
539
540
541
542
543
544
545
546
547
548
549
# File 'lib/active_ldap/base.rb', line 538

def human_name(options={})
  defaults = self_and_descendants_from_active_ldap.collect do |klass|
    if klass.name.blank?
      nil
    else
      :"#{klass.name.underscore}"
    end
  end
  defaults << name.humanize
  defaults = defaults.compact
  defaults.first || name || to_s
end

.inherited(sub_class) ⇒ Object



338
339
340
341
342
343
# File 'lib/active_ldap/base.rb', line 338

def inherited(sub_class)
  super
  sub_class.module_eval do
    include GetTextSupport
  end
end

.inspectObject



484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# File 'lib/active_ldap/base.rb', line 484

def inspect
  if self == Base
    super
  elsif abstract_class?
    "#{super}(abstract)"
  else
    detail = nil
    begin
      must = []
      may = []
      class_names = classes.collect do |object_class|
        must.concat(object_class.must)
        may.concat(object_class.may)
        object_class.name
      end
      detail = ["objectClass:<#{class_names.join(', ')}>",
                "must:<#{inspect_attributes(must)}>",
                "may:<#{inspect_attributes(may)}>"].join(", ")
    rescue ActiveLdap::ConnectionNotSetup
      detail = "not-connected"
    rescue ActiveLdap::Error
      detail = "connection-failure"
    end
    "#{super}(#{detail})"
  end
end

.ldap_mapping(options = {}) ⇒ Object

This class function is used to setup all mappings between the subclass and ldap for use in activeldap

Example:

ldap_mapping :dn_attribute => 'uid', :prefix => 'ou=People',
             :classes => ['top', 'posixAccount'],
             :scope => :sub


412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/active_ldap/base.rb', line 412

def ldap_mapping(options={})
  options = options.symbolize_keys
  validate_ldap_mapping_options(options)

  self.dn_attribute = options[:dn_attribute] || default_dn_attribute
  self.dn_attribute = dn_attribute.to_s if dn_attribute.is_a?(Symbol)
  self.prefix = options[:prefix] || default_prefix
  self.scope = options[:scope]
  self.required_classes = options[:classes]
  self.recommended_classes = options[:recommended_classes]
  self.excluded_classes = options[:excluded_classes]
  self.sort_by = options[:sort_by]
  self.order = options[:order]

  public_class_method :new
end

.parsed_baseObject

Base.base

This method when included into Base provides an inheritable, overwritable configuration setting

This should be a string with the base of the ldap server such as ‘dc=example,dc=com’, and it should be overwritten by including configuration.rb into this class. When subclassing, the specified prefix will be concatenated. for backward compatibility



442
443
444
# File 'lib/active_ldap/base.rb', line 442

def base
  @base ||= compute_base
end

.prefixObject



449
450
451
# File 'lib/active_ldap/base.rb', line 449

def prefix
  @prefix ||= inheritable_prefix and DN.parse(inheritable_prefix)
end

.prefix=(value) ⇒ Object



453
454
455
456
457
# File 'lib/active_ldap/base.rb', line 453

def prefix=(value)
  self.inheritable_prefix = value
  @prefix = nil
  @base = nil
end

.scope=(scope) ⇒ Object



460
461
462
463
# File 'lib/active_ldap/base.rb', line 460

def scope=(scope)
  validate_scope(scope)
  self.scope_without_validation = scope
end

.scope_without_validation=Object



459
# File 'lib/active_ldap/base.rb', line 459

alias_method :scope_without_validation=, :scope=

.self_and_descendants_from_active_ldapObject



527
528
529
530
531
532
533
534
535
536
# File 'lib/active_ldap/base.rb', line 527

def self_and_descendants_from_active_ldap
  klass = self
  classes = [klass]
  while klass != klass.base_class
    classes << klass = klass.superclass
  end
  classes
rescue
  [self]
end

.setup_connection(config = nil) ⇒ Object

Set LDAP connection configuration up. It doesn’t connect and bind to LDAP server. A connection to LDAP server is created when it’s needed.

config

config must be a hash that may contain any of the following fields: :password_block, :logger, :host, :port, :base, :bind_dn, :try_sasl, :allow_anonymous :bind_dn specifies the DN to bind with. :password_block specifies a Proc object that will yield a String to

be used as the password when called.

:logger specifies a logger object (Logger, Log4r::Logger and s on) :host sets the LDAP server hostname :port sets the LDAP server port :base overwrites Base.base - this affects EVERYTHING :try_sasl indicates that a SASL bind should be attempted when binding

to the server (default: false)

:sasl_mechanisms is an array of SASL mechanism to try

(default: ["GSSAPI", "CRAM-MD5", "EXTERNAL"])

:allow_anonymous indicates that a true anonymous bind is allowed when

trying to bind to the server (default: true)

:retries - indicates the number of attempts to reconnect that will be

undertaken when a stale connection occurs. -1 means infinite.

:sasl_quiet - if true, sets @sasl_quiet on the Ruby/LDAP connection :method - whether to use :ssl, :tls, or :plain (unencrypted) :retry_wait - seconds to wait before retrying a connection :scope - dictates how to find objects. ONELEVEL by default to

avoid dn_attr collisions across OUs. Think before changing.

:timeout - time in seconds - defaults to disabled. This CAN interrupt

search() requests. Be warned.

:retry_on_timeout - whether to reconnect when timeouts occur. Defaults

to true

See lib/active_ldap/configuration.rb for defaults for each option



378
379
380
381
382
# File 'lib/active_ldap/base.rb', line 378

def setup_connection(config=nil)
  super
  ensure_logger
  nil
end

.validate_scope(scope) ⇒ Object

Raises:



465
466
467
468
469
470
# File 'lib/active_ldap/base.rb', line 465

def validate_scope(scope)
  scope = scope.to_sym if scope.is_a?(String)
  return if scope.nil? or scope.is_a?(Symbol)
  raise ConfigurationError,
          _("scope '%s' must be a Symbol") % scope.inspect
end

Instance Method Details

#==(comparison_object) ⇒ Object

Returns true if the comparison_object is the same object, or is of the same type and has the same dn.



694
695
696
697
698
699
# File 'lib/active_ldap/base.rb', line 694

def ==(comparison_object)
  comparison_object.equal?(self) or
    (comparison_object.instance_of?(self.class) and
     comparison_object.dn == dn and
     !comparison_object.new_entry?)
end

#[](name, force_array = false) ⇒ Object



881
882
883
884
885
886
887
# File 'lib/active_ldap/base.rb', line 881

def [](name, force_array=false)
  if name == "dn"
    array_of(dn, force_array)
  else
    get_attribute(name, force_array)
  end
end

#[]=(name, value) ⇒ Object



889
890
891
# File 'lib/active_ldap/base.rb', line 889

def []=(name, value)
  set_attribute(name, value)
end

#assign_attributes(new_attributes) ⇒ Object



827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
# File 'lib/active_ldap/base.rb', line 827

def assign_attributes(new_attributes)
  return if new_attributes.blank?

  _schema = _local_entry_attribute = nil
  targets = sanitize_for_mass_assignment(new_attributes)
  targets.each do |key, value|
    setter = "#{key}="
    unless respond_to?(setter)
      _schema ||= schema
      attribute = _schema.attribute(key)
      next if attribute.id.nil?
      _local_entry_attribute ||= local_entry_attribute
      _local_entry_attribute.register(attribute)
    end
    send(setter, value)
  end
end

#attribute_names(normalize = false) ⇒ Object

attributes

Return attribute methods so that a program can determine available attributes dynamically without schema awareness



736
737
738
# File 'lib/active_ldap/base.rb', line 736

def attribute_names(normalize=false)
  entry_attribute.names(normalize)
end

#attribute_present?(name) ⇒ Boolean

Returns:

  • (Boolean)


740
741
742
743
# File 'lib/active_ldap/base.rb', line 740

def attribute_present?(name)
  values = get_attribute(name, true)
  !values.empty? or values.any? {|x| !(x and x.empty?)}
end

#attributesObject

This returns the key value pairs in @data with all values cloned



811
812
813
814
# File 'lib/active_ldap/base.rb', line 811

def attributes
  @simplified_data ||= simplify_data(@data)
  @simplified_data.clone
end

#attributes=(new_attributes) ⇒ Object

This allows a bulk update to the attributes of a record without forcing an immediate save or validation.

It is unwise to attempt objectClass updates this way. Also be sure to only pass in key-value pairs of your choosing. Do not let URL/form hackers supply the keys.



822
823
824
825
# File 'lib/active_ldap/base.rb', line 822

def attributes=(new_attributes)
  return if new_attributes.blank?
  assign_attributes(new_attributes)
end

#baseObject



947
948
949
# File 'lib/active_ldap/base.rb', line 947

def base
  @base ||= compute_base
end

#base=(object_local_base) ⇒ Object



951
952
953
954
955
956
# File 'lib/active_ldap/base.rb', line 951

def base=(object_local_base)
  ensure_update_dn
  @dn = nil
  @base = nil
  @base_value = object_local_base
end

#bind(config_or_password = {}, config_or_ignore = nil, &block) ⇒ Object



893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
# File 'lib/active_ldap/base.rb', line 893

def bind(config_or_password={}, config_or_ignore=nil, &block)
  if config_or_password.is_a?(String)
    config = (config_or_ignore || {}).merge(:password => config_or_password)
  else
    config = config_or_password
  end
  config = {:bind_dn => dn, :allow_anonymous => false}.merge(config)
  config[:password_block] ||= block if block_given?
  setup_connection(config)

  before_connection = @connection
  begin
    @connection = nil
    connection.connect
    @connection = connection
    clear_connection_based_cache
    clear_association_cache
  rescue ActiveLdap::Error
    remove_connection
    @connection = before_connection
    raise
  end
  true
end

#clear_connection_based_cacheObject



918
919
920
921
922
# File 'lib/active_ldap/base.rb', line 918

def clear_connection_based_cache
  @schema = nil
  @local_entry_attribute = nil
  clear_object_class_based_cache
end

#clear_object_class_based_cacheObject



924
925
926
927
928
929
930
# File 'lib/active_ldap/base.rb', line 924

def clear_object_class_based_cache
  @entry_attribute = nil
  @real_names = {}
  @changed_attributes.reject! do |key, _|
    not attribute_method?(key)
  end
end

#clear_removed_attributes_data(removed_attributes) ⇒ Object



932
933
934
935
936
937
938
939
940
941
# File 'lib/active_ldap/base.rb', line 932

def clear_removed_attributes_data(removed_attributes)
  return if removed_attributes.empty?
  removed_entry_attribute = EntryAttribute.new(nil, [])
  removed_attributes.each do |attribute|
    removed_entry_attribute.register(attribute)
  end
  @data.reject! do |key, _|
    removed_entry_attribute.exist?(key)
  end
end

#default_search_attributeObject



787
788
789
# File 'lib/active_ldap/base.rb', line 787

def default_search_attribute
  self.class.default_search_attribute
end

#delete_all(options = {}) ⇒ Object



968
969
970
# File 'lib/active_ldap/base.rb', line 968

def delete_all(options={})
  super({:base => dn}.merge(options || {}))
end

#destroy_all(options = {}) ⇒ Object



972
973
974
# File 'lib/active_ldap/base.rb', line 972

def destroy_all(options={})
  super({:base => dn}.merge(options || {}))
end

#dnObject

dn

Return the authoritative dn



756
757
758
# File 'lib/active_ldap/base.rb', line 756

def dn
  @dn ||= compute_dn
end

#dn=(value) ⇒ Object Also known as: id=



775
776
777
# File 'lib/active_ldap/base.rb', line 775

def dn=(value)
  set_attribute(dn_attribute_with_fallback, value)
end

#dn_attributeObject



781
782
783
784
785
# File 'lib/active_ldap/base.rb', line 781

def dn_attribute
  ensure_update_dn
  _dn_attribute = @dn_attribute || dn_attribute_of_class
  to_real_attribute_name(_dn_attribute) || _dn_attribute
end

#dn_attribute_of_classObject



780
# File 'lib/active_ldap/base.rb', line 780

alias_method(:dn_attribute_of_class, :dn_attribute)

#eql?(comparison_object) ⇒ Boolean

Delegates to ==

Returns:

  • (Boolean)


702
703
704
# File 'lib/active_ldap/base.rb', line 702

def eql?(comparison_object)
  self == (comparison_object)
end

#exist?Boolean Also known as: exists?

exist?

Return whether the entry exists in LDAP or not

Returns:

  • (Boolean)


748
749
750
# File 'lib/active_ldap/base.rb', line 748

def exist?
  self.class.exists?(dn)
end

#hashObject

Delegates to id in order to allow two records of the same type and id to work with something like:

[ User.find("a"), User.find("b"), User.find("c") ] &
  [ User.find("a"), User.find("d") ] # => [ User.find("a") ]


710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/active_ldap/base.rb', line 710

def hash
  return super if @_hashing # workaround for GetText :<
  _dn = nil
  begin
    @_hashing = true
    _dn = dn
  rescue DistinguishedNameInvalid, DistinguishedNameNotSetError
    return super
  ensure
    @_hashing = false
  end
  _dn.hash
end

#have_attribute?(name, except = []) ⇒ Boolean Also known as: has_attribute?

Returns:

  • (Boolean)


875
876
877
878
# File 'lib/active_ldap/base.rb', line 875

def have_attribute?(name, except=[])
  real_name = to_real_attribute_name(name)
  !real_name.nil? and !except.include?(real_name)
end

#idObject



760
761
762
# File 'lib/active_ldap/base.rb', line 760

def id
  get_attribute(dn_attribute_with_fallback)
end

#inspectObject



976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
# File 'lib/active_ldap/base.rb', line 976

def inspect
  object_classes = entry_attribute.object_classes
  inspected_object_classes = object_classes.collect do |object_class|
    object_class.name
  end.join(', ')
  must_attributes = must.collect(&:name).sort.join(', ')
  may_attributes = may.collect(&:name).sort.join(', ')
  inspected_attributes = attribute_names.sort.collect do |name|
    inspect_attribute(name)
  end.join(', ')
  result = "\#<#{self.class} objectClass:<#{inspected_object_classes}>, "
  result << "must:<#{must_attributes}>, may:<#{may_attributes}>, "
  result << "#{inspected_attributes}>"
  result
end

#mayObject



724
725
726
# File 'lib/active_ldap/base.rb', line 724

def may
  entry_attribute.may
end

#mustObject



728
729
730
# File 'lib/active_ldap/base.rb', line 728

def must
  entry_attribute.must
end

#schemaObject



943
944
945
# File 'lib/active_ldap/base.rb', line 943

def schema
  @schema ||= super
end

#scopeObject



959
960
961
# File 'lib/active_ldap/base.rb', line 959

def scope
  @scope || scope_of_class
end

#scope=(scope) ⇒ Object



963
964
965
966
# File 'lib/active_ldap/base.rb', line 963

def scope=(scope)
  self.class.validate_scope(scope)
  @scope = scope
end

#scope_of_classObject



958
# File 'lib/active_ldap/base.rb', line 958

alias_method :scope_of_class, :scope

#to_keyObject

Returns this entity’s dn wrapped in an Array or nil if the entity’ s dn is not set.



769
770
771
772
773
# File 'lib/active_ldap/base.rb', line 769

def to_key
  [dn]
rescue DistinguishedNameNotSetError
  nil
end

#to_ldifObject



849
850
851
# File 'lib/active_ldap/base.rb', line 849

def to_ldif
  Ldif.new([to_ldif_record]).to_s
end

#to_ldif_recordObject



845
846
847
# File 'lib/active_ldap/base.rb', line 845

def to_ldif_record
  super(dn, normalize_data(@data))
end

#to_paramObject



764
765
766
# File 'lib/active_ldap/base.rb', line 764

def to_param
  id
end

#to_sObject



871
872
873
# File 'lib/active_ldap/base.rb', line 871

def to_s
  to_ldif
end

#to_xml(options = {}) ⇒ Object



853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# File 'lib/active_ldap/base.rb', line 853

def to_xml(options={})
  options = options.dup
  options[:root] ||= (self.class.name || '').underscore
  options[:root] = 'anonymous' if options[:root].blank?
  [:only, :except].each do |attribute_names_key|
    names = options[attribute_names_key]
    next if names.nil?
    options[attribute_names_key] = names.collect do |name|
      if name.to_s.downcase == "dn"
        "dn"
      else
        to_real_attribute_name(name)
      end
    end.compact
  end
  XML.new(dn, normalize_data(@data), schema).to_s(options)
end

#update_attribute(name, value) ⇒ Object

Updates a given attribute and saves immediately



792
793
794
795
# File 'lib/active_ldap/base.rb', line 792

def update_attribute(name, value)
  send("#{name}=", value)
  save
end

#update_attributes(attrs) ⇒ Object

This performs a bulk update of attributes and immediately calls #save.



799
800
801
802
# File 'lib/active_ldap/base.rb', line 799

def update_attributes(attrs)
  self.attributes = attrs
  save
end

#update_attributes!(attrs) ⇒ Object



804
805
806
807
# File 'lib/active_ldap/base.rb', line 804

def update_attributes!(attrs)
  self.attributes = attrs
  save!
end