| 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, :sort_by, :order] |
| 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 |
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 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
# 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
# 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
# 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
# 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 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 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
# 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
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 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
# File lib/active_ldap/base.rb, line 328
328: def scope=(scope)
329: validate_scope(scope)
330: self.scope_without_validation = scope
331: end
# 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
# 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
# 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
# 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
# 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
# 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
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 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
# 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
# File lib/active_ldap/base.rb, line 753
753: def []=(name, value)
754: set_attribute(name, value)
755: end
Return attribute methods so that a program can determine available attributes dynamically without schema awareness
# 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
# 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
# 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.
# 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
# File lib/active_ldap/base.rb, line 795
795: def base
796: [@base, base_of_class].compact.join(",")
797: end
# File lib/active_ldap/base.rb, line 800
800: def base=(object_local_base)
801: @base = object_local_base
802: end
# 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
# File lib/active_ldap/base.rb, line 554
554: def default_search_attribute
555: self.class.default_search_attribute
556: end
# File lib/active_ldap/base.rb, line 570
570: def delete(options={})
571: super(dn, options)
572: end
Return the authoritative dn
# 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
# File lib/active_ldap/base.rb, line 544
544: def dn=(value)
545: set_attribute(dn_attribute, value)
546: end
# File lib/active_ldap/base.rb, line 550
550: def dn_attribute
551: @dn_attribute || dn_attribute_of_class
552: end
# 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 ==
# File lib/active_ldap/base.rb, line 462
462: def eql?(comparison_object)
463: self == (comparison_object)
464: end
# 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
# File lib/active_ldap/base.rb, line 815
815: def inspect
816: abbreviate_instance_variables do
817: super
818: end
819: end
# File lib/active_ldap/base.rb, line 474
474: def may
475: ensure_apply_object_class
476: @may
477: 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 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
# 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
# File lib/active_ldap/base.rb, line 479
479: def must
480: ensure_apply_object_class
481: @must
482: end
# 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
# 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
# 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 and validate this object into LDAP either adding or replacing attributes TODO: Relative DN support
# File lib/active_ldap/base.rb, line 579
579: def save
580: create_or_update
581: end
# 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
# File lib/active_ldap/base.rb, line 810
810: def scope=(scope)
811: self.class.validate_scope(scope)
812: @scope = scope
813: end
# File lib/active_ldap/base.rb, line 695
695: def to_ldif
696: super(dn, normalize_data(@data))
697: end
# 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
# 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.
# File lib/active_ldap/base.rb, line 657
657: def update_attributes(attrs)
658: self.attributes = attrs
659: save
660: end
# File lib/active_ldap/base.rb, line 662
662: def update_attributes!(attrs)
663: self.attributes = attrs
664: save!
665: end
# 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
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.
# 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
Returns the array form of a value, or not an array if false is passed in.
# 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
# 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
# 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
# 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
# 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
# File lib/active_ldap/base.rb, line 1229
1229: def create_or_update
1230: new_entry? ? create : update
1231: end
Make a method entry for every alias of a valid attribute and map it onto the first attribute passed in.
# 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 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 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
# 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
# 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
# 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
Return the value of the attribute called by method_missing?
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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 the value of the attribute called by method_missing?
# 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
# 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
# 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
# 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
# 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
# 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