Class ActiveLdap::Base
In: lib/active_ldap/base.rb
Parent: Object
Error DeleteError LdapError AdapterNotSpecified OperationNotPermitted RequiredAttributeMissed LdifInvalid AttributeAssignmentError RequiredObjectClassMissed DistinguishedNameNotSetError StrongAuthenticationRequired ConnectionError SaveError EntryNotFound AuthenticationError EntryNotSaved UnknownAttribute ConnectionNotEstablished TimeoutError ConfigurationError AdapterNotFound DistinguishedNameInvalid ObjectClassError EntryInvalid EntryAlreadyExist Base DistinguishedName Ldif Reloadable::Deprecated Reloadable::Subclasses Enumerable Collection StandardError Children HasMany HasManyWrap BelongsToMany Proxy BelongsTo Common Find LDIF Delete Update GetText Parser GetTextSupport Base\n[lib/active_ldap/adapter/base.rb\nlib/active_ldap/adapter/ldap.rb\nlib/active_ldap/adapter/net_ldap.rb] Ldap NetLdap Normalize ActiveRecord::Callbacks ActiveRecord::Validations Schema\n[lib/active_ldap/schema.rb\nlib/active_ldap/schema/syntaxes.rb] lib/active_ldap/base.rb lib/active_ldap/schema.rb lib/active_ldap/ldif.rb lib/active_ldap/distinguished_name.rb lib/active_ldap/ldap_error.rb ClassMethods Associations ClassMethods HumanReadable lib/active_ldap/association/has_many_wrap.rb lib/active_ldap/association/has_many.rb lib/active_ldap/association/proxy.rb lib/active_ldap/association/children.rb lib/active_ldap/association/collection.rb lib/active_ldap/association/belongs_to_many.rb lib/active_ldap/association/belongs_to.rb HasManyUtils Association ClassMethods Tree Acts Common LDIF Delete Find Update Operations lib/active_ldap/get_text/parser.rb GetText ClassMethods Configuration Command lib/active_ldap/adapter/net_ldap.rb lib/active_ldap/adapter/ldap.rb Adapter GetTextSupport Normalize ClassMethods Attributes Escape Callbacks ClassMethods ObjectClass Helper Validations ClassMethods Connection GetTextFallback Populate Salt UserPassword ActiveLdap dot/m_40_0.png

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.

Methods

Included Modules

GetTextSupport Reloadable::Deprecated Reloadable::Subclasses Enumerable

Constants

VALID_LDAP_MAPPING_OPTIONS = [:dn_attribute, :prefix, :scope, :classes, :recommended_classes, :sort_by, :order]

External Aliases

base -> base_inheritable
scope= -> scope_without_validation=
dn_attribute -> dn_attribute_of_class
respond_to? -> respond_to_without_attributes?
base -> base_of_class
scope -> scope_of_class

Public Class methods

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.

[Source]

     # File lib/active_ldap/base.rb, line 318
318:       def base
319:         _base = base_inheritable
320:         _base = configuration[:base] if _base.nil? and configuration
321:         _base ||= base_inheritable(true)
322:         [prefix, _base].find_all do |component|
323:           !component.blank?
324:         end.join(",")
325:       end

[Source]

     # File lib/active_ldap/base.rb, line 340
340:       def base_class
341:         if self == Base or superclass == Base
342:           self
343:         else
344:           superclass.base_class
345:         end
346:       end

[Source]

     # File lib/active_ldap/base.rb, line 201
201:     def self.class_local_attr_accessor(search_ancestors, *syms)
202:       syms.flatten.each do |sym|
203:         class_eval("def self.\#{sym}(search_superclasses=\#{search_ancestors})\n@\#{sym} ||= nil\nreturn @\#{sym} if @\#{sym}\nif search_superclasses\ntarget = superclass\nvalue = nil\nloop do\nbreak nil unless target.respond_to?(:\#{sym})\nvalue = target.\#{sym}\nbreak if value\ntarget = target.superclass\nend\nvalue\nelse\nnil\nend\nend\ndef \#{sym}; self.class.\#{sym}; end\ndef self.\#{sym}=(value); @\#{sym} = value; end\ndef \#{sym}=(value); self.class.\#{sym} = value; end\n", __FILE__, __LINE__ + 1)
204:       end
205:     end

[Source]

     # File lib/active_ldap/base.rb, line 275
275:       def create(attributes=nil, &block)
276:         if attributes.is_a?(Array)
277:           attributes.collect {|attrs| create(attrs, &block)}
278:         else
279:           object = new(attributes, &block)
280:           object.save
281:           object
282:         end
283:       end

[Source]

     # File lib/active_ldap/base.rb, line 348
348:       def default_search_attribute
349:         dn_attribute
350:       end

Connect and bind to LDAP creating a class variable for use by all ActiveLdap objects.

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/configuration.rb for defaults for each option

[Source]

     # File lib/active_ldap/base.rb, line 269
269:       def establish_connection(config=nil)
270:         super
271:         ensure_logger
272:         nil
273:       end

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

[Source]

     # File lib/active_ldap/base.rb, line 292
292:       def ldap_mapping(options={})
293:         options = options.symbolize_keys
294:         validate_ldap_mapping_options(options)
295: 
296:         self.dn_attribute = options[:dn_attribute] || default_dn_attribute
297:         self.prefix = options[:prefix] || default_prefix
298:         self.scope = options[:scope]
299:         self.required_classes = options[:classes]
300:         self.recommended_classes = options[:recommended_classes]
301:         self.sort_by = options[:sort_by]
302:         self.order = options[:order]
303: 
304:         public_class_method :new
305:       end

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

[Source]

     # File lib/active_ldap/base.rb, line 424
424:     def initialize(attributes=nil)
425:       init_base
426:       @new_entry = true
427:       initial_classes = required_classes | recommended_classes
428:       if attributes.nil?
429:         apply_object_class(initial_classes)
430:       elsif attributes.is_a?(String) or attributes.is_a?(Array)
431:         apply_object_class(initial_classes)
432:         self.dn = attributes
433:       elsif attributes.is_a?(Hash)
434:         classes, attributes = extract_object_class(attributes)
435:         apply_object_class(classes | initial_classes)
436:         normalized_attributes = {}
437:         attributes.each do |key, value|
438:           real_key = to_real_attribute_name(key) || key
439:           normalized_attributes[real_key] = value
440:         end
441:         self.dn = normalized_attributes[dn_attribute]
442:         self.attributes = normalized_attributes
443:       else
444:         message = _("'%s' must be either nil, DN value as String or Array " \
445:                     "or attributes as Hash") % attributes.inspect
446:         raise ArgumentError, message
447:       end
448:       yield self if block_given?
449:       assert_dn_attribute
450:     end

[Source]

     # File lib/active_ldap/base.rb, line 328
328:       def scope=(scope)
329:         validate_scope(scope)
330:         self.scope_without_validation = scope
331:       end

[Source]

     # File lib/active_ldap/base.rb, line 333
333:       def validate_scope(scope)
334:         scope = scope.to_sym if scope.is_a?(String)
335:         return if scope.nil? or scope.is_a?(Symbol)
336:         raise ConfigurationError,
337:                 _("scope '%s' must be a Symbol") % scope.inspect
338:       end

Private Class methods

[Source]

     # File lib/active_ldap/base.rb, line 389
389:       def default_dn_attribute
390:         if name.empty?
391:           dn_attribute = nil
392:           parent_class = ancestors[1]
393:           if parent_class.respond_to?(:dn_attribute)
394:             dn_attribute = parent_class.dn_attribute
395:           end
396:           dn_attribute || "cn"
397:         else
398:           Inflector.underscore(Inflector.demodulize(name))
399:         end
400:       end

[Source]

     # File lib/active_ldap/base.rb, line 402
402:       def default_prefix
403:         if name.empty?
404:           nil
405:         else
406:           "ou=#{Inflector.pluralize(Inflector.demodulize(name))}"
407:         end
408:       end

[Source]

     # File lib/active_ldap/base.rb, line 357
357:       def ensure_logger
358:         @@logger ||= configuration[:logger]
359:         # Setup default logger to console
360:         if @@logger.nil?
361:           require 'logger'
362:           @@logger = Logger.new(STDERR)
363:           @@logger.progname = 'ActiveLdap'
364:           @@logger.level = Logger::UNKNOWN
365:         end
366:         configuration[:logger] ||= @@logger
367:       end

[Source]

     # File lib/active_ldap/base.rb, line 369
369:       def instantiate(args)
370:         dn, attributes, options = args
371:         options ||= {}
372:         if self.class == Class
373:           klass = self.ancestors[0].to_s.split(':').last
374:           real_klass = self.ancestors[0]
375:         else
376:           klass = self.class.to_s.split(':').last
377:           real_klass = self.class
378:         end
379: 
380:         obj = real_klass.allocate
381:         conn = options[:connection] || connection
382:         obj.connection = conn if conn != connection
383:         obj.instance_eval do
384:           initialize_by_ldap_data(dn, attributes)
385:         end
386:         obj
387:       end

[Source]

     # File lib/active_ldap/base.rb, line 353
353:       def validate_ldap_mapping_options(options)
354:         options.assert_valid_keys(VALID_LDAP_MAPPING_OPTIONS)
355:       end

Public Instance methods

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

[Source]

     # File lib/active_ldap/base.rb, line 454
454:     def ==(comparison_object)
455:       comparison_object.equal?(self) or
456:         (comparison_object.instance_of?(self.class) and
457:          comparison_object.dn == dn and
458:          !comparison_object.new_entry?)
459:     end

[Source]

     # File lib/active_ldap/base.rb, line 745
745:     def [](name, force_array=false)
746:       if name == "dn"
747:         array_of(dn, force_array)
748:       else
749:         get_attribute(name, force_array)
750:       end
751:     end

[Source]

     # File lib/active_ldap/base.rb, line 753
753:     def []=(name, value)
754:       set_attribute(name, value)
755:     end

attributes

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

[Source]

     # File lib/active_ldap/base.rb, line 488
488:     def attribute_names(normalize=false)
489:       ensure_apply_object_class
490:       names = @attribute_names.keys
491:       if normalize
492:         names.collect do |name|
493:           to_real_attribute_name(name)
494:         end.uniq
495:       else
496:         names
497:       end
498:     end

[Source]

     # File lib/active_ldap/base.rb, line 500
500:     def attribute_present?(name)
501:       values = get_attribute(name, true)
502:       !values.empty? or values.any? {|x| not (x and x.empty?)}
503:     end

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

[Source]

     # File lib/active_ldap/base.rb, line 669
669:     def attributes
670:       Marshal.load(Marshal.dump(@data))
671:     end

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.

[Source]

     # File lib/active_ldap/base.rb, line 679
679:     def attributes=(new_attributes)
680:       return if new_attributes.nil?
681:       _schema = nil
682:       targets = remove_attributes_protected_from_mass_assignment(new_attributes)
683:       targets.each do |key, value|
684:         setter = "#{key}="
685:         unless respond_to?(setter)
686:           _schema ||= schema
687:           attribute = _schema.attribute(key)
688:           next if attribute.id.nil?
689:           define_attribute_methods(attribute)
690:         end
691:         send(setter, value)
692:       end
693:     end

[Source]

     # File lib/active_ldap/base.rb, line 795
795:     def base
796:       [@base, base_of_class].compact.join(",")
797:     end

[Source]

     # File lib/active_ldap/base.rb, line 800
800:     def base=(object_local_base)
801:       @base = object_local_base
802:     end

[Source]

     # File lib/active_ldap/base.rb, line 763
763:     def bind(config_or_password={}, &block)
764:       if config_or_password.is_a?(String)
765:         config = {:password => config_or_password}
766:       elsif config_or_password.respond_to?(:call)
767:         config = {:password_block => config_or_password}
768:       else
769:         config = config_or_password
770:       end
771:       config = {:bind_dn => dn, :allow_anonymous => false}.merge(config)
772:       config[:password_block] ||= block if block_given?
773:       establish_connection(config)
774: 
775:       before_connection = @connection
776:       begin
777:         @connection = nil
778:         connection.connect
779:         @connection = connection
780:         @schema = nil
781:         clear_association_cache
782:       rescue ActiveLdap::Error
783:         remove_connection
784:         @connection = before_connection
785:         raise
786:       end
787:       true
788:     end

[Source]

     # File lib/active_ldap/base.rb, line 554
554:     def default_search_attribute
555:       self.class.default_search_attribute
556:     end

[Source]

     # File lib/active_ldap/base.rb, line 570
570:     def delete(options={})
571:       super(dn, options)
572:     end

destroy

Delete this entry from LDAP

[Source]

     # File lib/active_ldap/base.rb, line 561
561:     def destroy
562:       begin
563:         self.class.delete(dn)
564:         @new_entry = true
565:       rescue Error
566:         raise DeleteError.new(_("Failed to delete LDAP entry: %s") % dn)
567:       end
568:     end

dn

Return the authoritative dn

[Source]

     # File lib/active_ldap/base.rb, line 523
523:     def dn
524:       return base if @dn_is_base
525: 
526:       dn_value = id
527:       if dn_value.nil?
528:         raise DistinguishedNameNotSetError.new,
529:                 _("%s's DN attribute (%s) isn't set") % [self, dn_attribute]
530:       end
531:       _base = base
532:       _base = nil if _base.empty?
533:       ["#{dn_attribute}=#{dn_value}", _base].compact.join(",")
534:     end

[Source]

     # File lib/active_ldap/base.rb, line 544
544:     def dn=(value)
545:       set_attribute(dn_attribute, value)
546:     end

[Source]

     # File lib/active_ldap/base.rb, line 550
550:     def dn_attribute
551:       @dn_attribute || dn_attribute_of_class
552:     end

[Source]

     # File lib/active_ldap/base.rb, line 757
757:     def each
758:       @data.each do |key, values|
759:         yield(key.dup, values.dup)
760:       end
761:     end

Delegates to ==

[Source]

     # File lib/active_ldap/base.rb, line 462
462:     def eql?(comparison_object)
463:       self == (comparison_object)
464:     end

exist?

Return whether the entry exists in LDAP or not

[Source]

     # File lib/active_ldap/base.rb, line 508
508:     def exist?
509:       self.class.exists?(dn)
510:     end
exists?()

Alias for exist?

has_attribute?(name, except=[])

Alias for have_attribute?

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") ]

[Source]

     # File lib/active_ldap/base.rb, line 470
470:     def hash
471:       dn.hash
472:     end

[Source]

     # File lib/active_ldap/base.rb, line 722
722:     def have_attribute?(name, except=[])
723:       real_name = to_real_attribute_name(name)
724:       real_name and !except.include?(real_name)
725:     end

[Source]

     # File lib/active_ldap/base.rb, line 536
536:     def id
537:       get_attribute(dn_attribute)
538:     end
id=(value)

Alias for dn=

[Source]

     # File lib/active_ldap/base.rb, line 815
815:     def inspect
816:       abbreviate_instance_variables do
817:         super
818:       end
819:     end

[Source]

     # File lib/active_ldap/base.rb, line 474
474:     def may
475:       ensure_apply_object_class
476:       @may
477:     end

method_missing

If a given method matches an attribute or an attribute alias then call the appropriate method. TODO: Determine if it would be better to define each allowed method

      using class_eval instead of using method_missing.  This would
      give tab completion in irb.

[Source]

     # File lib/active_ldap/base.rb, line 596
596:     def method_missing(name, *args, &block)
597:       ensure_apply_object_class
598: 
599:       key = name.to_s
600:       case key
601:       when /=$/
602:         real_key = $PREMATCH
603:         if have_attribute?(real_key, ['objectClass'])
604:           if args.size != 1
605:             raise ArgumentError,
606:                     _("wrong number of arguments (%d for 1)") % args.size
607:           end
608:           return set_attribute(real_key, *args, &block)
609:         end
610:       when /(?:(_before_type_cast)|(\?))?$/
611:         real_key = $PREMATCH
612:         before_type_cast = !$1.nil?
613:         query = !$2.nil?
614:         if have_attribute?(real_key, ['objectClass'])
615:           if args.size > 1
616:             raise ArgumentError,
617:               _("wrong number of arguments (%d for 1)") % args.size
618:           end
619:           if before_type_cast
620:             return get_attribute_before_type_cast(real_key, *args)[1]
621:           elsif query
622:             return get_attribute_as_query(real_key, *args)
623:           else
624:             return get_attribute(real_key, *args)
625:           end
626:         end
627:       end
628:       super
629:     end

Add available attributes to the methods

[Source]

     # File lib/active_ldap/base.rb, line 632
632:     def methods(inherited_too=true)
633:       ensure_apply_object_class
634:       target_names = @attribute_names.keys + @attribute_aliases.keys
635:       target_names -= ['objectClass', Inflector.underscore('objectClass')]
636:       super + target_names.uniq.collect do |x|
637:         [x, "#{x}=", "#{x}?", "#{x}_before_type_cast"]
638:       end.flatten
639:     end

[Source]

     # File lib/active_ldap/base.rb, line 479
479:     def must
480:       ensure_apply_object_class
481:       @must
482:     end

new_entry?

Return whether the entry is new entry in LDAP or not

[Source]

     # File lib/active_ldap/base.rb, line 516
516:     def new_entry?
517:       @new_entry
518:     end

[Source]

     # File lib/active_ldap/base.rb, line 821
821:     def pretty_print(q)
822:       abbreviate_instance_variables do
823:         q.pp_object(self)
824:       end
825:     end

[Source]

     # File lib/active_ldap/base.rb, line 728
728:     def reload
729:       clear_association_cache
730:       _, attributes = search(:value => id).find do |_dn, _attributes|
731:         dn == _dn
732:       end
733:       if attributes.nil?
734:         raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
735:       end
736: 
737:       @ldap_data.update(attributes)
738:       classes, attributes = extract_object_class(attributes)
739:       apply_object_class(classes)
740:       self.attributes = attributes
741:       @new_entry = false
742:       self
743:     end

[Source]

     # File lib/active_ldap/base.rb, line 642
642:     def respond_to?(name, include_priv=false)
643:       have_attribute?(name.to_s) or
644:         (/(?:=|\?|_before_type_cast)$/ =~ name.to_s and
645:          have_attribute?($PREMATCH)) or
646:         super
647:     end

save

Save and validate this object into LDAP either adding or replacing attributes TODO: Relative DN support

[Source]

     # File lib/active_ldap/base.rb, line 579
579:     def save
580:       create_or_update
581:     end

[Source]

     # File lib/active_ldap/base.rb, line 583
583:     def save!
584:       unless create_or_update
585:         raise EntryNotSaved, _("entry %s can't be saved") % dn
586:       end
587:     end

[Source]

     # File lib/active_ldap/base.rb, line 790
790:     def schema
791:       @schema ||= super
792:     end

[Source]

     # File lib/active_ldap/base.rb, line 805
805:     def scope
806:       @scope || scope_of_class
807:     end

[Source]

     # File lib/active_ldap/base.rb, line 810
810:     def scope=(scope)
811:       self.class.validate_scope(scope)
812:       @scope = scope
813:     end

[Source]

     # File lib/active_ldap/base.rb, line 695
695:     def to_ldif
696:       super(dn, normalize_data(@data))
697:     end

[Source]

     # File lib/active_ldap/base.rb, line 540
540:     def to_param
541:       id
542:     end

[Source]

     # File lib/active_ldap/base.rb, line 699
699:     def to_xml(options={})
700:       root = options[:root] || Inflector.underscore(self.class.name)
701:       result = "<#{root}>\n"
702:       result << "  <dn>#{dn}</dn>\n"
703:       normalize_data(@data).sort_by {|key, values| key}.each do |key, values|
704:         targets = []
705:         values.each do |value|
706:           if value.is_a?(Hash)
707:             value.each do |option, real_value|
708:               targets << [real_value, " #{option}=\"true\""]
709:             end
710:           else
711:             targets << [value]
712:           end
713:         end
714:         targets.sort_by {|value, attr| value}.each do |value, attr|
715:           result << "  <#{key}#{attr}>#{value}</#{key}>\n"
716:         end
717:       end
718:       result << "</#{root}>\n"
719:       result
720:     end

Updates a given attribute and saves immediately

[Source]

     # File lib/active_ldap/base.rb, line 650
650:     def update_attribute(name, value)
651:       send("#{name}=", value)
652:       save
653:     end

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

[Source]

     # File lib/active_ldap/base.rb, line 657
657:     def update_attributes(attrs)
658:       self.attributes = attrs
659:       save
660:     end

[Source]

     # File lib/active_ldap/base.rb, line 662
662:     def update_attributes!(attrs)
663:       self.attributes = attrs
664:       save!
665:     end

Private Instance methods

[Source]

     # File lib/active_ldap/base.rb, line 828
828:     def abbreviate_instance_variables
829:       @abbreviating ||= nil
830:       connection, @connection = @connection, nil
831:       schema, @schema = @schema, nil
832:       attribute_schemata, @attribute_schemata = @attribute_schemata, nil
833:       must, may = @must, @may
834:       object_classes = @object_classes
835:       unless @abbreviating
836:         @abbreviating = true
837:         @must, @may = @must.collect(&:name), @may.collect(&:name)
838:         @object_classes = @object_classes.collect(&:name)
839:       end
840:       yield
841:     ensure
842:       @connection = connection
843:       @schema = schema
844:       @attribute_schemata = attribute_schemata
845:       @must = must
846:       @may = may
847:       @object_classes = object_classes
848:       @abbreviating = false
849:     end

apply_object_class

objectClass= special case for updating appropriately This updates the objectClass entry in @data. It also updating all required and allowed attributes while removing defined attributes that are no longer valid given the new objectclasses.

[Source]

     # File lib/active_ldap/base.rb, line 950
950:     def apply_object_class(val)
951:       new_oc = val
952:       new_oc = [val] if new_oc.class != Array
953:       new_oc = new_oc.uniq
954:       return new_oc if @last_oc == new_oc
955: 
956:       # Store for caching purposes
957:       @last_oc = new_oc.dup
958: 
959:       # Set the actual objectClass data
960:       define_attribute_methods(schema.attribute('objectClass'))
961:       replace_class(*new_oc)
962: 
963:       # Build |data| from schema
964:       # clear attribute name mapping first
965:       @attribute_schemata = {}
966:       @attribute_names = {}
967:       @normalized_attribute_names = {}
968:       @attribute_aliases = {}
969:       @must = []
970:       @may = []
971:       @object_classes = []
972:       new_oc.each do |objc|
973:         # get all attributes for the class
974:         object_class = schema.object_class(objc)
975:         @object_classes << object_class
976:         @must.concat(object_class.must)
977:         @may.concat(object_class.may)
978:       end
979:       @must.uniq!
980:       @may.uniq!
981:       (@must + @may).each do |attr|
982:         # Update attr_method with appropriate
983:         define_attribute_methods(attr)
984:       end
985:     end

array_of

Returns the array form of a value, or not an array if false is passed in.

[Source]

      # File lib/active_ldap/base.rb, line 1127
1127:     def array_of(value, to_a=true)
1128:       case value
1129:       when Array
1130:         if to_a or value.size > 1
1131:           value.collect {|v| array_of(v, to_a)}
1132:         else
1133:           if value.empty?
1134:             nil
1135:           else
1136:             array_of(value.first, to_a)
1137:           end
1138:         end
1139:       when Hash
1140:         if to_a
1141:           [value]
1142:         else
1143:           result = {}
1144:           value.each {|k, v| result[k] = array_of(v, to_a)}
1145:           result
1146:         end
1147:       else
1148:         to_a ? [value.to_s] : value.to_s
1149:       end
1150:     end

[Source]

      # File lib/active_ldap/base.rb, line 1222
1222:     def assert_dn_attribute
1223:       unless dn_attribute
1224:         raise ConfigurationError,
1225:                 _("dn_attribute isn't set for this class: %s") % self.class
1226:       end
1227:     end

[Source]

      # File lib/active_ldap/base.rb, line 1204
1204:     def collect_all_attributes(data)
1205:       dn_attr = to_real_attribute_name(dn_attribute)
1206:       dn_value = data[dn_attr]
1207: 
1208:       attributes = []
1209:       attributes.push([:add, dn_attr, dn_value])
1210: 
1211:       oc_value = data['objectClass']
1212:       attributes.push([:add, 'objectClass', oc_value])
1213:       data.each do |key, value|
1214:         next if value.empty? or key == 'objectClass' or key == dn_attr
1215: 
1216:         attributes.push([:add, key, value])
1217:       end
1218: 
1219:       attributes
1220:     end

[Source]

      # File lib/active_ldap/base.rb, line 1167
1167:     def collect_modified_attributes(ldap_data, data)
1168:       attributes = []
1169:       # Now that all the options will be treated as unique attributes
1170:       # we can see what's changed and add anything that is brand-spankin'
1171:       # new.
1172:       ldap_data.each do |k, v|
1173:         value = data[k] || []
1174: 
1175:         next if v == value
1176: 
1177:         # Create mod entries
1178:         if value.empty?
1179:           # Since some types do not have equality matching rules,
1180:           # delete doesn't work
1181:           # Replacing with nothing is equivalent.
1182:           if !data.has_key?(k) and schema.attribute(k).binary_required?
1183:             value = [{'binary' => []}]
1184:           end
1185:         else
1186:           # Ditched delete then replace because attribs with no equality
1187:           # match rules will fails
1188:         end
1189:         attributes.push([:replace, k, value])
1190:       end
1191:       data.each do |k, v|
1192:         value = v || []
1193:         next if ldap_data.has_key?(k) or value.empty?
1194: 
1195:         # Detect subtypes and account for them
1196:         # REPLACE will function like ADD, but doesn't hit EQUALITY problems
1197:         # TODO: Added equality(attr) to Schema
1198:         attributes.push([:replace, k, value])
1199:       end
1200: 
1201:       attributes
1202:     end

[Source]

      # File lib/active_ldap/base.rb, line 1257
1257:     def create
1258:       prepare_data_for_saving do |data, ldap_data|
1259:         attributes = collect_all_attributes(data)
1260:         add_entry(dn, attributes)
1261:         @new_entry = false
1262:         true
1263:       end
1264:     end

[Source]

      # File lib/active_ldap/base.rb, line 1229
1229:     def create_or_update
1230:       new_entry? ? create : update
1231:     end

define_attribute_methods

Make a method entry for every alias of a valid attribute and map it onto the first attribute passed in.

[Source]

      # File lib/active_ldap/base.rb, line 1112
1112:     def define_attribute_methods(attribute)
1113:       real_name = attribute.name
1114:       return if @attribute_schemata.has_key?(real_name)
1115:       @attribute_schemata[real_name] = attribute
1116:       ([real_name] + attribute.aliases).each do |name|
1117:         @attribute_names[name] = real_name
1118:         @attribute_aliases[Inflector.underscore(name)] = real_name
1119:         @normalized_attribute_names[normalize_attribute_name(name)] = real_name
1120:       end
1121:     end

enforce_type

enforce_type applies your changes without attempting to write to LDAP. This means that if you set userCertificate to somebinary value, it will wrap it up correctly.

[Source]

     # File lib/active_ldap/base.rb, line 921
921:     def enforce_type(key, value)
922:       ensure_apply_object_class
923:       # Enforce attribute value formatting
924:       normalize_attribute(key, value)[1]
925:     end

[Source]

     # File lib/active_ldap/base.rb, line 910
910:     def ensure_apply_object_class
911:       current_object_class = @data['objectClass']
912:       return if current_object_class.nil? or current_object_class == @last_oc
913:       apply_object_class(current_object_class)
914:     end

[Source]

     # File lib/active_ldap/base.rb, line 851
851:     def extract_object_class(attributes)
852:       classes = []
853:       attrs = attributes.stringify_keys.reject do |key, value|
854:         if key == 'objectClass' or
855:             key.underscore == 'object_class' or
856:             key.downcase == 'objectclass'
857:           classes |= [value].flatten
858:           true
859:         else
860:           false
861:         end
862:       end
863:       [classes, attrs]
864:     end

[Source]

      # File lib/active_ldap/base.rb, line 1033
1033:     def false_value?(value)
1034:       value.nil? or value == false or value == [] or
1035:         value == "false" or value == "FALSE" or value == ""
1036:     end

get_attribute

Return the value of the attribute called by method_missing?

[Source]

     # File lib/active_ldap/base.rb, line 990
990:     def get_attribute(name, force_array=false)
991:       name, value = get_attribute_before_type_cast(name, force_array)
992:       attribute = schema.attribute(name)
993:       type_cast(attribute, value)
994:     end

[Source]

      # File lib/active_ldap/base.rb, line 1024
1024:     def get_attribute_as_query(name, force_array=false)
1025:       name, value = get_attribute_before_type_cast(name, force_array)
1026:       if force_array
1027:         value.collect {|x| !false_value?(x)}
1028:       else
1029:         !false_value?(value)
1030:       end
1031:     end

[Source]

      # File lib/active_ldap/base.rb, line 1013
1013:     def get_attribute_before_type_cast(name, force_array=false)
1014:       name = to_real_attribute_name(name)
1015: 
1016:       value = @data[name] || []
1017:       if force_array
1018:         [name, value.dup]
1019:       else
1020:         [name, array_of(value.dup, false)]
1021:       end
1022:     end

[Source]

     # File lib/active_ldap/base.rb, line 866
866:     def init_base
867:       init_instance_variables
868:     end

[Source]

     # File lib/active_ldap/base.rb, line 927
927:     def init_instance_variables
928:       @mutex = Mutex.new
929:       @data = {} # where the r/w entry data is stored
930:       @ldap_data = {} # original ldap entry data
931:       @attribute_schemata = {}
932:       @attribute_names = {} # list of valid method calls for attributes used
933:                             # for dereferencing
934:       @normalized_attribute_names = {} # list of normalized attribute name
935:       @attribute_aliases = {} # aliases of @attribute_names
936:       @last_oc = false # for use in other methods for "caching"
937:       @dn_attribute = nil
938:       @base = nil
939:       @scope = nil
940:       @connection ||= nil
941:     end

[Source]

     # File lib/active_ldap/base.rb, line 870
870:     def initialize_by_ldap_data(dn, attributes)
871:       init_base
872:       @new_entry = false
873:       @dn_is_base = false
874:       @ldap_data = attributes
875:       classes, attributes = extract_object_class(attributes)
876:       apply_object_class(classes)
877:       self.dn = dn
878:       self.attributes = attributes
879:       yield self if block_given?
880:       assert_dn_attribute
881:     end

[Source]

     # File lib/active_ldap/base.rb, line 883
883:     def instantiate(args)
884:       dn, attributes, options = args
885:       options ||= {}
886: 
887:       obj = self.class.allocate
888:       obj.connection = options[:connection] || @connection
889:       obj.instance_eval do
890:         initialize_by_ldap_data(dn, attributes)
891:       end
892:       obj
893:     end

[Source]

      # File lib/active_ldap/base.rb, line 1152
1152:     def normalize_data(data, except=[])
1153:       _schema = schema
1154:       result = {}
1155:       data.each do |key, values|
1156:         next if except.include?(key)
1157:         real_name = to_real_attribute_name(key)
1158:         next if real_name and except.include?(real_name)
1159:         real_name ||= key
1160:         next if _schema.attribute(real_name).id.nil?
1161:         result[real_name] ||= []
1162:         result[real_name].concat(values)
1163:       end
1164:       result
1165:     end

[Source]

      # File lib/active_ldap/base.rb, line 1233
1233:     def prepare_data_for_saving
1234:       # Expand subtypes to real ldap_data attributes
1235:       # We can't reuse @ldap_data because an exception would leave
1236:       # an object in an unknown state
1237:       ldap_data = normalize_data(@ldap_data)
1238: 
1239:       # Expand subtypes to real data attributes, but leave @data alone
1240:       bad_attrs = @data.keys - attribute_names
1241:       data = normalize_data(@data, bad_attrs)
1242: 
1243:       success = yield(data, ldap_data)
1244: 
1245:       if success
1246:         @ldap_data = Marshal.load(Marshal.dump(data))
1247:         # Delete items disallowed by objectclasses.
1248:         # They should have been removed from ldap.
1249:         bad_attrs.each do |remove_me|
1250:           @ldap_data.delete(remove_me)
1251:         end
1252:       end
1253: 
1254:       success
1255:     end

set_attribute

Set the value of the attribute called by method_missing?

[Source]

      # File lib/active_ldap/base.rb, line 1041
1041:     def set_attribute(name, value)
1042:       attr = to_real_attribute_name(name)
1043:       attr, value = update_dn(attr, value) if attr == dn_attribute
1044:       raise UnknownAttribute.new(name) if attr.nil?
1045: 
1046:       case value
1047:       when nil, ""
1048:         value = []
1049:       when Array
1050:         value = value.collect {|c| c.blank? ? [] : c}.flatten
1051:       when String
1052:         value = [value]
1053:       when Numeric
1054:         value = [value.to_s]
1055:       end
1056: 
1057:       @data[attr] = enforce_type(attr, value)
1058:     end

[Source]

      # File lib/active_ldap/base.rb, line 1083
1083:     def split_dn_value(value)
1084:       dn_value = relative_dn_value = nil
1085:       begin
1086:         dn_value = DN.parse(value)
1087:       rescue DistinguishedNameInvalid
1088:         dn_value = DN.parse("#{dn_attribute}=#{value}")
1089:       end
1090: 
1091:       begin
1092:         relative_dn_value = dn_value - DN.parse(base_of_class)
1093:         if relative_dn_value.rdns.empty?
1094:           val = []
1095:           bases = dn_value.rdns
1096:         else
1097:           val, *bases = relative_dn_value.rdns
1098:         end
1099:       rescue ArgumentError
1100:         val, *bases = dn_value.rdns
1101:       end
1102: 
1103:       dn_attribute_name, dn_attribute_value = val.to_a[0]
1104:       [dn_attribute_name, dn_attribute_value,
1105:        bases.empty? ? nil : DN.new(*bases).to_s]
1106:     end

[Source]

     # File lib/active_ldap/base.rb, line 895
895:     def to_real_attribute_name(name, allow_normalized_name=false)
896:       return name if name.nil?
897:       ensure_apply_object_class
898:       name = name.to_s
899:       real_name = @attribute_names[name]
900:       real_name ||= @attribute_aliases[Inflector.underscore(name)]
901:       if real_name
902:         real_name
903:       elsif allow_normalized_name
904:         @normalized_attribute_names[normalize_attribute_name(name)]
905:       else
906:         nil
907:       end
908:     end

[Source]

      # File lib/active_ldap/base.rb, line 996
 996:     def type_cast(attribute, value)
 997:       case value
 998:       when Hash
 999:         result = {}
1000:         value.each do |option, val|
1001:           result[option] = type_cast(attribute, val)
1002:         end
1003:         result
1004:       when Array
1005:         value.collect do |val|
1006:           type_cast(attribute, val)
1007:         end
1008:       else
1009:         attribute.type_cast(value)
1010:       end
1011:     end

[Source]

      # File lib/active_ldap/base.rb, line 1266
1266:     def update
1267:       prepare_data_for_saving do |data, ldap_data|
1268:         attributes = collect_modified_attributes(ldap_data, data)
1269:         modify_entry(dn, attributes)
1270:         true
1271:       end
1272:     end

[Source]

      # File lib/active_ldap/base.rb, line 1060
1060:     def update_dn(attr, value)
1061:       @dn_is_base = false
1062:       return [attr, value] if value.blank?
1063: 
1064:       new_dn_attribute, new_value, base = split_dn_value(value)
1065:       if new_dn_attribute.nil? and new_value.nil?
1066:         @dn_is_base = true
1067:         @base = nil
1068:         attr, value = DN.parse(base).rdns[0].to_a[0]
1069:         @dn_attribute = attr
1070:       else
1071:         new_dn_attribute = to_real_attribute_name(new_dn_attribute)
1072:         if new_dn_attribute
1073:           value = new_value
1074:           @base = base
1075:           if dn_attribute != new_dn_attribute
1076:             @dn_attribute = attr = new_dn_attribute
1077:           end
1078:         end
1079:       end
1080:       [attr, value]
1081:     end

[Validate]