Class: GitHub::Ldap
- Inherits:
-
Object
- Object
- GitHub::Ldap
- Extended by:
- Forwardable
- Includes:
- Instrumentation
- Defined in:
- lib/github/ldap.rb,
lib/github/ldap/url.rb,
lib/github/ldap/group.rb,
lib/github/ldap/domain.rb,
lib/github/ldap/filter.rb,
lib/github/ldap/server.rb,
lib/github/ldap/posix_group.rb,
lib/github/ldap/virtual_group.rb,
lib/github/ldap/instrumentation.rb,
lib/github/ldap/referral_chaser.rb,
lib/github/ldap/connection_cache.rb,
lib/github/ldap/member_search/base.rb,
lib/github/ldap/virtual_attributes.rb,
lib/github/ldap/user_search/default.rb,
lib/github/ldap/member_search/classic.rb,
lib/github/ldap/member_search/recursive.rb,
lib/github/ldap/membership_validators/base.rb,
lib/github/ldap/user_search/active_directory.rb,
lib/github/ldap/membership_validators/classic.rb,
lib/github/ldap/member_search/active_directory.rb,
lib/github/ldap/membership_validators/recursive.rb,
lib/github/ldap/membership_validators/active_directory.rb
Defined Under Namespace
Modules: Filter, Instrumentation, MemberSearch, MembershipValidators, UserSearch Classes: ConnectionCache, Domain, Group, PosixGroup, ReferralChaser, URL, VirtualAttributes, VirtualGroup
Constant Summary collapse
- ACTIVE_DIRECTORY_V51_OID =
Internal: The capability required to use ActiveDirectory features. See: msdn.microsoft.com/en-us/library/cc223359.aspx.
"1.2.840.113556.1.4.1670".freeze
- DEFAULT_FIXTURES_PATH =
Preconfigured user fixtures. If you want to use them for your own tests.
File.('fixtures.ldif', File.dirname(__FILE__))
- DEFAULT_SERVER_OPTIONS =
{ user_fixtures: DEFAULT_FIXTURES_PATH, user_domain: 'dc=github,dc=com', admin_user: 'uid=admin,dc=github,dc=com', admin_password: 'secret', quiet: true, port: 3897 }
Class Attribute Summary collapse
-
.ldap_server ⇒ Object
readonly
ldap_server: is the instance of the testing ldap server, you should never interact with it, but it’s used to grecefully stop it after your tests finalize.
-
.server_options ⇒ Object
readonly
server_options: is the options used to start the server, useful to know in development.
Instance Attribute Summary collapse
-
#admin_password ⇒ Object
readonly
Returns the value of attribute admin_password.
-
#admin_user ⇒ Object
readonly
Returns the value of attribute admin_user.
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
-
#instrumentation_service ⇒ Object
readonly
Returns the value of attribute instrumentation_service.
-
#member_search_strategy ⇒ Object
readonly
Returns the value of attribute member_search_strategy.
-
#membership_validator ⇒ Object
readonly
Returns the value of attribute membership_validator.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#search_domains ⇒ Object
readonly
Returns the value of attribute search_domains.
-
#uid ⇒ Object
readonly
Returns the value of attribute uid.
-
#user_search_strategy ⇒ Object
readonly
Returns the value of attribute user_search_strategy.
-
#virtual_attributes ⇒ Object
readonly
Returns the value of attribute virtual_attributes.
Class Method Summary collapse
-
.server_tmp ⇒ Object
Determine the temporal directory where the ldap server lives.
-
.start_server(options = {}) ⇒ Object
Start a testing server.
-
.stop_server ⇒ Object
Stop the testing server.
Instance Method Summary collapse
-
#capabilities ⇒ Object
Internal: Searches the host LDAP server’s Root DSE for capabilities and extensions.
-
#check_encryption(encryption) ⇒ Object
Internal - Determine whether to use encryption or not.
-
#configure_member_search_strategy(strategy = nil) ⇒ Object
Internal: Configure the member search strategy.
-
#configure_membership_validation_strategy(strategy = nil) ⇒ Object
Internal: Configure the membership validation strategy.
-
#configure_search_strategy(strategy = nil) ⇒ Object
Internal: Configure the member search and membership validation strategies.
-
#configure_user_search_strategy(strategy) ⇒ Object
Internal: Set the user search strategy that will be used by Domain#user?.
-
#configure_virtual_attributes(attributes) ⇒ Object
Internal - Configure virtual attributes for this server.
-
#domain(base_name) ⇒ Object
Public - Creates a new domain object to perform operations.
-
#group(base_name) ⇒ Object
Public - Creates a new group object to perform operations.
-
#initialize(options = {}) ⇒ Ldap
constructor
Build a new GitHub::Ldap instance.
-
#load_group(group_entry) ⇒ Object
Public - Create a new group object based on a Net::LDAP::Entry.
-
#posix_support_enabled? ⇒ Boolean
Public - Whether membership checks should include posixGroup filter conditions on ‘memberUid`.
-
#recursive_group_search_fallback? ⇒ Boolean
Public - Whether membership checks should recurse into nested groups when virtual attributes aren’t enabled.
-
#search(options, &block) ⇒ Object
Public - Search entries in the ldap server.
-
#test_connection ⇒ Object
Public - Utility method to check if the connection with the server can be stablished.
Constructor Details
#initialize(options = {}) ⇒ Ldap
Build a new GitHub::Ldap instance
## Connection
host: required string ldap server host address port: required string or number ldap server port hosts: an enumerable of pairs of hosts and corresponding ports with
which to attempt opening connections (default [[host, port]]). Overrides
host and port if set.
encryption: optional string. ‘ssl` or `tls`. nil by default admin_user: optional string ldap administrator user dn for authentication admin_password: optional string ldap administrator user password
## Behavior
uid: optional field name used to authenticate users. Defaults to ‘sAMAccountName` (what ActiveDirectory uses) virtual_attributes: optional. boolean true to use server’s virtual attributes. Hash to specify custom mapping. Default false. recursive_group_search_fallback: optional boolean whether membership checks should recurse into nested groups when virtual attributes aren’t enabled. Default false. posix_support: optional boolean ‘posixGroup` support. Default true. search_domains: optional array of string bases to search through
## Diagnostics
instrumentation_service: optional ActiveSupport::Notifications compatible object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/github/ldap.rb', line 83 def initialize( = {}) @uid = [:uid] || "sAMAccountName" # Keep a reference to these as default auth for a Global Catalog if needed @admin_user = [:admin_user] @admin_password = [:admin_password] @port = [:port] @connection = Net::LDAP.new({ host: [:host], port: [:port], hosts: [:hosts], instrumentation_service: [:instrumentation_service] }) if [:admin_user] && [:admin_password] @connection.authenticate([:admin_user], [:admin_password]) end if encryption = check_encryption([:encryption]) @connection.encryption(encryption) end configure_virtual_attributes([:virtual_attributes]) # enable fallback recursive group search unless option is false @recursive_group_search_fallback = ([:recursive_group_search_fallback] != false) # enable posixGroup support unless option is false @posix_support = ([:posix_support] != false) # search_domains is a connection of bases to perform searches # when a base is not explicitly provided. @search_domains = Array([:search_domains]) # configure both the membership validator and the member search strategies configure_search_strategy([:search_strategy]) # configure the strategy used by Domain#user? to look up a user entry for login configure_user_search_strategy([:user_search_strategy]) # enables instrumenting queries @instrumentation_service = [:instrumentation_service] end |
Class Attribute Details
.ldap_server ⇒ Object (readonly)
ldap_server: is the instance of the testing ldap server,
you should never interact with it,
but it's used to grecefully stop it after your tests finalize.
26 27 28 |
# File 'lib/github/ldap/server.rb', line 26 def ldap_server @ldap_server end |
.server_options ⇒ Object (readonly)
server_options: is the options used to start the server,
useful to know in development.
21 22 23 |
# File 'lib/github/ldap/server.rb', line 21 def @server_options end |
Instance Attribute Details
#admin_password ⇒ Object (readonly)
Returns the value of attribute admin_password.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def admin_password @admin_password end |
#admin_user ⇒ Object (readonly)
Returns the value of attribute admin_user.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def admin_user @admin_user end |
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def connection @connection end |
#instrumentation_service ⇒ Object (readonly)
Returns the value of attribute instrumentation_service.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def instrumentation_service @instrumentation_service end |
#member_search_strategy ⇒ Object (readonly)
Returns the value of attribute member_search_strategy.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def member_search_strategy @member_search_strategy end |
#membership_validator ⇒ Object (readonly)
Returns the value of attribute membership_validator.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def membership_validator @membership_validator end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def port @port end |
#search_domains ⇒ Object (readonly)
Returns the value of attribute search_domains.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def search_domains @search_domains end |
#uid ⇒ Object (readonly)
Returns the value of attribute uid.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def uid @uid end |
#user_search_strategy ⇒ Object (readonly)
Returns the value of attribute user_search_strategy.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def user_search_strategy @user_search_strategy end |
#virtual_attributes ⇒ Object (readonly)
Returns the value of attribute virtual_attributes.
48 49 50 |
# File 'lib/github/ldap.rb', line 48 def virtual_attributes @virtual_attributes end |
Class Method Details
.server_tmp ⇒ Object
Determine the temporal directory where the ldap server lives. If there is no temporal directory in the environment we create one in the base path.
Returns the path to the temporal directory.
57 58 59 60 61 62 63 64 65 66 |
# File 'lib/github/ldap/server.rb', line 57 def self.server_tmp tmp = ENV['TMPDIR'] || ENV['TEMPDIR'] if tmp.nil? tmp = 'tmp' Dir.mkdir(tmp) unless File.directory?('tmp') end tmp end |
.start_server(options = {}) ⇒ Object
Start a testing server. If there is already a server initialized it doesn’t do anything.
options: is a hash with the custom options for the server.
33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/github/ldap/server.rb', line 33 def self.start_server( = {}) @server_options = DEFAULT_SERVER_OPTIONS.merge() @server_options[:allow_anonymous] ||= false @server_options[:ldif] = @server_options[:user_fixtures] @server_options[:domain] = @server_options[:user_domain] @server_options[:tmpdir] ||= server_tmp @server_options[:quiet] = false if @server_options[:verbose] @ldap_server = Ladle::Server.new(@server_options) @ldap_server.start end |
.stop_server ⇒ Object
Stop the testing server. If there is no server started this method doesn’t do anything.
49 50 51 |
# File 'lib/github/ldap/server.rb', line 49 def self.stop_server ldap_server && ldap_server.stop end |
Instance Method Details
#capabilities ⇒ Object
Internal: Searches the host LDAP server’s Root DSE for capabilities and extensions.
Returns a Net::LDAP::Entry object.
223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/github/ldap.rb', line 223 def capabilities @capabilities ||= instrument "capabilities.github_ldap" do |payload| begin @connection.search_root_dse rescue Net::LDAP::LdapError => error payload[:error] = error # stubbed result Net::LDAP::Entry.new end end end |
#check_encryption(encryption) ⇒ Object
Internal - Determine whether to use encryption or not.
encryption: is the encryption method, either ‘ssl’, ‘tls’, ‘simple_tls’ or ‘start_tls’.
Returns the real encryption type.
241 242 243 244 245 246 247 248 249 250 |
# File 'lib/github/ldap.rb', line 241 def check_encryption(encryption) return unless encryption case encryption.downcase.to_sym when :ssl, :simple_tls :simple_tls when :tls, :start_tls :start_tls end end |
#configure_member_search_strategy(strategy = nil) ⇒ Object
Internal: Configure the member search strategy.
If no known strategy is provided, detects ActiveDirectory capabilities or falls back to the Recursive strategy by default.
Returns the selected strategy Class.
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/github/ldap.rb', line 336 def configure_member_search_strategy(strategy = nil) @member_search_strategy = case strategy.to_s when "classic" GitHub::Ldap::MemberSearch::Classic when "recursive" GitHub::Ldap::MemberSearch::Recursive when "active_directory" GitHub::Ldap::MemberSearch::ActiveDirectory else # fallback to detection, defaulting to recursive strategy if active_directory_capability? GitHub::Ldap::MemberSearch::ActiveDirectory else GitHub::Ldap::MemberSearch::Recursive end end end |
#configure_membership_validation_strategy(strategy = nil) ⇒ Object
Internal: Configure the membership validation strategy.
If no known strategy is provided, detects ActiveDirectory capabilities or falls back to the Recursive strategy by default.
Returns the membership validator strategy Class.
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/github/ldap.rb', line 288 def configure_membership_validation_strategy(strategy = nil) @membership_validator = case strategy.to_s when "classic" GitHub::Ldap::MembershipValidators::Classic when "recursive" GitHub::Ldap::MembershipValidators::Recursive when "active_directory" GitHub::Ldap::MembershipValidators::ActiveDirectory else # fallback to detection, defaulting to recursive strategy if active_directory_capability? GitHub::Ldap::MembershipValidators::ActiveDirectory else GitHub::Ldap::MembershipValidators::Recursive end end end |
#configure_search_strategy(strategy = nil) ⇒ Object
Internal: Configure the member search and membership validation strategies.
TODO: Inline the logic in these two methods here.
Returns nothing.
274 275 276 277 278 279 280 |
# File 'lib/github/ldap.rb', line 274 def configure_search_strategy(strategy = nil) # configure which strategy should be used to validate user membership configure_membership_validation_strategy(strategy) # configure which strategy should be used for member search configure_member_search_strategy(strategy) end |
#configure_user_search_strategy(strategy) ⇒ Object
Internal: Set the user search strategy that will be used by
Domain#user?.
strategy - Can be either ‘default’ or ‘global_catalog’.
'default' strategy will search the configured
domain controller with a search base relative
to the controller's domain context.
'global_catalog' will search the entire forest
using Active Directory's Global Catalog
functionality.
317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/github/ldap.rb', line 317 def configure_user_search_strategy(strategy) @user_search_strategy = case strategy.to_s when "default" GitHub::Ldap::UserSearch::Default.new(self) when "global_catalog" GitHub::Ldap::UserSearch::ActiveDirectory.new(self) else GitHub::Ldap::UserSearch::Default.new(self) end end |
#configure_virtual_attributes(attributes) ⇒ Object
Internal - Configure virtual attributes for this server. If the option is ‘true`, we’ll use the default virual attributes. If it’s a Hash we’ll map the attributes in the hash.
attributes: is the option set when Ldap is initialized.
Returns a VirtualAttributes.
259 260 261 262 263 264 265 266 267 |
# File 'lib/github/ldap.rb', line 259 def configure_virtual_attributes(attributes) @virtual_attributes = if attributes == true VirtualAttributes.new(true) elsif attributes.is_a?(Hash) VirtualAttributes.new(true, attributes) else VirtualAttributes.new(false) end end |
#domain(base_name) ⇒ Object
Public - Creates a new domain object to perform operations
base_name: is the dn of the base root.
Returns a new Domain object.
164 165 166 |
# File 'lib/github/ldap.rb', line 164 def domain(base_name) Domain.new(self, base_name, @uid) end |
#group(base_name) ⇒ Object
Public - Creates a new group object to perform operations
base_name: is the dn of the base root.
Returns a new Group object. Returns nil if the dn is not in the server.
174 175 176 177 178 179 |
# File 'lib/github/ldap.rb', line 174 def group(base_name) entry = domain(base_name).bind return unless entry load_group(entry) end |
#load_group(group_entry) ⇒ Object
Public - Create a new group object based on a Net::LDAP::Entry.
group_entry: is a Net::LDAP::Entry.
Returns a Group, PosixGroup or VirtualGroup object.
186 187 188 189 190 191 192 193 194 |
# File 'lib/github/ldap.rb', line 186 def load_group(group_entry) if @virtual_attributes.enabled? VirtualGroup.new(self, group_entry) elsif posix_support_enabled? && PosixGroup.valid?(group_entry) PosixGroup.new(self, group_entry) else Group.new(self, group_entry) end end |
#posix_support_enabled? ⇒ Boolean
Public - Whether membership checks should include posixGroup filter conditions on ‘memberUid`. Configurable since some LDAP servers don’t handle unsupported attribute queries gracefully.
Enable by passing :posix_support => true.
Returns true, false, or nil (assumed false).
145 146 147 |
# File 'lib/github/ldap.rb', line 145 def posix_support_enabled? @posix_support end |
#recursive_group_search_fallback? ⇒ Boolean
Public - Whether membership checks should recurse into nested groups when virtual attributes aren’t enabled. The fallback search has poor performance characteristics in some cases, in which case this should be disabled by passing :recursive_group_search_fallback => false.
Returns true or false.
134 135 136 |
# File 'lib/github/ldap.rb', line 134 def recursive_group_search_fallback? @recursive_group_search_fallback end |
#search(options, &block) ⇒ Object
Public - Search entries in the ldap server.
options: is a hash with the same options that Net::LDAP::Connection#search supports. block: is an optional block to pass to the search.
Returns an Array of Net::LDAP::Entry.
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/github/ldap.rb', line 202 def search(, &block) instrument "search.github_ldap", .dup do |payload| result = if [:base] @connection.search(, &block) else search_domains.each_with_object([]) do |base, result| rs = @connection.search(.merge(:base => base), &block) result.concat Array(rs) unless rs == false end end return [] if result == false Array(result) end end |
#test_connection ⇒ Object
Public - Utility method to check if the connection with the server can be stablished. It tries to bind with the ldap auth default configuration.
Returns an OpenStruct with ‘code` and `message`. If `code` is 0, the operation succeeded and there is no message.
154 155 156 157 |
# File 'lib/github/ldap.rb', line 154 def test_connection @connection.bind last_operation_result end |