Skip to content

Commit

Permalink
Merge pull request #3453 from bgeuken/ldap_con_tests
Browse files Browse the repository at this point in the history
Ldap con tests
  • Loading branch information
bgeuken committed Jul 27, 2017
2 parents 3d25131 + 3b0a1cc commit ce0d958
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 20 deletions.
38 changes: 18 additions & 20 deletions src/api/app/models/user_ldap_strategy.rb
Expand Up @@ -334,50 +334,48 @@ def self.initialize_ldap_con(user_name, password)
return unless defined?(CONFIG['ldap_servers'])
require 'ldap'
ldap_servers = CONFIG['ldap_servers'].split(":")
count = 0

max_ldap_attempts = CONFIG.has_key?('ldap_max_attempts') ? CONFIG['ldap_max_attempts'] : 10

while count < max_ldap_attempts
count += 1
# Do 10 attempts to connect to one of the configured LDAP servers. LDAP server
# to connect to is chosen randomly.
max_ldap_attempts.times do
server = ldap_servers[rand(ldap_servers.length)]
conn = try_ldap_con(server, user_name, password)
if !conn.nil? && conn.bound?
return conn
end

return conn if conn.try(:bound?)
end

Rails.logger.error("Unable to bind to any LDAP server: #{CONFIG['ldap_servers']}")
nil
end

def self.ldap_port
return CONFIG['ldap_port'] if CONFIG['ldap_port']

CONFIG['ldap_ssl'] == :on ? 636 : 389
end
private_class_method :ldap_port

def self.try_ldap_con(server, user_name, password)
# implicitly turn array into string
user_name = [user_name].flatten.join('')

Rails.logger.debug("Connecting to #{server} as '#{user_name}'")
port = ldap_port

begin
if CONFIG.has_key?('ldap_ssl') && CONFIG['ldap_ssl'] == :on
port = CONFIG.has_key?('ldap_port') ? CONFIG['ldap_port'] : 636
conn = LDAP::SSLConn.new(server, port)
if CONFIG['ldap_ssl'] == :on || CONFIG['ldap_start_tls'] == :on
conn = LDAP::SSLConn.new(server, port, CONFIG['ldap_start_tls'] == :on)
else
port = CONFIG.has_key?('ldap_port') ? CONFIG['ldap_port'] : 389
# Use LDAP StartTLS. By default start_tls is off.
if CONFIG.has_key?('ldap_start_tls') && CONFIG['ldap_start_tls'] == :on
conn = LDAP::SSLConn.new(server, port, true)
else
conn = LDAP::Conn.new(server, port)
end
conn = LDAP::Conn.new(server, port)
end
conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
if CONFIG.has_key?('ldap_referrals') && CONFIG['ldap_referrals'] == :off
conn.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_OFF)
end
conn.bind(user_name, password)
rescue LDAP::ResultError
if !conn.nil? && conn.bound?
conn.unbind
end
conn.unbind if conn.try(:bound?)
Rails.logger.info("Not bound as #{user_name}: #{conn.err2string(conn.err)}")
return
end
Expand Down
43 changes: 43 additions & 0 deletions src/api/spec/models/user_ldap_strategy_spec.rb
@@ -1,4 +1,5 @@
require 'rails_helper'
require 'ldap'

RSpec.describe UserLdapStrategy do
let(:dn_string_no_uid) { 'cn=jsmith,ou=Promotions,dc=noam,dc=com' }
Expand Down Expand Up @@ -87,4 +88,46 @@
end
end
end

describe '.initialize_ldap_con' do
context 'when no ldap_servers are configured' do
it { expect(UserLdapStrategy.initialize_ldap_con('tux', 'tux_password')).to be nil }
end

context 'when ldap servers are configured' do
before do
stub_const('CONFIG', CONFIG.merge({ 'ldap_servers' => 'my_ldap_server.com' }))
end

context 'for SSL' do
include_context 'setup ldap mock', for_ssl: true

before do
stub_const('CONFIG', CONFIG.merge({ 'ldap_ssl' => :on }))
end

it_should_behave_like 'a ldap connection'
end

context 'configured for TSL' do
include_context 'setup ldap mock', for_ssl: true, start_tls: true

before do
stub_const('CONFIG', CONFIG.merge({ 'ldap_start_tls' => :on }))
end

it_should_behave_like 'a ldap connection'
end

context 'not configured for TSL or SSL' do
include_context 'setup ldap mock'

before do
stub_const('CONFIG', CONFIG.merge({ 'ldap_ssl' => :off }))
end

it_should_behave_like 'a ldap connection'
end
end
end
end
24 changes: 24 additions & 0 deletions src/api/spec/support/shared_contexts/setup_ldap_mock.rb
@@ -0,0 +1,24 @@
RSpec.shared_context 'setup ldap mock' do |opts|
let(:ldap_mock) { double(:ldap) }

before do
opts ||= {}
expected_port = (opts[:for_ssl] ? 636 : 389)
connection = (opts[:for_ssl] ? LDAP::SSLConn : LDAP::Conn)

stub_const('CONFIG', CONFIG.merge({ 'ldap_servers' => 'my_ldap_server.com' }))

allow(ldap_mock).to receive(:set_option).with(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_OFF)
allow(ldap_mock).to receive(:set_option).with(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)

if opts[:for_ssl]
allow(connection).to receive(:new).with(
'my_ldap_server.com', expected_port, opts[:start_tls] == true
).and_return(ldap_mock)
else
allow(connection).to receive(:new).with(
'my_ldap_server.com', expected_port
).and_return(ldap_mock)
end
end
end
34 changes: 34 additions & 0 deletions src/api/spec/support/shared_examples/a_ldap_connection.rb
@@ -0,0 +1,34 @@
RSpec.shared_examples 'a ldap connection' do
context 'when a connection can be established' do
before do
allow(ldap_mock).to receive(:bind).with('tux', 'tux_password')
allow(ldap_mock).to receive(:bound?).and_return(true)
end

it 'returns the connection object' do
expect(UserLdapStrategy.initialize_ldap_con('tux', 'tux_password')).to be ldap_mock
end
end

context 'when no connection can be established' do
before do
allow(ldap_mock).to receive(:bind).with('tux', 'tux_password')
allow(ldap_mock).to receive(:bound?).and_return(false)
end

it { expect(UserLdapStrategy.initialize_ldap_con('tux', 'tux_password')).to be nil }
end

context 'when establishing a connection fails with an error' do
let(:err_object) { double(error: 'something happened') }

before do
allow(ldap_mock).to receive(:bound?)
allow(ldap_mock).to receive(:bind).with('tux', 'tux_password').and_raise(LDAP::ResultError)
allow(ldap_mock).to receive(:err).and_return(err_object)
allow(ldap_mock).to receive(:err2string).with(err_object).and_return('something happened')
end

it { expect(UserLdapStrategy.initialize_ldap_con('tux', 'tux_password')).to be nil }
end
end

0 comments on commit ce0d958

Please sign in to comment.