Class: JSS::LDAPServer
- Defined in:
- lib/jss-api/api_object/ldap_server.rb,
lib/jss-api.rb
Overview
An LDAP server in the JSS.
This class doesn’t curretly provide creation or updaing of LDAP server definitions in the JSS. Please use the JSS web UI.
However, it does provide methods for querying users and usergroups from LDAP servers, and checking group membership.
When an LDAPServer instance is created, if it uses anonymous binding for lookups (the Authentication Type is set to ‘none’) then the LDAP connection is established immediately. Otherwise, you must use the #connect method, and provide the appropriate password for the lookup account defined.
Since LDAP server connections are used to verify the validity of LDAP users & groups used in scopes, if you don’t connect to all LDAP servers before modifying any scope’s user & group limitations or exceptions, those new values may not be verifiable. Unverified limitations and exceptions, when sent to the API, will result in a REST 409 Conflict error if the user or group doesn’t exist. Unfortunately, 409 Conflict errors are very generic and don’t indicate the source of the problem (in this case, a non-existent user or group limitation or exception to the scope). The Scopable module tries to catch these errors and raise a more useful exception when they happen.
The class method LDAPServer.all_ldaps returns a Hash of JSS::LDAPServer instances. one for each server defined in the JSS.
The class methods LDAPServer.user_in_ldap? and LDAPServer.group_in_ldap? can be used to check all defined LDAP servers for a user or group. They are used by Scopable::Scope when adding user and groups to scope limitations and exceptions.
Within an LDAPServer instance, the methods #find_user and #find_group will return all matches in the server for a given search term.
Constant Summary collapse
- RSRC_BASE =
The base for REST resources of this class
"ldapservers"
- RSRC_LIST_KEY =
the hash key used for the JSON list output of all objects in the JSS
:ldap_servers
- RSRC_OBJECT_KEY =
The hash key used for the JSON object output. It’s also used in various error messages
:ldap_server
- VALID_DATA_KEYS =
these keys, as well as :id and :name, are present in valid API JSON data for this class
[]
- DEFAULT_PORT =
the default LDAP port
389
- SEARCH_SCOPES =
possible values for search scope
["All Subtrees", "First Level Only"]
- AUTH_TYPES =
possible authentication types
{'none' => :anonymous, 'simple' => :simple, 'CRAM-MD5' => :cram_md5, 'DIGEST-MD5' => :digest_md5 }
- REFERRAL_RESPONSES =
possible referral responses
['', nil, 'follow', 'ignore']
- OBJECT_CLASS_MAPPING_OPTIONS =
possible objectclass mapping options
["any", "all"]
- @@all_ldaps =
Class Variables
nil
Constants inherited from APIObject
APIObject::DEFAULT_LOOKUP_KEYS, APIObject::REQUIRED_DATA_KEYS
Instance Attribute Summary collapse
-
#authentication_type ⇒ String
readonly
What authentication method should be used?.
-
#connected ⇒ Boolean
(also: #connected?)
readonly
We we connected to this server at the moment?.
-
#hostanme ⇒ String
readonly
The hostname of the server.
-
#lookup_dn ⇒ String
readonly
The Distinguished Name of the account used for connections/lookups?.
-
#lookup_pw_sha256 ⇒ String
readonly
The password for the connection/lookup account, as a SHA256 digest.
-
#open_close_timeout ⇒ Integer
readonly
Timeout, in seconds, for opening LDAP connections.
-
#port ⇒ Integer
readonly
The port for ldap.
-
#referral_response ⇒ String
readonly
The referral response from the server.
-
#search_timeout ⇒ Integer
readonly
Timeout, in seconds, for search queries.
-
#use_ssl ⇒ Boolean
readonly
Should the connection use ssl?.
-
#use_wildcards ⇒ Boolean
readonly
Should searches use wildcards?.
-
#user_group_mappings ⇒ Hash<Symbol=>String>
readonly
The LDAP attributes mapped to various user group data.
-
#user_group_membership_mappings ⇒ Hash<Symbol=>String>
readonly
The LDAP attributes used to identify a user as a member of a group.
-
#user_mappings ⇒ Hash<Symbol=>String>
readonly
The LDAP attributes mapped to various user data.
Attributes inherited from APIObject
#id, #in_jss, #name, #rest_rsrc
Class Method Summary collapse
-
.all_ldaps(refresh = false) ⇒ Hash{String => JSS::LDAPServer}
JSS::LDAPServer instances for all defined servers.
-
.group_in_ldap?(group) ⇒ Boolean
Does the group exist in any LDAP server?.
-
.user_in_ldap?(user) ⇒ Boolean
Does the user exist in any LDAP server?.
Instance Method Summary collapse
-
#check_membership(user, group) ⇒ Boolean?
Is the user a member? Nil if unable to check.
-
#connect(pw = nil) ⇒ Boolean
The connect to this LDAP server for subsequent use of the #find_user, #find_group and #check_membership methods.
-
#find_group(group, exact = false, additional_filter = nil) ⇒ Array<Hash>
The @user_group_attrs_to_get for all groups matching the query.
-
#find_user(user, exact = false, additional_filter = nil) ⇒ Array<Hash>
The @user_attrs_to_get for all usernames matching the query.
-
#initialize(args = {}) ⇒ LDAPServer
constructor
See JSS::APIObject#initialize.
Methods inherited from APIObject
all, all_ids, all_names, #delete, get_name, map_all_ids_to, #save, xml_list
Constructor Details
#initialize(args = {}) ⇒ LDAPServer
See JSS::APIObject#initialize
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 271 def initialize (args = {}) require 'net/ldap' super @hostname = @init_data[:connection][:hostname] @port = @init_data[:connection][:port] @use_ssl = @init_data[:connection][:use_ssl] @authentication_type = AUTH_TYPES[@init_data[:connection][:authentication_type]] @open_close_timeout = @init_data[:connection][:open_close_timeout] @search_timeout = @init_data[:connection][:search_timeout] @referral_response = @init_data[:connection][:referral_response] @use_wildcards = @init_data[:connection][:use_wildcards] @lookup_dn = @init_data[:connection][:account][:distinguished_username] @lookup_pw_sha256 = @init_data[:connection][:account][:password_sha256] @user_mappings = @init_data[:mappings_for_users ][:user_mappings] @user_group_mappings = @init_data[:mappings_for_users ][:user_group_mappings] @user_group_membership_mappings = @init_data[:mappings_for_users ][:user_group_membership_mappings] # the ldap attributes to retrieve with user lookups # (all those defined in the user mappings) @user_attrs_to_get = { :username => @user_mappings[:map_username], :user_id => @user_mappings[:map_user_id], :department => @user_mappings[:map_department], :building => @user_mappings[:map_building], :room => @user_mappings[:map_room], :realname => @user_mappings[:map_realname], :phone => @user_mappings[:map_phone], :email_address => @user_mappings[:map_email_address], :position => @user_mappings[:map_position], :user_uuid => @user_mappings[:map_user_uuid] }.delete_if{|k,v| v.nil? } # and for groups.... @user_group_attrs_to_get = { :group_id => @user_group_mappings[:map_group_id], :group_name => @user_group_mappings[:map_group_name], :group_uuid => @user_group_mappings[:map_group_uuid] }.delete_if{|k,v| v.nil? } @connection = nil @connected = false # If we are using anonymous binding, connect now connect if @authentication_type == :anonymous end |
Instance Attribute Details
#authentication_type ⇒ String (readonly)
Returns what authentication method should be used?.
180 181 182 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 180 def authentication_type @authentication_type end |
#connected ⇒ Boolean (readonly) Also known as: connected?
Returns we we connected to this server at the moment?.
262 263 264 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 262 def connected @connected end |
#hostanme ⇒ String (readonly)
Returns the hostname of the server.
171 172 173 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 171 def hostanme @hostanme end |
#lookup_dn ⇒ String (readonly)
Returns the Distinguished Name of the account used for connections/lookups?.
183 184 185 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 183 def lookup_dn @lookup_dn end |
#lookup_pw_sha256 ⇒ String (readonly)
Returns the password for the connection/lookup account, as a SHA256 digest.
186 187 188 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 186 def lookup_pw_sha256 @lookup_pw_sha256 end |
#open_close_timeout ⇒ Integer (readonly)
Returns timeout, in seconds, for opening LDAP connections.
189 190 191 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 189 def open_close_timeout @open_close_timeout end |
#port ⇒ Integer (readonly)
Returns the port for ldap.
174 175 176 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 174 def port @port end |
#referral_response ⇒ String (readonly)
Returns the referral response from the server.
195 196 197 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 195 def referral_response @referral_response end |
#search_timeout ⇒ Integer (readonly)
Returns timeout, in seconds, for search queries.
192 193 194 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 192 def search_timeout @search_timeout end |
#use_ssl ⇒ Boolean (readonly)
Returns should the connection use ssl?.
177 178 179 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 177 def use_ssl @use_ssl end |
#use_wildcards ⇒ Boolean (readonly)
Returns should searches use wildcards?.
198 199 200 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 198 def use_wildcards @use_wildcards end |
#user_group_mappings ⇒ Hash<Symbol=>String> (readonly)
The LDAP attributes mapped to various user group data
The hash keys are:
-
:search_base =>
-
:search_scope =>
-
:object_classes =>
-
:map_object_class_to_any_or_all =>
-
:map_group_id =>
-
:map_group_name =>
-
:map_group_uuid =>
238 239 240 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 238 def user_group_mappings @user_group_mappings end |
#user_group_membership_mappings ⇒ Hash<Symbol=>String> (readonly)
The LDAP attributes used to identify a user as a member of a group
The hash keys are:
-
:user_group_membership_stored_in =>
-
:map_user_membership_use_dn =>
-
:map_group_membership_to_user_field =>
-
:group_id =>
-
:map_object_class_to_any_or_all =>
-
:append_to_username =>
-
:username =>
-
:object_classes =>
-
:use_dn =>
-
:search_base =>
-
:recursive_lookups =>
-
:search_scope =>
-
:map_user_membership_to_group_field =>
259 260 261 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 259 def user_group_membership_mappings @user_group_membership_mappings end |
#user_mappings ⇒ Hash<Symbol=>String> (readonly)
The LDAP attributes mapped to various user data
The hash keys are:
-
:search_base =>
-
:search_scope =>
-
:object_classes =>
-
:map_object_class_to_any_or_all =>
-
:map_username =>
-
:map_user_id =>
-
:map_department =>
-
:map_building =>
-
:map_room =>
-
:map_realname =>
-
:map_phone =>
-
:map_email_address =>
-
:map_position =>
-
:map_user_uuid =>
-
:append_to_email_results =>
222 223 224 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 222 def user_mappings @user_mappings end |
Class Method Details
.all_ldaps(refresh = false) ⇒ Hash{String => JSS::LDAPServer}
Returns JSS::LDAPServer instances for all defined servers.
97 98 99 100 101 102 103 104 105 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 97 def self.all_ldaps(refresh = false) @@all_ldaps = nil if refresh return @@all_ldaps if @@all_ldaps @@all_ldaps = {} JSS::LDAPServer.all.each { |svr| @@all_ldaps[svr[:name]] = JSS::LDAPServer.new(:id =>svr[:id])} @@all_ldaps end |
.group_in_ldap?(group) ⇒ Boolean
Returns does the group exist in any LDAP server?.
123 124 125 126 127 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 123 def self.group_in_ldap? (group) gotgroup = false self.all_ldaps.values.each{|ldap| gotgroup = true unless ldap.find_group(group, :exact).empty? } return gotgroup end |
.user_in_ldap?(user) ⇒ Boolean
Returns does the user exist in any LDAP server?.
112 113 114 115 116 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 112 def self.user_in_ldap? (user) gotuser = false self.all_ldaps.values.each{|ldap| gotuser = true unless ldap.find_user(user, :exact).empty? } return gotuser end |
Instance Method Details
#check_membership(user, group) ⇒ Boolean?
Implement checking groups membership in ‘other’ ldap area
Returns is the user a member? Nil if unable to check.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 449 def check_membership(user, group) raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected found_user = find_user(user, :exact)[0] found_group = find_group(group, :exact)[0] raise JSS::NoSuchItemError, "No user '#{user}' in LDAP." unless found_user raise JSS::NoSuchItemError, "No group '#{group}' in LDAP." unless found_group if @user_group_membership_mappings[:user_group_membership_stored_in] == "group object" if @user_group_membership_mappings[:map_user_membership_use_dn] return found_group[:members].include? found_user[:dn] else return found_group[:members].include? user end elsif @user_group_membership_mappings[:user_group_membership_stored_in] == "user object" if @user_group_membership_mappings[:use_dn] return found_user[:groups].include? found_group[:dn] else return found_user[:groups].include? group end else ### To do!! return nil # implement a search based on the "other" settings # This will be 3 searchs # - one for the username mapping in users # - one for the gid in groups # - one for a record linking them in the "other" search base end end |
#connect(pw = nil) ⇒ Boolean
The connect to this LDAP server for subsequent use of the #find_user, #find_group and #check_membership methods
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 501 def connect(pw = nil) unless @authentication_type == :anonymous # how do we get the password? password = if pw == :prompt JSS.prompt_for_password "Enter the password for the LDAP connection account '#{@lookup_dn}':" elsif pw.is_a?(Symbol) and pw.to_s.start_with?('stdin') pw.to_s =~ /^stdin(\d+)$/ line = $1 line ||= 2 JSS.stdin line else pw end raise JSS::InvalidDataError, "Incorrect password for LDAP connection account '#{@lookup_dn}'" unless @lookup_pw_sha256 == Digest::SHA2.new(256).update(password.to_s).to_s end # unless @connection = Net::LDAP.new :host => @hostname, :port => @port, :auth => {:method => @authentication_type, :username => @lookup_dn, :password => password } @connected = true end |
#find_group(group, exact = false, additional_filter = nil) ⇒ Array<Hash>
Returns The @user_group_attrs_to_get for all groups matching the query.
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 392 def find_group(group, exact = false, additional_filter = nil) raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected if @use_wildcards and not exact group_filter = Net::LDAP::Filter.contains(@user_group_mappings[:map_group_name], group) else group_filter = Net::LDAP::Filter.eq(@user_group_mappings[:map_group_name], group) end # limit the object classes ocs = @user_group_mappings[:object_classes].to_s.chomp.split(/,\s*/) anyall = @user_group_mappings[:map_object_class_to_any_or_all] oc_filter = Net::LDAP::Filter.eq("objectclass", ocs.shift) ocs.each do |oc| if anyall == "any" oc_filter = oc_filter | Net::LDAP::Filter.eq("objectclass", oc) else oc_filter = oc_filter & Net::LDAP::Filter.eq("objectclass", oc) end end full_filter = oc_filter & group_filter full_filter = full_filter & additional_filter if additional_filter treebase = @user_group_mappings[:search_base] ldap_attribs = @user_group_attrs_to_get.values # should we grab membership from the group? if @user_group_membership_mappings[:user_group_membership_stored_in] == "group object" and \ @user_group_membership_mappings[:map_user_membership_to_group_field] get_members = true ldap_attribs << @user_group_membership_mappings[:map_user_membership_to_group_field] end results = [] @connection.search(:base => treebase, :filter => full_filter, :attributes => ldap_attribs ) do |entry| hash = {:dn => entry.dn} @user_group_attrs_to_get.each do |k,attr| hash[k] = entry[attr][0] end hash[:members] = entry[@user_group_membership_mappings[:map_user_membership_to_group_field]] if get_members # to do, if the members are dns, convert to usernames results << hash end results end |
#find_user(user, exact = false, additional_filter = nil) ⇒ Array<Hash>
Returns The @user_attrs_to_get for all usernames matching the query.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
# File 'lib/jss-api/api_object/ldap_server.rb', line 334 def find_user(user, exact = false, additional_filter = nil) raise JSS::InvalidConnectionError, "Not connected to LDAP server '#{@name}'. Please use #connect first." unless @connected if @use_wildcards and not exact user_filter = Net::LDAP::Filter.contains(@user_mappings[:map_username], user) else user_filter = Net::LDAP::Filter.eq(@user_mappings[:map_username], user) end # limit the object classes ocs = @user_mappings[:object_classes].to_s.chomp.split(/,\s*/) anyall = @user_mappings[:map_object_class_to_any_or_all] oc_filter = Net::LDAP::Filter.eq("objectclass", ocs.shift) ocs.each do |oc| if anyall == "any" oc_filter = oc_filter | Net::LDAP::Filter.eq("objectclass", oc) else oc_filter = oc_filter & Net::LDAP::Filter.eq("objectclass", oc) end end full_filter = oc_filter & user_filter full_filter = full_filter & additional_filter if additional_filter treebase = @user_mappings[:search_base] ldap_attribs = @user_attrs_to_get.values # should we grab membership from the user? if @user_group_membership_mappings[:user_group_membership_stored_in] == "user object" and \ @user_group_membership_mappings[:map_group_membership_to_user_field] get_groups = true ldap_attribs << @user_group_membership_mappings[:map_group_membership_to_user_field] end results = [] @connection.search(:base => treebase, :filter => full_filter, :attributes => ldap_attribs ) do |entry| userhash = {:dn => entry.dn} @user_attrs_to_get.each do |k,attr| userhash[k] = entry[attr][0] end userhash[:groups] = entry[@user_group_membership_mappings[:map_group_membership_to_user_field]] if get_groups # to do - if the groups are dns, convert to groupnames results << userhash end results end |