Base is the primary class which contains all of the core ActiveLdap functionality. It is meant to only ever be subclassed by extension classes.
# File lib/active_ldap/base.rb, line 506
506: def abstract_class?
507: defined?(@abstract_class) && @abstract_class
508: end
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.
# File lib/active_ldap/base.rb, line 433
433: def base
434: @base ||= compute_base
435: end
# File lib/active_ldap/base.rb, line 438
438: def base=(value)
439: self.inheritable_base = value
440: @base = nil
441: end
# File lib/active_ldap/base.rb, line 466
466: def base_class
467: if self == Base or superclass == Base
468: self
469: else
470: superclass.base_class
471: end
472: end
# File lib/active_ldap/base.rb, line 298
298: def self.class_local_attr_accessor(search_ancestors, *syms)
299: syms.flatten.each do |sym|
300: class_eval( 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, __FILE__, __LINE__ + 1)
301: end
302: end
# File lib/active_ldap/base.rb, line 510
510: def class_of_active_ldap_descendant(klass)
511: if klass.superclass == Base or klass.superclass.abstract_class?
512: klass
513: elsif klass.superclass.nil?
514: raise Error, _("%s doesn't belong in a hierarchy descending " "from ActiveLdap") % (name || to_s)
515: else
516: class_of_active_ldap_descendant(klass.superclass)
517: end
518: end
# File lib/active_ldap/base.rb, line 389
389: def create(attributes=nil, &block)
390: if attributes.is_a?(Array)
391: attributes.collect {|attrs| create(attrs, &block)}
392: else
393: object = new(attributes, &block)
394: object.save
395: object
396: end
397: end
# File lib/active_ldap/base.rb, line 474
474: def default_search_attribute
475: dn_attribute
476: end
establish_connection is deprecated since 1.1.0. Please use setup_connection() instead.
# File lib/active_ldap/base.rb, line 380
380: def establish_connection(config=nil)
381: message =
382: _("ActiveLdap::Base.establish_connection has been deprecated " "since 1.1.0. " "Please use ActiveLdap::Base.setup_connection instead.")
383: ActiveSupport::Deprecation.warn(message)
384: setup_connection(config)
385: end
# File lib/active_ldap/base.rb, line 540
540: def human_name(options={})
541: defaults = self_and_descendants_from_active_ldap.collect do |klass|
542: if klass.name.blank?
543: nil
544: else
545: :"#{klass.name.underscore}"
546: end
547: end
548: defaults << name.humanize
549: defaults = defaults.compact
550: defaults.first || name || to_s
551: end
Hide new in Base
# File lib/active_ldap/base.rb, line 333
333: def inherited(sub_class)
334: super
335: sub_class.module_eval do
336: include GetTextSupport
337: end
338: end
# File lib/active_ldap/base.rb, line 478
478: def inspect
479: if self == Base
480: super
481: elsif abstract_class?
482: "#{super}(abstract)"
483: else
484: detail = nil
485: begin
486: must = []
487: may = []
488: class_names = classes.collect do |object_class|
489: must.concat(object_class.must)
490: may.concat(object_class.may)
491: object_class.name
492: end
493: detail = ["objectClass:<#{class_names.join(', ')}>",
494: "must:<#{inspect_attributes(must)}>",
495: "may:<#{inspect_attributes(may)}>"].join(", ")
496: rescue ActiveLdap::ConnectionNotSetup
497: detail = "not-connected"
498: rescue ActiveLdap::Error
499: detail = "connection-failure"
500: end
501: "#{super}(#{detail})"
502: end
503: 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
# File lib/active_ldap/base.rb, line 406
406: def ldap_mapping(options={})
407: options = options.symbolize_keys
408: validate_ldap_mapping_options(options)
409:
410: self.dn_attribute = options[:dn_attribute] || default_dn_attribute
411: self.dn_attribute = dn_attribute.to_s if dn_attribute.is_a?(Symbol)
412: self.prefix = options[:prefix] || default_prefix
413: self.scope = options[:scope]
414: self.required_classes = options[:classes]
415: self.recommended_classes = options[:recommended_classes]
416: self.excluded_classes = options[:excluded_classes]
417: self.sort_by = options[:sort_by]
418: self.order = options[:order]
419:
420: public_class_method :new
421: 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
# File lib/active_ldap/base.rb, line 670
670: def initialize(attributes=nil)
671: init_base
672: @new_entry = true
673: initial_classes = required_classes | recommended_classes
674: case attributes
675: when nil
676: self.classes = initial_classes
677: when String, Array, DN
678: self.classes = initial_classes
679: self.dn = attributes
680: when Hash
681: classes, attributes = extract_object_class(attributes)
682: self.classes = classes | initial_classes
683: normalized_attributes = {}
684: attributes.each do |key, value|
685: real_key = to_real_attribute_name(key) || key
686: normalized_attributes[real_key] = value
687: end
688: self.dn = normalized_attributes.delete(dn_attribute)
689: self.attributes = normalized_attributes
690: else
691: format = _("'%s' must be either nil, DN value as ActiveLdap::DN, " "String or Array or attributes as Hash")
692: raise ArgumentError, format % attributes.inspect
693: end
694: yield self if block_given?
695: end
# File lib/active_ldap/base.rb, line 443
443: def prefix
444: @prefix ||= inheritable_prefix and DN.parse(inheritable_prefix)
445: end
# File lib/active_ldap/base.rb, line 447
447: def prefix=(value)
448: self.inheritable_prefix = value
449: @prefix = nil
450: @base = nil
451: end
# File lib/active_ldap/base.rb, line 454
454: def scope=(scope)
455: validate_scope(scope)
456: self.scope_without_validation = scope
457: end
# File lib/active_ldap/base.rb, line 521
521: def self_and_descendants_from_active_ldap
522: klass = self
523: classes = [klass]
524: while klass != klass.base_class
525: classes << klass = klass.superclass
526: end
527: classes
528: rescue
529: [self]
530: end
Connect and bind to LDAP creating a class variable for use by all ActiveLdap objects.
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
# File lib/active_ldap/base.rb, line 372
372: def setup_connection(config=nil)
373: super
374: ensure_logger
375: nil
376: end
# File lib/active_ldap/base.rb, line 459
459: def validate_scope(scope)
460: scope = scope.to_sym if scope.is_a?(String)
461: return if scope.nil? or scope.is_a?(Symbol)
462: raise ConfigurationError,
463: _("scope '%s' must be a Symbol") % scope.inspect
464: end
# File lib/active_ldap/base.rb, line 633
633: def compute_base
634: _base = inheritable_base
635: _base = configuration[:base] if _base.nil? and configuration
636: if _base.nil?
637: target = superclass
638: loop do
639: break unless target.respond_to?(:base)
640: _base = target.base
641: break if _base
642: target = target.superclass
643: end
644: end
645: _prefix = prefix
646:
647: _base ||= connection.naming_contexts.first
648: return _prefix if _base.blank?
649:
650: _base = DN.parse(_base)
651: _base = _prefix + _base if _prefix
652: _base
653: end
# File lib/active_ldap/base.rb, line 616
616: def default_dn_attribute
617: dn_attribute = nil
618: parent_class = ancestors[1]
619: if parent_class.respond_to?(:dn_attribute)
620: dn_attribute = parent_class.dn_attribute
621: end
622: dn_attribute || "cn"
623: end
# File lib/active_ldap/base.rb, line 625
625: def default_prefix
626: if name.blank?
627: nil
628: else
629: "ou=#{name.demodulize.pluralize}"
630: end
631: end
# File lib/active_ldap/base.rb, line 584
584: def ensure_logger
585: @@logger ||= configuration[:logger]
586: # Setup default logger to console
587: if @@logger.nil?
588: require 'logger'
589: @@logger = Logger.new(STDERR)
590: @@logger.progname = 'ActiveLdap'
591: @@logger.level = Logger::ERROR
592: end
593: configuration[:logger] ||= @@logger
594: end
# File lib/active_ldap/base.rb, line 566
566: def inspect_attribute(attribute)
567: syntax = attribute.syntax
568: result = "#{attribute.name}"
569: if syntax and !syntax.description.blank?
570: result << ": #{syntax.description}"
571: end
572: properties = []
573: properties << "read-only" if attribute.read_only?
574: properties << "binary" if attribute.binary?
575: properties << "binary-required" if attribute.binary_required?
576: result << "(#{properties.join(', ')})" unless properties.empty?
577: result
578: end
# File lib/active_ldap/base.rb, line 554
554: def inspect_attributes(attributes)
555: inspected_attribute_names = {}
556: attributes.collect do |attribute|
557: if inspected_attribute_names.has_key?(attribute.name)
558: nil
559: else
560: inspected_attribute_names[attribute.name] = true
561: inspect_attribute(attribute)
562: end
563: end.compact.join(', ')
564: end
# File lib/active_ldap/base.rb, line 596
596: def instantiate(args)
597: dn, attributes, options = args
598: options ||= {}
599: if self.class == Class
600: klass = self.ancestors[0].to_s.split(':').last
601: real_klass = self.ancestors[0]
602: else
603: klass = self.class.to_s.split(':').last
604: real_klass = self.class
605: end
606:
607: obj = real_klass.allocate
608: conn = options[:connection] || connection
609: obj.connection = conn if conn != connection
610: obj.instance_eval do
611: initialize_by_ldap_data(dn, attributes)
612: end
613: obj
614: end
Returns true if the comparison_object is the same object, or is of the same type and has the same dn.
# File lib/active_ldap/base.rb, line 700
700: def ==(comparison_object)
701: comparison_object.equal?(self) or
702: (comparison_object.instance_of?(self.class) and
703: comparison_object.dn == dn and
704: !comparison_object.new_entry?)
705: end
# File lib/active_ldap/base.rb, line 983
983: def [](name, force_array=false)
984: if name == "dn"
985: array_of(dn, force_array)
986: else
987: get_attribute(name, force_array)
988: end
989: end
# File lib/active_ldap/base.rb, line 991
991: def []=(name, value)
992: set_attribute(name, value)
993: end
attributes
Return attribute methods so that a program can determine available attributes dynamically without schema awareness
# File lib/active_ldap/base.rb, line 742
742: def attribute_names(normalize=false)
743: entry_attribute.names(normalize)
744: end
# File lib/active_ldap/base.rb, line 746
746: def attribute_present?(name)
747: values = get_attribute(name, true)
748: !values.empty? or values.any? {|x| !(x and x.empty?)}
749: end
This returns the key value pairs in @data with all values cloned
# File lib/active_ldap/base.rb, line 903
903: def attributes
904: @simplified_data ||= simplify_data(@data)
905: @simplified_data.clone
906: 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.
# File lib/active_ldap/base.rb, line 914
914: def attributes=(new_attributes)
915: return if new_attributes.blank?
916: _schema = _local_entry_attribute = nil
917: targets = remove_attributes_protected_from_mass_assignment(new_attributes)
918: targets.each do |key, value|
919: setter = "#{key}="
920: unless respond_to?(setter)
921: _schema ||= schema
922: attribute = _schema.attribute(key)
923: next if attribute.id.nil?
924: _local_entry_attribute ||= local_entry_attribute
925: _local_entry_attribute.register(attribute)
926: end
927: send(setter, value)
928: end
929: end
# File lib/active_ldap/base.rb, line 1041
1041: def base
1042: @base ||= compute_base
1043: end
# File lib/active_ldap/base.rb, line 1045
1045: def base=(object_local_base)
1046: ensure_update_dn
1047: @dn = nil
1048: @base = nil
1049: @base_value = object_local_base
1050: end
# File lib/active_ldap/base.rb, line 1001
1001: def bind(config_or_password={}, config_or_ignore=nil, &block)
1002: if config_or_password.is_a?(String)
1003: config = (config_or_ignore || {}).merge(:password => config_or_password)
1004: else
1005: config = config_or_password
1006: end
1007: config = {:bind_dn => dn, :allow_anonymous => false}.merge(config)
1008: config[:password_block] ||= block if block_given?
1009: setup_connection(config)
1010:
1011: before_connection = @connection
1012: begin
1013: @connection = nil
1014: connection.connect
1015: @connection = connection
1016: clear_connection_based_cache
1017: clear_association_cache
1018: rescue ActiveLdap::Error
1019: remove_connection
1020: @connection = before_connection
1021: raise
1022: end
1023: true
1024: end
# File lib/active_ldap/base.rb, line 1026
1026: def clear_connection_based_cache
1027: @schema = nil
1028: @local_entry_attribute = nil
1029: clear_object_class_based_cache
1030: end
# File lib/active_ldap/base.rb, line 1032
1032: def clear_object_class_based_cache
1033: @entry_attribute = nil
1034: @real_names = {}
1035: end
# File lib/active_ldap/base.rb, line 793
793: def default_search_attribute
794: self.class.default_search_attribute
795: end
# File lib/active_ldap/base.rb, line 805
805: def delete(options={})
806: super(dn, options)
807: end
# File lib/active_ldap/base.rb, line 1062
1062: def delete_all(options={})
1063: super({:base => dn}.merge(options || {}))
1064: end
destroy
Delete this entry from LDAP
# File lib/active_ldap/base.rb, line 800
800: def destroy
801: self.class.delete(dn)
802: @new_entry = true
803: end
# File lib/active_ldap/base.rb, line 1066
1066: def destroy_all(options={})
1067: super({:base => dn}.merge(options || {}))
1068: end
dn
Return the authoritative dn
# File lib/active_ldap/base.rb, line 769
769: def dn
770: @dn ||= compute_dn
771: end
# File lib/active_ldap/base.rb, line 781
781: def dn=(value)
782: set_attribute(dn_attribute_with_fallback, value)
783: end
# File lib/active_ldap/base.rb, line 787
787: def dn_attribute
788: ensure_update_dn
789: _dn_attribute = @dn_attribute || dn_attribute_of_class
790: to_real_attribute_name(_dn_attribute) || _dn_attribute
791: end
# File lib/active_ldap/base.rb, line 995
995: def each
996: @data.each do |key, values|
997: yield(key.dup, values.dup)
998: end
999: end
Delegates to ==
# File lib/active_ldap/base.rb, line 708
708: def eql?(comparison_object)
709: self == (comparison_object)
710: end
exist?
Return whether the entry exists in LDAP or not
# File lib/active_ldap/base.rb, line 754
754: def exist?
755: self.class.exists?(dn)
756: end
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") ]
# File lib/active_ldap/base.rb, line 716
716: def hash
717: return super if @_hashing # workaround for GetText :<
718: _dn = nil
719: begin
720: @_hashing = true
721: _dn = dn
722: rescue DistinguishedNameInvalid, DistinguishedNameNotSetError
723: return super
724: ensure
725: @_hashing = false
726: end
727: _dn.hash
728: end
# File lib/active_ldap/base.rb, line 960
960: def have_attribute?(name, except=[])
961: real_name = to_real_attribute_name(name)
962: !real_name.nil? and !except.include?(real_name)
963: end
# File lib/active_ldap/base.rb, line 773
773: def id
774: get_attribute(dn_attribute_with_fallback)
775: end
# File lib/active_ldap/base.rb, line 1070
1070: def inspect
1071: object_classes = entry_attribute.object_classes
1072: inspected_object_classes = object_classes.collect do |object_class|
1073: object_class.name
1074: end.join(', ')
1075: must_attributes = must.collect(&:name).sort.join(', ')
1076: may_attributes = may.collect(&:name).sort.join(', ')
1077: inspected_attributes = attribute_names.sort.collect do |name|
1078: inspect_attribute(name)
1079: end.join(', ')
1080: result = "\#<#{self.class} objectClass:<#{inspected_object_classes}>, "
1081: result << "must:<#{must_attributes}>, may:<#{may_attributes}>, "
1082: result << "#{inspected_attributes}>"
1083: result
1084: end
# File lib/active_ldap/base.rb, line 730
730: def may
731: entry_attribute.may
732: end
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.
# File lib/active_ldap/base.rb, line 831
831: def method_missing(name, *args, &block)
832: key = name.to_s
833: case key
834: when /=$/
835: real_key = $PREMATCH
836: if have_attribute?(real_key, ['objectClass'])
837: if args.size != 1
838: raise ArgumentError,
839: _("wrong number of arguments (%d for 1)") % args.size
840: end
841: return set_attribute(real_key, *args, &block)
842: end
843: when /(?:(_before_type_cast)|(\?))?$/
844: real_key = $PREMATCH
845: before_type_cast = !$1.nil?
846: query = !$2.nil?
847: if have_attribute?(real_key, ['objectClass'])
848: if args.size > 1
849: raise ArgumentError,
850: _("wrong number of arguments (%d for 1)") % args.size
851: end
852: if before_type_cast
853: return get_attribute_before_type_cast(real_key, *args)[1]
854: elsif query
855: return get_attribute_as_query(real_key, *args)
856: else
857: return get_attribute(real_key, *args)
858: end
859: end
860: end
861: super
862: end
Add available attributes to the methods
# File lib/active_ldap/base.rb, line 865
865: def methods(inherited_too=true)
866: target_names = entry_attribute.all_names
867: target_names -= ['objectClass', 'objectClass'.underscore]
868: super + target_names.uniq.collect do |x|
869: [x, "#{x}=", "#{x}?", "#{x}_before_type_cast"]
870: end.flatten
871: end
# File lib/active_ldap/base.rb, line 734
734: def must
735: entry_attribute.must
736: end
new_entry?
Return whether the entry is new entry in LDAP or not
# File lib/active_ldap/base.rb, line 762
762: def new_entry?
763: @new_entry
764: end
# File lib/active_ldap/base.rb, line 966
966: def reload
967: clear_association_cache
968: _, attributes = search(:value => id).find do |_dn, _attributes|
969: dn == _dn
970: end
971: if attributes.nil?
972: raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
973: end
974:
975: @ldap_data.update(attributes)
976: classes, attributes = extract_object_class(attributes)
977: self.classes = classes
978: self.attributes = attributes
979: @new_entry = false
980: self
981: end
# File lib/active_ldap/base.rb, line 874
874: def respond_to?(name, include_priv=false)
875: return true if super
876:
877: name = name.to_s
878: return true if have_attribute?(name, ["objectClass"])
879: return false if /(?:=|\?|_before_type_cast)$/ !~ name
880: have_attribute?($PREMATCH, ["objectClass"])
881: end
# File lib/active_ldap/base.rb, line 818
818: def save!
819: unless create_or_update
820: raise EntryNotSaved, _("entry %s can't be saved") % dn
821: end
822: end
# File lib/active_ldap/base.rb, line 1037
1037: def schema
1038: @schema ||= super
1039: end
# File lib/active_ldap/base.rb, line 1053
1053: def scope
1054: @scope || scope_of_class
1055: end
# File lib/active_ldap/base.rb, line 1057
1057: def scope=(scope)
1058: self.class.validate_scope(scope)
1059: @scope = scope
1060: end
# File lib/active_ldap/base.rb, line 935
935: def to_ldif
936: Ldif.new([to_ldif_record]).to_s
937: end
# File lib/active_ldap/base.rb, line 931
931: def to_ldif_record
932: super(dn, normalize_data(@data))
933: end
# File lib/active_ldap/base.rb, line 777
777: def to_param
778: id
779: end
# File lib/active_ldap/base.rb, line 956
956: def to_s
957: to_ldif
958: end
# File lib/active_ldap/base.rb, line 939
939: def to_xml(options={})
940: options = options.dup
941: options[:root] ||= (self.class.name || '').underscore
942: options[:root] = 'anonymous' if options[:root].blank?
943: except = options[:except]
944: if except
945: options[:except] = except.collect do |name|
946: if name.to_s.downcase == "dn"
947: "dn"
948: else
949: to_real_attribute_name(name)
950: end
951: end.compact
952: end
953: XML.new(dn, normalize_data(@data), schema).to_s(options)
954: end
Updates a given attribute and saves immediately
# File lib/active_ldap/base.rb, line 884
884: def update_attribute(name, value)
885: send("#{name}=", value)
886: save
887: end
This performs a bulk update of attributes and immediately calls #.
# File lib/active_ldap/base.rb, line 891
891: def update_attributes(attrs)
892: self.attributes = attrs
893: save
894: end
Returns the array form of a value, or not an array if false is passed in.
# File lib/active_ldap/base.rb, line 1413
1413: def array_of(value, to_a=true)
1414: case value
1415: when Array
1416: if to_a or value.size > 1
1417: value.collect {|v| array_of(v, false)}.compact
1418: else
1419: if value.empty?
1420: nil
1421: else
1422: array_of(value.first, to_a)
1423: end
1424: end
1425: when Hash
1426: if to_a
1427: [value]
1428: else
1429: result = {}
1430: value.each {|k, v| result[k] = array_of(v, to_a)}
1431: result
1432: end
1433: else
1434: to_a ? [value] : value
1435: end
1436: end
# File lib/active_ldap/base.rb, line 1116
1116: def attribute_name_resolvable_without_connection?
1117: @entry_attribute and @local_entry_attribute
1118: end
# File lib/active_ldap/base.rb, line 1510
1510: def collect_all_attributes(data)
1511: dn_attr = dn_attribute
1512: dn_value = data[dn_attr]
1513:
1514: attributes = []
1515: attributes.push([dn_attr, dn_value])
1516:
1517: oc_value = data['objectClass']
1518: attributes.push(['objectClass', oc_value])
1519: except_keys = ['objectClass', dn_attr].collect(&:downcase)
1520: data.each do |key, value|
1521: next if except_keys.include?(key.downcase)
1522: value = self.class.remove_blank_value(value)
1523: next if self.class.blank_value?(value)
1524:
1525: attributes.push([key, value])
1526: end
1527:
1528: attributes
1529: end
# File lib/active_ldap/base.rb, line 1466
1466: def collect_modified_attributes(ldap_data, data)
1467: klass = self.class
1468: _dn_attribute = dn_attribute
1469: new_dn_value = nil
1470: attributes = []
1471:
1472: # Now that all the options will be treated as unique attributes
1473: # we can see what's changed and add anything that is brand-spankin'
1474: # new.
1475: ldap_data.each do |k, v|
1476: value = data[k] || []
1477:
1478: next if v == value
1479:
1480: value = klass.remove_blank_value(value) || []
1481: next if v == value
1482:
1483: if klass.blank_value?(value) and
1484: schema.attribute(k).binary_required?
1485: value = [{'binary' => []}]
1486: end
1487: if k == _dn_attribute
1488: new_dn_value = value[0]
1489: else
1490: attributes.push([:replace, k, value])
1491: end
1492: end
1493:
1494: data.each do |k, v|
1495: value = v || []
1496: next if ldap_data.has_key?(k)
1497:
1498: value = klass.remove_blank_value(value) || []
1499: next if klass.blank_value?(value)
1500:
1501: # Detect subtypes and account for them
1502: # REPLACE will function like ADD, but doesn't hit EQUALITY problems
1503: # TODO: Added equality(attr) to Schema
1504: attributes.push([:replace, k, value])
1505: end
1506:
1507: [new_dn_value, attributes]
1508: end
# File lib/active_ldap/base.rb, line 1398
1398: def compute_base
1399: base_of_class = self.class.base
1400: if @base_value.nil?
1401: base_of_class
1402: else
1403: base_of_object = DN.parse(@base_value)
1404: base_of_object += base_of_class if base_of_class
1405: base_of_object
1406: end
1407: end
# File lib/active_ldap/base.rb, line 1382
1382: def compute_dn
1383: return base if @dn_is_base
1384:
1385: ensure_update_dn
1386: dn_value = id
1387: if dn_value.nil?
1388: format = _("%s's DN attribute (%s) isn't set")
1389: message = format % [self.inspect, dn_attribute]
1390: raise DistinguishedNameNotSetError.new, message
1391: end
1392: dn_value = DN.escape_value(dn_value.to_s)
1393: _base = base
1394: _base = nil if _base.blank?
1395: DN.parse(["#{dn_attribute}=#{dn_value}", _base].compact.join(","))
1396: end
# File lib/active_ldap/base.rb, line 1563
1563: def create
1564: prepare_data_for_saving do |data, ldap_data|
1565: attributes = collect_all_attributes(data)
1566: add_entry(dn, attributes)
1567: @new_entry = false
1568: true
1569: end
1570: end
# File lib/active_ldap/base.rb, line 1531
1531: def create_or_update
1532: new_entry? ? create : update
1533: end
# File lib/active_ldap/base.rb, line 1087
1087: def dn_attribute_with_fallback
1088: begin
1089: dn_attribute
1090: rescue DistinguishedNameInvalid
1091: _dn_attribute = @dn_attribute || dn_attribute_of_class
1092: _dn_attribute = to_real_attribute_name(_dn_attribute) || _dn_attribute
1093: raise if _dn_attribute.nil?
1094: _dn_attribute
1095: end
1096: end
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.
# File lib/active_ldap/base.rb, line 1194
1194: def enforce_type(key, value)
1195: # Enforce attribute value formatting
1196: normalize_attribute(key, value)[1]
1197: end
# File lib/active_ldap/base.rb, line 1372
1372: def ensure_update_dn
1373: return unless need_update_dn?
1374: @mutex.synchronize do
1375: if @dn_split_value
1376: update_dn(*@dn_split_value)
1377: @dn_split_value = nil
1378: end
1379: end
1380: end
# File lib/active_ldap/base.rb, line 1120
1120: def entry_attribute
1121: @entry_attribute ||=
1122: connection.entry_attribute(find_object_class_values(@data) || [])
1123: end
# File lib/active_ldap/base.rb, line 1129
1129: def extract_object_class(attributes)
1130: classes = []
1131: attrs = {}
1132: attributes.each do |key, value|
1133: key = key.to_s
1134: if /\Aobject_?class\z/ =~ key
1135: classes.concat(value.to_a)
1136: else
1137: attrs[key] = value
1138: end
1139: end
1140: [classes, attributes]
1141: end
# File lib/active_ldap/base.rb, line 1262
1262: def false_value?(value)
1263: value.nil? or value == false or value == [] or
1264: value == "false" or value == "FALSE" or value == ""
1265: end
# File lib/active_ldap/base.rb, line 1112
1112: def find_object_class_values(data)
1113: data["objectClass"] || data["objectclass"]
1114: end
Return the value of the attribute called by method_missing?
# File lib/active_ldap/base.rb, line 1217
1217: def get_attribute(name, force_array=false)
1218: name, value = get_attribute_before_type_cast(name, force_array)
1219: return value if name.nil?
1220: attribute = schema.attribute(name)
1221: type_cast(attribute, value)
1222: end
# File lib/active_ldap/base.rb, line 1253
1253: def get_attribute_as_query(name, force_array=false)
1254: name, value = get_attribute_before_type_cast(name, force_array)
1255: if force_array
1256: value.collect {|x| !false_value?(x)}
1257: else
1258: !false_value?(value)
1259: end
1260: end
# File lib/active_ldap/base.rb, line 1245
1245: def get_attribute_before_type_cast(name, force_array=false)
1246: name = to_real_attribute_name(name)
1247:
1248: value = @data[name]
1249: value = [] if value.nil?
1250: [name, array_of(value, force_array)]
1251: end
# File lib/active_ldap/base.rb, line 1143
1143: def init_base
1144: init_instance_variables
1145: end
# File lib/active_ldap/base.rb, line 1199
1199: def init_instance_variables
1200: @mutex = Mutex.new
1201: @data = {} # where the r/w entry data is stored
1202: @ldap_data = {} # original ldap entry data
1203: @dn_attribute = nil
1204: @base = nil
1205: @scope = nil
1206: @dn = nil
1207: @dn_is_base = false
1208: @dn_split_value = nil
1209: @connection ||= nil
1210: @_hashing = false
1211: clear_connection_based_cache
1212: end
# File lib/active_ldap/base.rb, line 1147
1147: def initialize_by_ldap_data(dn, attributes)
1148: init_base
1149: dn = Compatible.convert_to_utf8_encoded_object(dn)
1150: attributes = Compatible.convert_to_utf8_encoded_object(attributes)
1151: @original_dn = dn.clone
1152: @dn = dn
1153: @base = nil
1154: @base_value = nil
1155: @new_entry = false
1156: @dn_is_base = false
1157: @ldap_data = attributes
1158: classes, attributes = extract_object_class(attributes)
1159: self.classes = classes
1160: self.dn = dn
1161: self.attributes = attributes
1162: yield self if block_given?
1163: end
# File lib/active_ldap/base.rb, line 1098
1098: def inspect_attribute(name)
1099: values = get_attribute(name, true)
1100: values.collect do |value|
1101: if value.is_a?(String) and value.length > 50
1102: "#{value[0, 50]}...".inspect
1103: elsif value.is_a?(Date) || value.is_a?(Time)
1104: "#{value.to_s(:db)}"
1105: else
1106: value.inspect
1107: end
1108: end
1109: "#{name}: #{values.inspect}"
1110: end
# File lib/active_ldap/base.rb, line 1165
1165: def instantiate(args)
1166: dn, attributes, options = args
1167: options ||= {}
1168:
1169: obj = self.class.allocate
1170: obj.connection = options[:connection] || @connection
1171: obj.instance_eval do
1172: initialize_by_ldap_data(dn, attributes)
1173: end
1174: obj
1175: end
# File lib/active_ldap/base.rb, line 1125
1125: def local_entry_attribute
1126: @local_entry_attribute ||= connection.entry_attribute([])
1127: end
# File lib/active_ldap/base.rb, line 1368
1368: def need_update_dn?
1369: not @dn_split_value.nil?
1370: end
# File lib/active_ldap/base.rb, line 1438
1438: def normalize_data(data, except=[])
1439: _schema = schema
1440: result = {}
1441: data.each do |key, values|
1442: next if except.include?(key)
1443: real_name = to_real_attribute_name(key)
1444: next if real_name and except.include?(real_name)
1445: real_name ||= key
1446: next if _schema.attribute(real_name).id.nil?
1447: result[real_name] ||= []
1448: result[real_name].concat(enforce_type(real_name, values))
1449: end
1450: result
1451: end
# File lib/active_ldap/base.rb, line 1535
1535: def prepare_data_for_saving
1536: # Expand subtypes to real ldap_data attributes
1537: # We can't reuse @ldap_data because an exception would leave
1538: # an object in an unknown state
1539: ldap_data = normalize_data(@ldap_data)
1540:
1541: # Expand subtypes to real data attributes, but leave @data alone
1542: object_classes = find_object_class_values(@ldap_data) || []
1543: original_attributes =
1544: connection.entry_attribute(object_classes).names
1545: bad_attrs = original_attributes - entry_attribute.names
1546: data = normalize_data(@data, bad_attrs)
1547:
1548: success = yield(data, ldap_data)
1549:
1550: if success
1551: @ldap_data = data.clone
1552: # Delete items disallowed by objectclasses.
1553: # They should have been removed from ldap.
1554: bad_attrs.each do |remove_me|
1555: @ldap_data.delete(remove_me)
1556: end
1557: @original_dn = dn.clone
1558: end
1559:
1560: success
1561: end
# File lib/active_ldap/base.rb, line 1288
1288: def register_new_dn_attribute(name, value)
1289: @dn = nil
1290: @dn_is_base = false
1291: if value.blank?
1292: @dn_split_value = nil
1293: [name, nil]
1294: else
1295: new_name, new_value, raw_new_value, new_bases = split_dn_value(value)
1296: @dn_split_value = [new_name, new_value, new_bases]
1297: if new_name.nil? and new_value.nil?
1298: new_name, raw_new_value = new_bases[0].to_a[0]
1299: end
1300: [to_real_attribute_name(new_name) || name,
1301: raw_new_value || value]
1302: end
1303: end
Set the value of the attribute called by method_missing?
# File lib/active_ldap/base.rb, line 1270
1270: def set_attribute(name, value)
1271: real_name = to_real_attribute_name(name)
1272: _dn_attribute = nil
1273: valid_dn_attribute = true
1274: begin
1275: _dn_attribute = dn_attribute
1276: rescue DistinguishedNameInvalid
1277: valid_dn_attribute = false
1278: end
1279: if valid_dn_attribute and real_name == _dn_attribute
1280: real_name, value = register_new_dn_attribute(real_name, value)
1281: end
1282: raise UnknownAttribute.new(name) if real_name.nil?
1283:
1284: @data[real_name] = value
1285: @simplified_data = nil
1286: end
# File lib/active_ldap/base.rb, line 1453
1453: def simplify_data(data)
1454: _schema = schema
1455: result = {}
1456: data.each do |key, values|
1457: attribute = _schema.attribute(key)
1458: if attribute.single_value? and values.is_a?(Array) and values.size == 1
1459: values = values[0]
1460: end
1461: result[key] = type_cast(attribute, values)
1462: end
1463: result
1464: end
# File lib/active_ldap/base.rb, line 1331
1331: def split_dn_value(value)
1332: dn_value = relative_dn_value = nil
1333: begin
1334: dn_value = value if value.is_a?(DN)
1335: dn_value ||= DN.parse(value)
1336: rescue DistinguishedNameInvalid
1337: begin
1338: dn_value = DN.parse("#{dn_attribute}=#{value}")
1339: rescue DistinguishedNameInvalid
1340: return [nil, value, value, []]
1341: end
1342: end
1343:
1344: val = bases = nil
1345: begin
1346: relative_dn_value = dn_value
1347: base_of_class = self.class.base
1348: relative_dn_value -= base_of_class if base_of_class
1349: if relative_dn_value.rdns.empty?
1350: val = []
1351: bases = dn_value.rdns
1352: else
1353: val, *bases = relative_dn_value.rdns
1354: end
1355: rescue ArgumentError
1356: val, *bases = dn_value.rdns
1357: end
1358:
1359: dn_attribute_name, dn_attribute_value = val.to_a[0]
1360: escaped_dn_attribute_value = nil
1361: unless dn_attribute_value.nil?
1362: escaped_dn_attribute_value = DN.escape_value(dn_attribute_value)
1363: end
1364: [dn_attribute_name, escaped_dn_attribute_value,
1365: dn_attribute_value, bases]
1366: end
# File lib/active_ldap/base.rb, line 1177
1177: def to_real_attribute_name(name, allow_normalized_name=true)
1178: return name if name.nil?
1179: if allow_normalized_name
1180: entry_attribute.normalize(name, allow_normalized_name) ||
1181: local_entry_attribute.normalize(name, allow_normalized_name)
1182: else
1183: @real_names[name] ||=
1184: entry_attribute.normalize(name, false) ||
1185: local_entry_attribute.normalize(name, false)
1186: end
1187: end
# File lib/active_ldap/base.rb, line 1224
1224: def type_cast(attribute, value)
1225: case value
1226: when Hash
1227: result = {}
1228: value.each do |option, val|
1229: result[option] = type_cast(attribute, val)
1230: end
1231: if result.size == 1 and result.has_key?("binary")
1232: result["binary"]
1233: else
1234: result
1235: end
1236: when Array
1237: value.collect do |val|
1238: type_cast(attribute, val)
1239: end
1240: else
1241: attribute.type_cast(value)
1242: end
1243: end
# File lib/active_ldap/base.rb, line 1572
1572: def update
1573: prepare_data_for_saving do |data, ldap_data|
1574: new_dn_value, attributes = collect_modified_attributes(ldap_data, data)
1575: modify_entry(@original_dn, attributes)
1576: if new_dn_value
1577: old_dn_base = DN.parse(@original_dn).parent
1578: new_dn_base = dn.clone.parent
1579: if old_dn_base == new_dn_base
1580: new_superior = nil
1581: else
1582: new_superior = new_dn_base
1583: end
1584: modify_rdn_entry(@original_dn,
1585: "#{dn_attribute}=#{DN.escape_value(new_dn_value)}",
1586: true,
1587: new_superior)
1588: end
1589: true
1590: end
1591: end
# File lib/active_ldap/base.rb, line 1305
1305: def update_dn(new_name, new_value, bases)
1306: if new_name.nil? and new_value.nil?
1307: @dn_is_base = true
1308: @base = nil
1309: @base_value = nil
1310: attr, value = bases[0].to_a[0]
1311: @dn_attribute = attr
1312: else
1313: new_name ||= @dn_attribute || dn_attribute_of_class
1314: new_name = to_real_attribute_name(new_name)
1315: if new_name.nil?
1316: new_name = @dn_attribute || dn_attribute_of_class
1317: new_name = to_real_attribute_name(new_name)
1318: end
1319: new_bases = bases.empty? ? nil : DN.new(*bases).to_s
1320: dn_components = ["#{new_name}=#{new_value}",
1321: new_bases,
1322: self.class.base.to_s]
1323: dn_components = dn_components.find_all {|component| !component.blank?}
1324: DN.parse(dn_components.join(','))
1325: @base = nil
1326: @base_value = new_bases
1327: @dn_attribute = new_name
1328: end
1329: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.