Class: UCB::LDAP::Entry
- Inherits:
-
Object
- Object
- UCB::LDAP::Entry
- Defined in:
- lib/ucb_ldap_entry.rb
Overview
UCB::LDAP::Entry
Abstract class representing an entry in the UCB LDAP directory. You won’t ever deal with Entry instances, but instead instances of Entry sub-classes.
Accessing LDAP Attributes
You will not see the attributes documented in the instance method section of the documentation for Entry sub-classes, even though you can access them as if they were instance methods.
person = Person.find_by_uid("123") #=> #<UCB::LDAP::Person ..>
people.givenname #=> ["John"]
Entry sub-classes may have convenience methods that allow for accessing attributes by friendly names:
person = Person.person_by_uid("123") #=> #<UCB::LDAP::Person ..>
person.firstname #=> "John"
See the sub-class documentation for specifics.
Single- / Multi-Value Attributes
Attribute values are returned as arrays or scalars based on how they are defined in the LDAP schema.
Entry subclasses may have convenience methods that return scalars even though the schema defines the unerlying attribute as multi-valued becuase in practice the are single-valued.
Attribute Types
Attribute values are stored as arrays of strings in LDAP, but when accessed through Entry sub-class methods are returned cast to their Ruby type as defined in the schema. Types are one of:
-
string
-
integer
-
boolean
-
datetime
Missing Attribute Values
If an attribute value is not present, the value returned depends on type and multi/single value field:
-
empty multi-valued attributes return an empty array ([])
-
empty booleans return
false
-
everything else returns
nil
if empty
Attempting to get or set an attribute value for an invalid attriubte name will raise a BadAttributeNameException.
Updating LDAP
If your bind has privleges for updating the directory you can update the directory using methods of Entry sub-classes. Make sure you call UCB::LDAP.authenticate before calling any update methods.
There are three pairs of update methods that behave like Rails ActiveRecord methods of the same name. These methods are fairly thin wrappers around standard LDAP update commands.
The “bang” methods (those ending in “!”) differ from their bangless counterparts in that the bang methods raise DirectoryNotUpdatedException
on failure, while the bangless return false
.
-
#create/#create! - class methods that do LDAP add
-
#update_attributes/#update_attributes! - instance methods that do LDAP modify
-
#delete/#delete! - instance methods that do LDAP delete
Direct Known Subclasses
Address, Affiliation, JobAppointment, Namespace, Org, Person, Service, StudentTerm
Class Method Summary collapse
-
.canonical(string_or_symbol) ⇒ Object
Returns the canonical representation of a symbol or string so we can look up attributes in a number of ways.
-
.combine_filters(filters, operator = '&') ⇒ Object
Returns a new Net::LDAP::Filter that is the result of combining filters using operator (filters is an
Array
of Net::LDAP::Filter). -
.create(args) ⇒ Object
Creates and returns new entry.
-
.create!(args) ⇒ Object
Same as #create(), but raises DirectoryNotUpdated on failure.
-
.entity_name ⇒ Object
Schema entity name.
-
.find_by_dn(dn) ⇒ Object
Returns entry whose distinguised name is dn.
-
.make_search_filter(filter) ⇒ Object
Returns Net::LDAP::Filter.
-
.net_ldap ⇒ Object
Returns underlying Net::LDAP instance.
-
.object_classes ⇒ Object
Returns
Array
of object classes making up this type of LDAP entity. -
.required_attributes ⇒ Object
returns an Array of symbols where each symbol is the name of a required attribute for the Entry.
-
.required_schema_attributes ⇒ Object
returns Hash of SchemaAttribute objects that are required for the Entry.
- .schema_attribute(attribute_name) ⇒ Object
-
.schema_attributes_array ⇒ Object
Returns an
Array
of Schema::Attribute for the entity. -
.schema_attributes_hash ⇒ Object
Returns as
Hash
whose keys are the canonical attribute names and whose values are the corresponding Schema::Attributes. -
.search(args = {}) ⇒ Object
Returns Array of UCB::LDAP::Entry for entries matching args.
-
.set_schema_attributes ⇒ Object
Want an array of Schema::Attributes as well as a hash of all possible variations on a name pointing to correct array element.
-
.tree_base ⇒ Object
Returns tree base for LDAP searches.
- .tree_base=(tree_base) ⇒ Object
- .unique_object_class ⇒ Object
Instance Method Summary collapse
- #assigned_attributes ⇒ Object
-
#attributes ⇒ Object
Hash
of attributes returned from underlying NET::LDAP::Entry instance. -
#canonical(string_or_symbol) ⇒ Object
:nodoc:.
-
#delete ⇒ Object
Delete entry.
-
#delete! ⇒ Object
Same as #delete() except raises DirectoryNotUpdated on failure.
-
#dn ⇒ Object
Returns the value of the Distinguished Name attribute.
-
#initialize(net_ldap_entry) ⇒ Entry
constructor
Returns new instance of UCB::LDAP::Entry.
-
#method_missing(method, *args) ⇒ Object
Used to get/set attribute values.
- #modify ⇒ Object
- #modify_operations ⇒ Object
- #net_ldap ⇒ Object
-
#setter_method?(method) ⇒ Boolean
Returns
true
if method is a “setter”, i.e., ends in “=”. -
#update_attributes(attrs) ⇒ Object
Update an existing entry.
-
#update_attributes!(attrs) ⇒ Object
Same as #update_attributes(), but raises DirectoryNotUpdated on failure.
-
#value_getter(method) ⇒ Object
Called by method_missing() to get an attribute value.
-
#value_setter(method, *args) ⇒ Object
Called by method_missing() to set an attribute value.
Constructor Details
#initialize(net_ldap_entry) ⇒ Entry
Returns new instance of UCB::LDAP::Entry. The argument net_ldap_entry is an instance of Net::LDAP::Entry.
You should not need to create any UCB::LDAP::Entry instances; they are created by calls to UCB::LDAP.search and friends.
87 88 89 90 91 92 93 94 95 |
# File 'lib/ucb_ldap_entry.rb', line 87 def initialize(net_ldap_entry) #:nodoc: # Don't store Net::LDAP entry in object since it uses the block # initialization method of Hash which can't be marshalled ... this # means it can't be stored in a Rails session. @attributes = {} net_ldap_entry.each do |attr, value| @attributes[canonical(attr)] = value.map{|v| v.dup} end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
Used to get/set attribute values.
If we can’t make an attribute name out of method, let regular method_missing() handle it.
170 171 172 173 174 |
# File 'lib/ucb_ldap_entry.rb', line 170 def method_missing(method, *args) #:nodoc: setter_method?(method) ? value_setter(method, *args) : value_getter(method) rescue BadAttributeNameException return super end |
Class Method Details
.canonical(string_or_symbol) ⇒ Object
Returns the canonical representation of a symbol or string so we can look up attributes in a number of ways.
393 394 395 |
# File 'lib/ucb_ldap_entry.rb', line 393 def canonical(string_or_symbol) string_or_symbol.to_s.downcase.to_sym end |
.combine_filters(filters, operator = '&') ⇒ Object
Returns a new Net::LDAP::Filter that is the result of combining filters using operator (filters is an Array
of Net::LDAP::Filter).
See Net::LDAP#& and Net::LDAP#| for details.
f1 = Net::LDAP::Filter.eq("lastname", "hansen")
f2 = Net::LDAP::Filter.eq("firstname", "steven")
combine_filters([f1, f2]) # same as: f1 & f2
combine_filters([f1, f2], '|') # same as: f1 | f2
279 280 281 |
# File 'lib/ucb_ldap_entry.rb', line 279 def combine_filters(filters, operator = '&') filters.inject{|accum, filter| accum.send(operator, filter)} end |
.create(args) ⇒ Object
Creates and returns new entry. Returns false
if unsuccessful. Sets :objectclass key of args[:attributes] to object_classes read from schema.
dn = "uid=999999,ou=people,dc=example,dc=com"
attr = {
:uid => "999999",
:mail => "[email protected]"
}
EntrySubClass.create(:dn => dn, :attributes => attr) #=> #<UCB::LDAP::EntrySubClass ..>
Caller is responsible for setting :dn and :attributes correctly, as well as any other validation.
243 244 245 246 247 248 |
# File 'lib/ucb_ldap_entry.rb', line 243 def create(args) args[:attributes][:objectclass] = object_classes result = net_ldap.add(args) result or return false find_by_dn(args[:dn]) end |
.create!(args) ⇒ Object
Same as #create(), but raises DirectoryNotUpdated on failure.
262 263 264 |
# File 'lib/ucb_ldap_entry.rb', line 262 def create!(args) create(args) || raise(DirectoryNotUpdatedException) end |
.entity_name ⇒ Object
Schema entity name. Set in each subclass.
409 410 411 |
# File 'lib/ucb_ldap_entry.rb', line 409 def entity_name @entity_name end |
.find_by_dn(dn) ⇒ Object
Returns entry whose distinguised name is dn.
252 253 254 255 256 257 258 |
# File 'lib/ucb_ldap_entry.rb', line 252 def find_by_dn(dn) search( :base => dn, :scope => Net::LDAP::SearchScope_BaseObject, :filter => "objectClass=*" ).first end |
.make_search_filter(filter) ⇒ Object
290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/ucb_ldap_entry.rb', line 290 def make_search_filter(filter) return filter if filter.instance_of? Net::LDAP::Filter return filter if filter.instance_of? String filters = [] # sort so result is predictable for unit test filter.keys.sort_by { |symbol| "#{symbol}" }.each do |attr| filters << Net::LDAP::Filter.eq("#{attr}", "#{filter[attr]}") end combine_filters(filters, "&") end |
.net_ldap ⇒ Object
Returns underlying Net::LDAP instance.
400 401 402 |
# File 'lib/ucb_ldap_entry.rb', line 400 def net_ldap #:nodoc: UCB::LDAP.net_ldap end |
.object_classes ⇒ Object
Returns Array
of object classes making up this type of LDAP entity.
304 305 306 |
# File 'lib/ucb_ldap_entry.rb', line 304 def object_classes @object_classes ||= UCB::LDAP::Schema.schema_hash[entity_name]["objectClasses"] end |
.required_attributes ⇒ Object
returns an Array of symbols where each symbol is the name of a required attribute for the Entry
315 316 317 |
# File 'lib/ucb_ldap_entry.rb', line 315 def required_attributes required_schema_attributes.keys end |
.required_schema_attributes ⇒ Object
returns Hash of SchemaAttribute objects that are required for the Entry. Each SchemaAttribute object is keyed to the attribute’s name.
Note: required_schema_attributes will not return aliases, it only returns the original attributes
Example:
Person.required_schema_attribues[:cn]
=> <UCB::LDAP::Schema::Attribute:0x11c6b68>
331 332 333 334 335 336 337 |
# File 'lib/ucb_ldap_entry.rb', line 331 def required_schema_attributes required_atts = schema_attributes_hash.reject { |key, value| !value.required? } required_atts.reject do |key, value| aliases = value.aliases.map { |a| canonical(a) } aliases.include?(key) end end |
.schema_attribute(attribute_name) ⇒ Object
356 357 358 359 |
# File 'lib/ucb_ldap_entry.rb', line 356 def schema_attribute(attribute_name) schema_attributes_hash[canonical(attribute_name)] || raise(BadAttributeNameException, "'#{attribute_name}' is not a recognized attribute name") end |
.schema_attributes_array ⇒ Object
Returns an Array
of Schema::Attribute for the entity.
342 343 344 345 |
# File 'lib/ucb_ldap_entry.rb', line 342 def schema_attributes_array @schema_attributes_array || set_schema_attributes @schema_attributes_array end |
.schema_attributes_hash ⇒ Object
Returns as Hash
whose keys are the canonical attribute names and whose values are the corresponding Schema::Attributes.
351 352 353 354 |
# File 'lib/ucb_ldap_entry.rb', line 351 def schema_attributes_hash @schema_attributes_hash || set_schema_attributes @schema_attributes_hash end |
.search(args = {}) ⇒ Object
Returns Array of UCB::LDAP::Entry for entries matching args. When called from a subclass, returns Array of subclass instances.
See Net::LDAP::search for more information on args.
Most common arguments are :base
and :filter
. Search methods of subclasses have default :base
that can be overriden.
See make_search_filter for :filter
options.
base = "ou=people,dc=berkeley,dc=edu"
entries = UCB::LDAP::Entry.search(:base => base, :filter => {:uid => '123'})
entries = UCB::LDAP::Entry.search(:base => base, :filter => {:sn => 'Doe', :givenname => 'John'}
377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/ucb_ldap_entry.rb', line 377 def search(args={}) args = args.dup args[:base] ||= tree_base args[:filter] = make_search_filter args[:filter] if args[:filter] results = [] net_ldap.search(args) do |entry| results << new(entry) end results end |
.set_schema_attributes ⇒ Object
Want an array of Schema::Attributes as well as a hash of all possible variations on a name pointing to correct array element.
417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/ucb_ldap_entry.rb', line 417 def set_schema_attributes @schema_attributes_array = [] @schema_attributes_hash = {} UCB::LDAP::Schema.schema_hash[entity_name]["attributes"].each do |k, v| sa = UCB::LDAP::Schema::Attribute.new(v.merge("name" => k)) @schema_attributes_array << sa [sa.name, sa.aliases].flatten.each do |name| @schema_attributes_hash[canonical(name)] = sa end end rescue raise "Error loading schema attributes for entity_name '#{entity_name}'" end |
.tree_base ⇒ Object
Returns tree base for LDAP searches. Subclasses each have their own value.
Can be overridden in #search by passing in a :base
parm.
437 438 439 |
# File 'lib/ucb_ldap_entry.rb', line 437 def tree_base @tree_base end |
.tree_base=(tree_base) ⇒ Object
441 442 443 |
# File 'lib/ucb_ldap_entry.rb', line 441 def tree_base=(tree_base) @tree_base = tree_base end |
.unique_object_class ⇒ Object
308 309 310 |
# File 'lib/ucb_ldap_entry.rb', line 308 def unique_object_class @unique_object_class ||= UCB::LDAP::Schema.schema_hash[entity_name]["uniqueObjectClass"] end |
Instance Method Details
#assigned_attributes ⇒ Object
201 202 203 |
# File 'lib/ucb_ldap_entry.rb', line 201 def assigned_attributes @assigned_attributes ||= {} end |
#attributes ⇒ Object
Hash
of attributes returned from underlying NET::LDAP::Entry instance. Hash keys are #canonical attribute names, hash values are attribute values as returned from LDAP, i.e. arrays.
You should most likely be referencing attributes as if they were instance methods rather than directly through this method. See top of this document.
106 107 108 |
# File 'lib/ucb_ldap_entry.rb', line 106 def attributes @attributes end |
#canonical(string_or_symbol) ⇒ Object
:nodoc:
117 118 119 |
# File 'lib/ucb_ldap_entry.rb', line 117 def canonical(string_or_symbol) #:nodoc: self.class.canonical(string_or_symbol) end |
#delete ⇒ Object
Delete entry. Returns true
on sucess, false
on failure.
146 147 148 |
# File 'lib/ucb_ldap_entry.rb', line 146 def delete net_ldap.delete(:dn => dn) end |
#delete! ⇒ Object
Same as #delete() except raises DirectoryNotUpdated on failure.
153 154 155 |
# File 'lib/ucb_ldap_entry.rb', line 153 def delete! delete || raise(DirectoryNotUpdatedException) end |
#dn ⇒ Object
Returns the value of the Distinguished Name attribute.
113 114 115 |
# File 'lib/ucb_ldap_entry.rb', line 113 def dn attributes[canonical(:dn)] end |
#modify ⇒ Object
215 216 217 218 219 220 221 |
# File 'lib/ucb_ldap_entry.rb', line 215 def modify() if UCB::LDAP.net_ldap.modify(:dn => dn, :operations => modify_operations) @assigned_attributes = nil return true end false end |
#modify_operations ⇒ Object
205 206 207 208 209 210 211 212 213 |
# File 'lib/ucb_ldap_entry.rb', line 205 def modify_operations ops = [] assigned_attributes.keys.sort_by{|k| k.to_s}.each do |key| value = assigned_attributes[key] op = value.nil? ? :delete : :replace ops << [op, key, value] end ops end |
#net_ldap ⇒ Object
157 158 159 |
# File 'lib/ucb_ldap_entry.rb', line 157 def net_ldap self.class.net_ldap end |
#setter_method?(method) ⇒ Boolean
Returns true
if method is a “setter”, i.e., ends in “=”.
179 180 181 |
# File 'lib/ucb_ldap_entry.rb', line 179 def setter_method?(method) method.to_s[-1, 1] == "=" end |
#update_attributes(attrs) ⇒ Object
Update an existing entry. Returns entry if successful else false.
attrs = {:attr1 => "new_v1", :attr2 => "new_v2"}
entry.update_attributes(attrs)
127 128 129 130 131 132 133 134 |
# File 'lib/ucb_ldap_entry.rb', line 127 def update_attributes(attrs) attrs.each{|k, v| self.send("#{k}=", v)} if modify() @attributes = self.class.find_by_dn(dn).attributes.dup return true end false end |
#update_attributes!(attrs) ⇒ Object
Same as #update_attributes(), but raises DirectoryNotUpdated on failure.
139 140 141 |
# File 'lib/ucb_ldap_entry.rb', line 139 def update_attributes!(attrs) update_attributes(attrs) || raise(DirectoryNotUpdatedException) end |
#value_getter(method) ⇒ Object
Called by method_missing() to get an attribute value.
186 187 188 189 190 |
# File 'lib/ucb_ldap_entry.rb', line 186 def value_getter(method) schema_attribute = self.class.schema_attribute(method) raw_value = attributes[canonical(schema_attribute.name)] schema_attribute.get_value(raw_value) end |
#value_setter(method, *args) ⇒ Object
Called by method_missing() to set an attribute value.
195 196 197 198 199 |
# File 'lib/ucb_ldap_entry.rb', line 195 def value_setter(method, *args) schema_attribute = self.class.schema_attribute(method.to_s.chop) attr_key = canonical(schema_attribute.name) assigned_attributes[attr_key] = schema_attribute.ldap_value(args[0]) end |