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