| Class | ActiveLdap::Base |
| In: |
lib/active_ldap/base.rb
|
| Parent: | Object |
Base is the primary class which contains all of the core ActiveLdap functionality. It is meant to only ever be subclassed by extension classes.
| VALID_LDAP_MAPPING_OPTIONS | = | [:dn_attribute, :prefix, :scope, :classes, :recommended_classes, :excluded_classes, :sort_by, :order] |
| base | -> | base_inheritable |
| base= | -> | base_without_parsed_cache_clear= |
| scope= | -> | scope_without_validation= |
| dn_attribute | -> | dn_attribute_of_class |
| respond_to? | -> | respond_to_without_attributes? |
| base | -> | base_of_class |
| scope | -> | scope_of_class |
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 395
395: def base
396: _base = base_inheritable
397: _base = configuration[:base] if _base.nil? and configuration
398: _base ||= base_inheritable(true)
399: [prefix, _base].find_all do |component|
400: !component.blank?
401: end.join(",")
402: end
# File lib/active_ldap/base.rb, line 405
405: def base=(value)
406: self.base_without_parsed_cache_clear = value
407: @parsed_base = nil
408: end
# File lib/active_ldap/base.rb, line 427
427: def base_class
428: if self == Base or superclass == Base
429: self
430: else
431: superclass.base_class
432: end
433: end
# File lib/active_ldap/base.rb, line 268
268: def self.class_local_attr_accessor(search_ancestors, *syms)
269: syms.flatten.each do |sym|
270: 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)
271: end
272: end
# File lib/active_ldap/base.rb, line 350
350: def create(attributes=nil, &block)
351: if attributes.is_a?(Array)
352: attributes.collect {|attrs| create(attrs, &block)}
353: else
354: object = new(attributes, &block)
355: object.save
356: object
357: end
358: end
# File lib/active_ldap/base.rb, line 435
435: def default_search_attribute
436: dn_attribute
437: 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/configuration.rb for defaults for each option
# File lib/active_ldap/base.rb, line 344
344: def establish_connection(config=nil)
345: super
346: ensure_logger
347: nil
348: end
# File lib/active_ldap/base.rb, line 439
439: def inspect
440: if self == Base
441: super
442: else
443: class_names = []
444: must = []
445: may = []
446: class_names = classes.collect do |object_class|
447: must.concat(object_class.must)
448: may.concat(object_class.may)
449: object_class.name
450: end
451: detail = ["objectClass:<#{class_names.join(', ')}>",
452: "must:<#{inspect_attributes(must)}>",
453: "may:<#{inspect_attributes(may)}>"].join(", ")
454: "#{super}(#{detail})"
455: end
456: 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 367
367: def ldap_mapping(options={})
368: options = options.symbolize_keys
369: validate_ldap_mapping_options(options)
370:
371: self.dn_attribute = options[:dn_attribute] || default_dn_attribute
372: self.dn_attribute = dn_attribute.to_s if dn_attribute.is_a?(Symbol)
373: self.prefix = options[:prefix] || default_prefix
374: self.scope = options[:scope]
375: self.required_classes = options[:classes]
376: self.recommended_classes = options[:recommended_classes]
377: self.excluded_classes = options[:excluded_classes]
378: self.sort_by = options[:sort_by]
379: self.order = options[:order]
380:
381: public_class_method :new
382: end
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 557
557: def initialize(attributes=nil)
558: init_base
559: @new_entry = true
560: initial_classes = required_classes | recommended_classes
561: case attributes
562: when nil
563: self.classes = initial_classes
564: when String, Array, DN
565: self.classes = initial_classes
566: self.dn = attributes
567: when Hash
568: classes, attributes = extract_object_class(attributes)
569: self.classes = classes | initial_classes
570: normalized_attributes = {}
571: attributes.each do |key, value|
572: real_key = to_real_attribute_name(key) || key
573: normalized_attributes[real_key] = value
574: end
575: self.dn = normalized_attributes.delete(dn_attribute)
576: self.attributes = normalized_attributes
577: else
578: format = _("'%s' must be either nil, DN value as ActiveLdap::DN, " \
579: "String or Array or attributes as Hash")
580: raise ArgumentError, format % attributes.inspect
581: end
582: yield self if block_given?
583: assert_dn_attribute
584: end
# File lib/active_ldap/base.rb, line 410
410: def parsed_base
411: @parsed_base ||= DN.parse(base)
412: end
# File lib/active_ldap/base.rb, line 415
415: def scope=(scope)
416: validate_scope(scope)
417: self.scope_without_validation = scope
418: end
# File lib/active_ldap/base.rb, line 420
420: def validate_scope(scope)
421: scope = scope.to_sym if scope.is_a?(String)
422: return if scope.nil? or scope.is_a?(Symbol)
423: raise ConfigurationError,
424: _("scope '%s' must be a Symbol") % scope.inspect
425: end
# File lib/active_ldap/base.rb, line 521
521: def default_dn_attribute
522: if name.empty?
523: dn_attribute = nil
524: parent_class = ancestors[1]
525: if parent_class.respond_to?(:dn_attribute)
526: dn_attribute = parent_class.dn_attribute
527: end
528: dn_attribute || "cn"
529: else
530: name.demodulize.underscore
531: end
532: end
# File lib/active_ldap/base.rb, line 534
534: def default_prefix
535: if name.empty?
536: nil
537: else
538: "ou=#{name.demodulize.pluralize}"
539: end
540: end
# File lib/active_ldap/base.rb, line 489
489: def ensure_logger
490: @@logger ||= configuration[:logger]
491: # Setup default logger to console
492: if @@logger.nil?
493: require 'logger'
494: @@logger = Logger.new(STDERR)
495: @@logger.progname = 'ActiveLdap'
496: @@logger.level = Logger::UNKNOWN
497: end
498: configuration[:logger] ||= @@logger
499: end
# File lib/active_ldap/base.rb, line 471
471: def inspect_attribute(attribute)
472: syntax = attribute.syntax
473: result = "#{attribute.name}"
474: if syntax and !syntax.description.blank?
475: result << ": #{syntax.description}"
476: end
477: properties = []
478: properties << "read-only" if attribute.read_only?
479: properties << "binary" if attribute.binary?
480: properties << "binary-required" if attribute.binary_required?
481: result << "(#{properties.join(', ')})" unless properties.empty?
482: result
483: end
# File lib/active_ldap/base.rb, line 459
459: def inspect_attributes(attributes)
460: inspected_attribute_names = {}
461: attributes.collect do |attribute|
462: if inspected_attribute_names.has_key?(attribute.name)
463: nil
464: else
465: inspected_attribute_names[attribute.name] = true
466: inspect_attribute(attribute)
467: end
468: end.compact.join(', ')
469: end
# File lib/active_ldap/base.rb, line 501
501: def instantiate(args)
502: dn, attributes, options = args
503: options ||= {}
504: if self.class == Class
505: klass = self.ancestors[0].to_s.split(':').last
506: real_klass = self.ancestors[0]
507: else
508: klass = self.class.to_s.split(':').last
509: real_klass = self.class
510: end
511:
512: obj = real_klass.allocate
513: conn = options[:connection] || connection
514: obj.connection = conn if conn != connection
515: obj.instance_eval do
516: initialize_by_ldap_data(dn, attributes)
517: end
518: obj
519: end
# File lib/active_ldap/base.rb, line 485
485: def validate_ldap_mapping_options(options)
486: options.assert_valid_keys(VALID_LDAP_MAPPING_OPTIONS)
487: 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 588
588: def ==(comparison_object)
589: comparison_object.equal?(self) or
590: (comparison_object.instance_of?(self.class) and
591: comparison_object.dn == dn and
592: !comparison_object.new_entry?)
593: end
# File lib/active_ldap/base.rb, line 866
866: def [](name, force_array=false)
867: if name == "dn"
868: array_of(dn, force_array)
869: else
870: get_attribute(name, force_array)
871: end
872: end
# File lib/active_ldap/base.rb, line 874
874: def []=(name, value)
875: set_attribute(name, value)
876: end
Return attribute methods so that a program can determine available attributes dynamically without schema awareness
# File lib/active_ldap/base.rb, line 620
620: def attribute_names(normalize=false)
621: entry_attribute.names(normalize)
622: end
# File lib/active_ldap/base.rb, line 624
624: def attribute_present?(name)
625: values = get_attribute(name, true)
626: !values.empty? or values.any? {|x| not (x and x.empty?)}
627: end
This returns the key value pairs in @data with all values cloned
# File lib/active_ldap/base.rb, line 785
785: def attributes
786: Marshal.load(Marshal.dump(@data))
787: 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 795
795: def attributes=(new_attributes)
796: return if new_attributes.nil?
797: _schema = _local_entry_attribute = nil
798: targets = remove_attributes_protected_from_mass_assignment(new_attributes)
799: targets.each do |key, value|
800: setter = "#{key}="
801: unless respond_to?(setter)
802: _schema ||= schema
803: attribute = _schema.attribute(key)
804: next if attribute.id.nil?
805: _local_entry_attribute ||= local_entry_attribute
806: _local_entry_attribute.register(attribute)
807: end
808: send(setter, value)
809: end
810: end
# File lib/active_ldap/base.rb, line 925
925: def base
926: [@base, base_of_class].compact.join(",")
927: end
# File lib/active_ldap/base.rb, line 930
930: def base=(object_local_base)
931: @dn = nil
932: @base = object_local_base
933: end
# File lib/active_ldap/base.rb, line 884
884: def bind(config_or_password={}, config_or_ignore=nil, &block)
885: if config_or_password.is_a?(String)
886: config = (config_or_ignore || {}).merge(:password => config_or_password)
887: else
888: config = config_or_password
889: end
890: config = {:bind_dn => dn, :allow_anonymous => false}.merge(config)
891: config[:password_block] ||= block if block_given?
892: establish_connection(config)
893:
894: before_connection = @connection
895: begin
896: @connection = nil
897: connection.connect
898: @connection = connection
899: clear_connection_based_cache
900: clear_association_cache
901: rescue ActiveLdap::Error
902: remove_connection
903: @connection = before_connection
904: raise
905: end
906: true
907: end
# File lib/active_ldap/base.rb, line 909
909: def clear_connection_based_cache
910: @schema = nil
911: @local_entry_attribute = nil
912: clear_object_class_based_cache
913: end
# File lib/active_ldap/base.rb, line 915
915: def clear_object_class_based_cache
916: @entry_attribute = nil
917: @real_names = {}
918: end
# File lib/active_ldap/base.rb, line 671
671: def default_search_attribute
672: self.class.default_search_attribute
673: end
# File lib/active_ldap/base.rb, line 687
687: def delete(options={})
688: super(dn, options)
689: end
# File lib/active_ldap/base.rb, line 659
659: def dn=(value)
660: set_attribute(dn_attribute, value)
661: @dn = nil
662: end
# File lib/active_ldap/base.rb, line 666
666: def dn_attribute
667: _dn_attribute = @dn_attribute || dn_attribute_of_class
668: to_real_attribute_name(_dn_attribute) || _dn_attribute
669: end
# File lib/active_ldap/base.rb, line 878
878: def each
879: @data.each do |key, values|
880: yield(key.dup, values.dup)
881: end
882: end
Delegates to ==
# File lib/active_ldap/base.rb, line 596
596: def eql?(comparison_object)
597: self == (comparison_object)
598: end
# File lib/active_ldap/base.rb, line 843
843: def have_attribute?(name, except=[])
844: real_name = to_real_attribute_name(name)
845: real_name and !except.include?(real_name)
846: end
# File lib/active_ldap/base.rb, line 946
946: def inspect
947: object_classes = entry_attribute.object_classes
948: inspected_object_classes = object_classes.collect do |object_class|
949: object_class.name
950: end.join(', ')
951: must_attributes = must.collect(&:name).sort.join(', ')
952: may_attributes = may.collect(&:name).sort.join(', ')
953: inspected_attributes = attribute_names.sort.collect do |name|
954: inspect_attribute(name)
955: end.join(', ')
956: result = "\#<#{self.class} objectClass:<#{inspected_object_classes}>, "
957: result << "must:<#{must_attributes}>, may:<#{may_attributes}>, "
958: result << "#{inspected_attributes}>"
959: result
960: 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 713
713: def method_missing(name, *args, &block)
714: key = name.to_s
715: case key
716: when /=$/
717: real_key = $PREMATCH
718: if have_attribute?(real_key, ['objectClass'])
719: if args.size != 1
720: raise ArgumentError,
721: _("wrong number of arguments (%d for 1)") % args.size
722: end
723: return set_attribute(real_key, *args, &block)
724: end
725: when /(?:(_before_type_cast)|(\?))?$/
726: real_key = $PREMATCH
727: before_type_cast = !$1.nil?
728: query = !$2.nil?
729: if have_attribute?(real_key, ['objectClass'])
730: if args.size > 1
731: raise ArgumentError,
732: _("wrong number of arguments (%d for 1)") % args.size
733: end
734: if before_type_cast
735: return get_attribute_before_type_cast(real_key, *args)[1]
736: elsif query
737: return get_attribute_as_query(real_key, *args)
738: else
739: return get_attribute(real_key, *args)
740: end
741: end
742: end
743: super
744: end
Add available attributes to the methods
# File lib/active_ldap/base.rb, line 747
747: def methods(inherited_too=true)
748: target_names = entry_attribute.all_names
749: target_names -= ['objectClass', 'objectClass'.underscore]
750: super + target_names.uniq.collect do |x|
751: [x, "#{x}=", "#{x}?", "#{x}_before_type_cast"]
752: end.flatten
753: end
# File lib/active_ldap/base.rb, line 849
849: def reload
850: clear_association_cache
851: _, attributes = search(:value => id).find do |_dn, _attributes|
852: dn == _dn
853: end
854: if attributes.nil?
855: raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
856: end
857:
858: @ldap_data.update(attributes)
859: classes, attributes = extract_object_class(attributes)
860: self.classes = classes
861: self.attributes = attributes
862: @new_entry = false
863: self
864: end
# File lib/active_ldap/base.rb, line 756
756: def respond_to?(name, include_priv=false)
757: return true if super
758:
759: name = name.to_s
760: return true if have_attribute?(name)
761: return false if /(?:=|\?|_before_type_cast)$/ !~ name
762: have_attribute?($PREMATCH)
763: end
Save and validate this object into LDAP either adding or replacing attributes TODO: Relative DN support
# File lib/active_ldap/base.rb, line 696
696: def save
697: create_or_update
698: end
# File lib/active_ldap/base.rb, line 700
700: def save!
701: unless create_or_update
702: raise EntryNotSaved, _("entry %s can't be saved") % dn
703: end
704: end
# File lib/active_ldap/base.rb, line 941
941: def scope=(scope)
942: self.class.validate_scope(scope)
943: @scope = scope
944: end
# File lib/active_ldap/base.rb, line 816
816: def to_ldif
817: Ldif.new([to_ldif_record]).to_s
818: end
# File lib/active_ldap/base.rb, line 812
812: def to_ldif_record
813: super(dn, normalize_data(@data))
814: end
# File lib/active_ldap/base.rb, line 820
820: def to_xml(options={})
821: root = options[:root] || self.class.name.underscore
822: result = "<#{root}>\n"
823: result << " <dn>#{dn}</dn>\n"
824: normalize_data(@data).sort_by {|key, values| key}.each do |key, values|
825: targets = []
826: values.each do |value|
827: if value.is_a?(Hash)
828: value.each do |option, real_value|
829: targets << [real_value, " #{option}=\"true\""]
830: end
831: else
832: targets << [value]
833: end
834: end
835: targets.sort_by {|value, attr| value}.each do |value, attr|
836: result << " <#{key}#{attr}>#{value}</#{key}>\n"
837: end
838: end
839: result << "</#{root}>\n"
840: result
841: end
Updates a given attribute and saves immediately
# File lib/active_ldap/base.rb, line 766
766: def update_attribute(name, value)
767: send("#{name}=", value)
768: save
769: end
This performs a bulk update of attributes and immediately calls save.
# File lib/active_ldap/base.rb, line 773
773: def update_attributes(attrs)
774: self.attributes = attrs
775: save
776: end
# File lib/active_ldap/base.rb, line 778
778: def update_attributes!(attrs)
779: self.attributes = attrs
780: save!
781: end
Returns the array form of a value, or not an array if false is passed in.
# File lib/active_ldap/base.rb, line 1201
1201: def array_of(value, to_a=true)
1202: case value
1203: when Array
1204: if to_a or value.size > 1
1205: value.collect {|v| array_of(v, false)}.compact
1206: else
1207: if value.empty?
1208: nil
1209: else
1210: array_of(value.first, to_a)
1211: end
1212: end
1213: when Hash
1214: if to_a
1215: [value]
1216: else
1217: result = {}
1218: value.each {|k, v| result[k] = array_of(v, to_a)}
1219: result
1220: end
1221: else
1222: to_a ? [value] : value
1223: end
1224: end
# File lib/active_ldap/base.rb, line 1296
1296: def assert_dn_attribute
1297: unless dn_attribute
1298: raise ConfigurationError,
1299: _("dn_attribute isn't set for this class: %s") % self.class
1300: end
1301: end
# File lib/active_ldap/base.rb, line 977
977: def attribute_name_resolvable_without_connection?
978: @entry_attribute and @local_entry_attribute
979: end
# File lib/active_ldap/base.rb, line 1278
1278: def collect_all_attributes(data)
1279: dn_attr = dn_attribute
1280: dn_value = data[dn_attr]
1281:
1282: attributes = []
1283: attributes.push([dn_attr, dn_value])
1284:
1285: oc_value = data['objectClass']
1286: attributes.push(['objectClass', oc_value])
1287: data.each do |key, value|
1288: next if value.empty? or key == 'objectClass' or key == dn_attr
1289:
1290: attributes.push([key, value])
1291: end
1292:
1293: attributes
1294: end
# File lib/active_ldap/base.rb, line 1241
1241: def collect_modified_attributes(ldap_data, data)
1242: attributes = []
1243: # Now that all the options will be treated as unique attributes
1244: # we can see what's changed and add anything that is brand-spankin'
1245: # new.
1246: ldap_data.each do |k, v|
1247: value = data[k] || []
1248:
1249: next if v == value
1250:
1251: # Create mod entries
1252: if value.empty?
1253: # Since some types do not have equality matching rules,
1254: # delete doesn't work
1255: # Replacing with nothing is equivalent.
1256: if !data.has_key?(k) and schema.attribute(k).binary_required?
1257: value = [{'binary' => []}]
1258: end
1259: else
1260: # Ditched delete then replace because attribs with no equality
1261: # match rules will fails
1262: end
1263: attributes.push([:replace, k, value])
1264: end
1265: data.each do |k, v|
1266: value = v || []
1267: next if ldap_data.has_key?(k) or value.empty?
1268:
1269: # Detect subtypes and account for them
1270: # REPLACE will function like ADD, but doesn't hit EQUALITY problems
1271: # TODO: Added equality(attr) to Schema
1272: attributes.push([:replace, k, value])
1273: end
1274:
1275: attributes
1276: end
# File lib/active_ldap/base.rb, line 1179
1179: def compute_dn(escape_dn_value=false)
1180: return base if @dn_is_base
1181:
1182: dn_value = id
1183: if dn_value.nil?
1184: raise DistinguishedNameNotSetError.new,
1185: _("%s's DN attribute (%s) isn't set") % [self, dn_attribute]
1186: end
1187: dn_value = DN.escape_value(dn_value) if escape_dn_value
1188: _base = base
1189: _base = nil if _base.empty?
1190: ["#{dn_attribute}=#{dn_value}", _base].compact.join(",")
1191: end
# File lib/active_ldap/base.rb, line 1331
1331: def create
1332: prepare_data_for_saving do |data, ldap_data|
1333: attributes = collect_all_attributes(data)
1334: add_entry(escaped_dn, attributes)
1335: @new_entry = false
1336: true
1337: end
1338: end
# File lib/active_ldap/base.rb, line 1303
1303: def create_or_update
1304: new_entry? ? create : update
1305: 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 1050
1050: def enforce_type(key, value)
1051: # Enforce attribute value formatting
1052: normalize_attribute(key, value)[1]
1053: end
# File lib/active_ldap/base.rb, line 981
981: def entry_attribute
982: @entry_attribute ||= connection.entry_attribute(@data["objectClass"] || [])
983: end
# File lib/active_ldap/base.rb, line 989
989: def extract_object_class(attributes)
990: classes = []
991: attrs = {}
992: attributes.each do |key, value|
993: key = key.to_s
994: if /\Aobject_?class\z/i =~ key
995: classes.concat(value.to_a)
996: else
997: attrs[key] = value
998: end
999: end
1000: [classes, attributes]
1001: end
# File lib/active_ldap/base.rb, line 1114
1114: def false_value?(value)
1115: value.nil? or value == false or value == [] or
1116: value == "false" or value == "FALSE" or value == ""
1117: end
Return the value of the attribute called by method_missing?
# File lib/active_ldap/base.rb, line 1070
1070: def get_attribute(name, force_array=false)
1071: name, value = get_attribute_before_type_cast(name, force_array)
1072: return value if name.nil?
1073: attribute = schema.attribute(name)
1074: type_cast(attribute, value)
1075: end
# File lib/active_ldap/base.rb, line 1105
1105: def get_attribute_as_query(name, force_array=false)
1106: name, value = get_attribute_before_type_cast(name, force_array)
1107: if force_array
1108: value.collect {|x| !false_value?(x)}
1109: else
1110: !false_value?(value)
1111: end
1112: end
# File lib/active_ldap/base.rb, line 1098
1098: def get_attribute_before_type_cast(name, force_array=false)
1099: name = to_real_attribute_name(name)
1100:
1101: value = @data[name] || []
1102: [name, array_of(value, force_array)]
1103: end
# File lib/active_ldap/base.rb, line 1003
1003: def init_base
1004: init_instance_variables
1005: end
# File lib/active_ldap/base.rb, line 1055
1055: def init_instance_variables
1056: @mutex = Mutex.new
1057: @data = {} # where the r/w entry data is stored
1058: @ldap_data = {} # original ldap entry data
1059: @dn_attribute = nil
1060: @base = nil
1061: @scope = nil
1062: @dn = nil
1063: @connection ||= nil
1064: clear_connection_based_cache
1065: end
# File lib/active_ldap/base.rb, line 1007
1007: def initialize_by_ldap_data(dn, attributes)
1008: init_base
1009: @dn = dn
1010: @new_entry = false
1011: @dn_is_base = false
1012: @ldap_data = attributes
1013: classes, attributes = extract_object_class(attributes)
1014: self.classes = classes
1015: self.dn = dn
1016: self.attributes = attributes
1017: yield self if block_given?
1018: assert_dn_attribute
1019: end
# File lib/active_ldap/base.rb, line 963
963: def inspect_attribute(name)
964: values = get_attribute(name, true)
965: values.collect do |value|
966: if value.is_a?(String) and value.length > 50
967: "#{value[0, 50]}...".inspect
968: elsif value.is_a?(Date) || value.is_a?(Time)
969: "#{value.to_s(:db)}"
970: else
971: value.inspect
972: end
973: end
974: "#{name}: #{values.inspect}"
975: end
# File lib/active_ldap/base.rb, line 1021
1021: def instantiate(args)
1022: dn, attributes, options = args
1023: options ||= {}
1024:
1025: obj = self.class.allocate
1026: obj.connection = options[:connection] || @connection
1027: obj.instance_eval do
1028: initialize_by_ldap_data(dn, attributes)
1029: end
1030: obj
1031: end
# File lib/active_ldap/base.rb, line 985
985: def local_entry_attribute
986: @local_entry_attribute ||= connection.entry_attribute([])
987: end
# File lib/active_ldap/base.rb, line 1226
1226: def normalize_data(data, except=[])
1227: _schema = schema
1228: result = {}
1229: data.each do |key, values|
1230: next if except.include?(key)
1231: real_name = to_real_attribute_name(key)
1232: next if real_name and except.include?(real_name)
1233: real_name ||= key
1234: next if _schema.attribute(real_name).id.nil?
1235: result[real_name] ||= []
1236: result[real_name].concat(enforce_type(real_name, values))
1237: end
1238: result
1239: end
# File lib/active_ldap/base.rb, line 1307
1307: def prepare_data_for_saving
1308: # Expand subtypes to real ldap_data attributes
1309: # We can't reuse @ldap_data because an exception would leave
1310: # an object in an unknown state
1311: ldap_data = normalize_data(@ldap_data)
1312:
1313: # Expand subtypes to real data attributes, but leave @data alone
1314: bad_attrs = @data.keys - attribute_names
1315: data = normalize_data(@data, bad_attrs)
1316:
1317: success = yield(data, ldap_data)
1318:
1319: if success
1320: @ldap_data = Marshal.load(Marshal.dump(data))
1321: # Delete items disallowed by objectclasses.
1322: # They should have been removed from ldap.
1323: bad_attrs.each do |remove_me|
1324: @ldap_data.delete(remove_me)
1325: end
1326: end
1327:
1328: success
1329: end
Set the value of the attribute called by method_missing?
# File lib/active_ldap/base.rb, line 1122
1122: def set_attribute(name, value)
1123: attr = to_real_attribute_name(name)
1124: attr, value = update_dn(attr, value) if attr == dn_attribute
1125: raise UnknownAttribute.new(name) if attr.nil?
1126:
1127: @data[attr] = value
1128: end
# File lib/active_ldap/base.rb, line 1154
1154: def split_dn_value(value)
1155: dn_value = relative_dn_value = nil
1156: begin
1157: dn_value = value if value.is_a?(DN)
1158: dn_value ||= DN.parse(value)
1159: rescue DistinguishedNameInvalid
1160: dn_value = DN.parse("#{dn_attribute}=#{value}")
1161: end
1162:
1163: begin
1164: relative_dn_value = dn_value - self.class.parsed_base
1165: if relative_dn_value.rdns.empty?
1166: val = []
1167: bases = dn_value.rdns
1168: else
1169: val, *bases = relative_dn_value.rdns
1170: end
1171: rescue ArgumentError
1172: val, *bases = dn_value.rdns
1173: end
1174:
1175: dn_attribute_name, dn_attribute_value = val.to_a[0]
1176: [dn_attribute_name, dn_attribute_value, bases]
1177: end
# File lib/active_ldap/base.rb, line 1033
1033: def to_real_attribute_name(name, allow_normalized_name=false)
1034: return name if name.nil?
1035: if allow_normalized_name
1036: entry_attribute.normalize(name, allow_normalized_name) ||
1037: local_entry_attribute.normalize(name, allow_normalized_name)
1038: else
1039: @real_names[name] ||=
1040: entry_attribute.normalize(name, false) ||
1041: local_entry_attribute.normalize(name, false)
1042: end
1043: end
# File lib/active_ldap/base.rb, line 1077
1077: def type_cast(attribute, value)
1078: case value
1079: when Hash
1080: result = {}
1081: value.each do |option, val|
1082: result[option] = type_cast(attribute, val)
1083: end
1084: if result.size == 1 and result.has_key?("binary")
1085: result["binary"]
1086: else
1087: result
1088: end
1089: when Array
1090: value.collect do |val|
1091: type_cast(attribute, val)
1092: end
1093: else
1094: attribute.type_cast(value)
1095: end
1096: end
# File lib/active_ldap/base.rb, line 1340
1340: def update
1341: prepare_data_for_saving do |data, ldap_data|
1342: attributes = collect_modified_attributes(ldap_data, data)
1343: modify_entry(escaped_dn, attributes)
1344: true
1345: end
1346: end
# File lib/active_ldap/base.rb, line 1130
1130: def update_dn(attr, value)
1131: @dn = nil
1132: @dn_is_base = false
1133: return [attr, nil] if value.blank?
1134:
1135: new_dn_attribute, new_value, bases = split_dn_value(value)
1136: if new_dn_attribute.nil? and new_value.nil?
1137: @dn_is_base = true
1138: @base = nil
1139: attr, value = bases[0].to_a[0]
1140: @dn_attribute = attr
1141: else
1142: new_dn_attribute = to_real_attribute_name(new_dn_attribute)
1143: if new_dn_attribute
1144: value = new_value
1145: @base = bases.empty? ? nil : DN.new(*bases).to_s
1146: if dn_attribute != new_dn_attribute
1147: @dn_attribute = attr = new_dn_attribute
1148: end
1149: end
1150: end
1151: [attr, value]
1152: end