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. - .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.
84 85 86 87 88 89 90 91 92 |
# File 'lib/ucb_ldap_entry.rb', line 84 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.
154 155 156 157 158 |
# File 'lib/ucb_ldap_entry.rb', line 154 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.
331 332 333 |
# File 'lib/ucb_ldap_entry.rb', line 331 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
253 254 255 |
# File 'lib/ucb_ldap_entry.rb', line 253 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.
221 222 223 224 225 |
# File 'lib/ucb_ldap_entry.rb', line 221 def create(args) args[:attributes][:objectclass] = object_classes net_ldap.add(args) or return false find_by_dn(args[:dn]) end |
.create!(args) ⇒ Object
Same as #create(), but raises DirectoryNotUpdated on failure.
237 238 239 |
# File 'lib/ucb_ldap_entry.rb', line 237 def create!(args) create(args) || raise(DirectoryNotUpdatedException) end |
.entity_name ⇒ Object
Schema entity name. Set in each subclass.
343 344 345 |
# File 'lib/ucb_ldap_entry.rb', line 343 def entity_name @entity_name end |
.find_by_dn(dn) ⇒ Object
Returns entry whose distinguised name is dn.
228 229 230 231 232 233 234 |
# File 'lib/ucb_ldap_entry.rb', line 228 def find_by_dn(dn) search( :base => dn, :scope => Net::LDAP::SearchScope_BaseObject, :filter => "objectClass=*" ).first end |
.make_search_filter(filter) ⇒ Object
263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/ucb_ldap_entry.rb', line 263 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.
336 337 338 |
# File 'lib/ucb_ldap_entry.rb', line 336 def net_ldap #:nodoc: UCB::LDAP.net_ldap end |
.object_classes ⇒ Object
Returns Array
of object classes making up this type of LDAP entity.
276 277 278 |
# File 'lib/ucb_ldap_entry.rb', line 276 def object_classes @object_classes ||= UCB::LDAP::Schema.schema_hash[entity_name]["objectClasses"] end |
.schema_attribute(attribute_name) ⇒ Object
297 298 299 300 |
# File 'lib/ucb_ldap_entry.rb', line 297 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.
285 286 287 288 |
# File 'lib/ucb_ldap_entry.rb', line 285 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.
292 293 294 295 |
# File 'lib/ucb_ldap_entry.rb', line 292 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'}
317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/ucb_ldap_entry.rb', line 317 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.
349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/ucb_ldap_entry.rb', line 349 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.
367 368 369 |
# File 'lib/ucb_ldap_entry.rb', line 367 def tree_base @tree_base end |
.tree_base=(tree_base) ⇒ Object
371 372 373 |
# File 'lib/ucb_ldap_entry.rb', line 371 def tree_base=(tree_base) @tree_base = tree_base end |
.unique_object_class ⇒ Object
280 281 282 |
# File 'lib/ucb_ldap_entry.rb', line 280 def unique_object_class @unique_object_class ||= UCB::LDAP::Schema.schema_hash[entity_name]["uniqueObjectClass"] end |
Instance Method Details
#assigned_attributes ⇒ Object
179 180 181 |
# File 'lib/ucb_ldap_entry.rb', line 179 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.
101 102 103 |
# File 'lib/ucb_ldap_entry.rb', line 101 def attributes @attributes end |
#canonical(string_or_symbol) ⇒ Object
:nodoc:
110 111 112 |
# File 'lib/ucb_ldap_entry.rb', line 110 def canonical(string_or_symbol) #:nodoc: self.class.canonical(string_or_symbol) end |
#delete ⇒ Object
Delete entry. Returns true
on sucess, false
on failure.
134 135 136 |
# File 'lib/ucb_ldap_entry.rb', line 134 def delete net_ldap.delete(:dn => dn) end |
#delete! ⇒ Object
Same as #delete() except raises DirectoryNotUpdated on failure.
139 140 141 |
# File 'lib/ucb_ldap_entry.rb', line 139 def delete! delete || raise(DirectoryNotUpdatedException) end |
#dn ⇒ Object
Returns the value of the Distinguished Name attribute.
106 107 108 |
# File 'lib/ucb_ldap_entry.rb', line 106 def dn attributes[canonical(:dn)] end |
#modify ⇒ Object
193 194 195 196 197 198 199 |
# File 'lib/ucb_ldap_entry.rb', line 193 def modify() if UCB::LDAP.net_ldap.modify(:dn => dn, :operations => modify_operations) @assigned_attributes = nil return true end false end |
#modify_operations ⇒ Object
183 184 185 186 187 188 189 190 191 |
# File 'lib/ucb_ldap_entry.rb', line 183 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
143 144 145 |
# File 'lib/ucb_ldap_entry.rb', line 143 def net_ldap self.class.net_ldap end |
#setter_method?(method) ⇒ Boolean
Returns true
if method is a “setter”, i.e., ends in “=”.
161 162 163 |
# File 'lib/ucb_ldap_entry.rb', line 161 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)
119 120 121 122 123 124 125 126 |
# File 'lib/ucb_ldap_entry.rb', line 119 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.
129 130 131 |
# File 'lib/ucb_ldap_entry.rb', line 129 def update_attributes!(attrs) update_attributes(attrs) || raise(DirectoryNotUpdatedException) end |
#value_getter(method) ⇒ Object
Called by method_missing() to get an attribute value.
166 167 168 169 170 |
# File 'lib/ucb_ldap_entry.rb', line 166 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.
173 174 175 176 177 |
# File 'lib/ucb_ldap_entry.rb', line 173 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 |