Class: GitHub::Ldap
- Inherits:
-
Object
- Object
- GitHub::Ldap
- Extended by:
- Forwardable
- Includes:
- Instrumentation
- Defined in:
- lib/github/ldap.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/member_search/base.rb,
lib/github/ldap/virtual_attributes.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/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 Classes: Domain, Group, PosixGroup, 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
-
#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.
-
#search_domains ⇒ Object
readonly
Returns the value of attribute search_domains.
-
#uid ⇒ Object
readonly
Returns the value of attribute uid.
-
#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_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 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
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/github/ldap.rb', line 69 def initialize( = {}) @uid = [:uid] || "sAMAccountName" @connection = Net::LDAP.new({ host: [:host], port: [:port], 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]) # 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
#instrumentation_service ⇒ Object (readonly)
Returns the value of attribute instrumentation_service.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 def instrumentation_service @instrumentation_service end |
#member_search_strategy ⇒ Object (readonly)
Returns the value of attribute member_search_strategy.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 def member_search_strategy @member_search_strategy end |
#membership_validator ⇒ Object (readonly)
Returns the value of attribute membership_validator.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 def membership_validator @membership_validator end |
#search_domains ⇒ Object (readonly)
Returns the value of attribute search_domains.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 def search_domains @search_domains end |
#uid ⇒ Object (readonly)
Returns the value of attribute uid.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 def uid @uid end |
#virtual_attributes ⇒ Object (readonly)
Returns the value of attribute virtual_attributes.
42 43 44 |
# File 'lib/github/ldap.rb', line 42 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.
200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/github/ldap.rb', line 200 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.
218 219 220 221 222 223 224 225 226 227 |
# File 'lib/github/ldap.rb', line 218 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.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/github/ldap.rb', line 291 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.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/github/ldap.rb', line 265 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.
251 252 253 254 255 256 257 |
# File 'lib/github/ldap.rb', line 251 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_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.
236 237 238 239 240 241 242 243 244 |
# File 'lib/github/ldap.rb', line 236 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.
141 142 143 |
# File 'lib/github/ldap.rb', line 141 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.
151 152 153 154 155 156 |
# File 'lib/github/ldap.rb', line 151 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.
163 164 165 166 167 168 169 170 171 |
# File 'lib/github/ldap.rb', line 163 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).
122 123 124 |
# File 'lib/github/ldap.rb', line 122 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.
111 112 113 |
# File 'lib/github/ldap.rb', line 111 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.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/github/ldap.rb', line 179 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.
131 132 133 134 |
# File 'lib/github/ldap.rb', line 131 def test_connection @connection.bind last_operation_result end |