mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 01:58:41 -05:00
Merge pull request #267 from mattkirby/multiple_ldap_search
(POOLER-113) Add support for multiple LDAP search bases
This commit is contained in:
commit
8be578493a
9 changed files with 239 additions and 84 deletions
|
|
@ -4,6 +4,7 @@ module Vmpooler
|
|||
require 'date'
|
||||
require 'json'
|
||||
require 'open-uri'
|
||||
require 'net/ldap'
|
||||
require 'rbvmomi'
|
||||
require 'redis'
|
||||
require 'sinatra/base'
|
||||
|
|
|
|||
|
|
@ -54,35 +54,60 @@ module Vmpooler
|
|||
return false
|
||||
end
|
||||
|
||||
def authenticate_ldap(port, host, user_object, base, username_str, password_str)
|
||||
ldap = Net::LDAP.new(
|
||||
:host => host,
|
||||
:port => port,
|
||||
:encryption => {
|
||||
:method => :start_tls,
|
||||
:tls_options => { :ssl_version => 'TLSv1' }
|
||||
},
|
||||
:base => base,
|
||||
:auth => {
|
||||
:method => :simple,
|
||||
:username => "#{user_object}=#{username_str},#{base}",
|
||||
:password => password_str
|
||||
}
|
||||
)
|
||||
|
||||
return true if ldap.bind
|
||||
return false
|
||||
end
|
||||
|
||||
def authenticate(auth, username_str, password_str)
|
||||
case auth['provider']
|
||||
when 'dummy'
|
||||
return (username_str != password_str)
|
||||
when 'ldap'
|
||||
require 'rubygems'
|
||||
require 'net/ldap'
|
||||
ldap_base = auth[:ldap]['base']
|
||||
ldap_port = auth[:ldap]['port'] || 389
|
||||
|
||||
ldap = Net::LDAP.new(
|
||||
:host => auth[:ldap]['host'],
|
||||
:port => auth[:ldap]['port'] || 389,
|
||||
:encryption => {
|
||||
:method => :start_tls,
|
||||
:tls_options => { :ssl_version => 'TLSv1' }
|
||||
},
|
||||
:base => auth[:ldap]['base'],
|
||||
:auth => {
|
||||
:method => :simple,
|
||||
:username => "#{auth[:ldap]['user_object']}=#{username_str},#{auth[:ldap]['base']}",
|
||||
:password => password_str
|
||||
}
|
||||
)
|
||||
|
||||
if ldap.bind
|
||||
return true
|
||||
if ldap_base.is_a? Array
|
||||
ldap_base.each do |search_base|
|
||||
result = authenticate_ldap(
|
||||
ldap_port,
|
||||
auth[:ldap]['host'],
|
||||
auth[:ldap]['user_object'],
|
||||
search_base,
|
||||
username_str,
|
||||
password_str,
|
||||
)
|
||||
return true if result == true
|
||||
end
|
||||
else
|
||||
result = authenticate_ldap(
|
||||
ldap_port,
|
||||
auth[:ldap]['host'],
|
||||
auth[:ldap]['user_object'],
|
||||
ldap_base,
|
||||
username_str,
|
||||
password_str,
|
||||
)
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def export_tags(backend, hostname, tags)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vmpooler::API::V1 do
|
||||
include Rack::Test::Methods
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def has_set_tag?(vm, tag, value)
|
||||
value == redis.hget("vmpooler__vm__#{vm}", "tag:#{tag}")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vmpooler::API::V1 do
|
||||
include Rack::Test::Methods
|
||||
|
||||
|
|
@ -39,7 +29,15 @@ describe Vmpooler::API::V1 do
|
|||
end
|
||||
|
||||
context '(auth configured)' do
|
||||
let(:config) { { auth: true } }
|
||||
let(:config) {
|
||||
{
|
||||
auth: {
|
||||
'provider' => 'dummy'
|
||||
}
|
||||
}
|
||||
}
|
||||
let(:username_str) { 'admin' }
|
||||
let(:password_str) { 's3cr3t' }
|
||||
|
||||
it 'returns a 401 if not authed' do
|
||||
get "#{prefix}/token"
|
||||
|
|
@ -69,7 +67,13 @@ describe Vmpooler::API::V1 do
|
|||
end
|
||||
|
||||
context '(auth configured)' do
|
||||
let(:config) { { auth: true } }
|
||||
let(:config) {
|
||||
{
|
||||
auth: {
|
||||
'provider' => 'dummy'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it 'returns a 401 if not authed' do
|
||||
post "#{prefix}/token"
|
||||
|
|
@ -146,7 +150,13 @@ describe Vmpooler::API::V1 do
|
|||
end
|
||||
|
||||
context '(auth configured)' do
|
||||
let(:config) { { auth: true } }
|
||||
let(:config) {
|
||||
{
|
||||
auth: {
|
||||
'provider' => 'dummy'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it 'returns a 401 if not authed' do
|
||||
delete "#{prefix}/token/this"
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def has_set_tag?(vm, tag, value)
|
||||
value == redis.hget("vmpooler__vm__#{vm}", "tag:#{tag}")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vmpooler::API::V1 do
|
||||
include Rack::Test::Methods
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
require 'spec_helper'
|
||||
require 'rack/test'
|
||||
|
||||
module Vmpooler
|
||||
class API
|
||||
module Helpers
|
||||
def authenticate(auth, username_str, password_str)
|
||||
username_str == 'admin' and password_str == 's3cr3t'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe Vmpooler::API::V1 do
|
||||
include Rack::Test::Methods
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
require 'spec_helper'
|
||||
require 'net/ldap'
|
||||
|
||||
# A class for testing purposes that includes the Helpers.
|
||||
# this is impersonating V1's `helpers do include Helpers end`
|
||||
|
|
@ -238,4 +239,172 @@ describe Vmpooler::API::Helpers do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#authenticate' do
|
||||
let(:username_str) { 'admin' }
|
||||
let(:password_str) { 's3cr3t' }
|
||||
|
||||
context 'with dummy provider' do
|
||||
let(:auth) {
|
||||
{
|
||||
'provider': 'dummy'
|
||||
}
|
||||
}
|
||||
it 'should return true' do
|
||||
expect(subject).to receive(:authenticate).with(auth, username_str, password_str).and_return(true)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with ldap provider' do
|
||||
let(:host) { 'ldap.example.com' }
|
||||
let(:base) { 'ou=user,dc=test,dc=com' }
|
||||
let(:user_object) { 'uid' }
|
||||
let(:auth) {
|
||||
{
|
||||
'provider' => 'ldap',
|
||||
ldap: {
|
||||
'host' => host,
|
||||
'base' => base,
|
||||
'user_object' => user_object
|
||||
}
|
||||
}
|
||||
}
|
||||
let(:default_port) { 389 }
|
||||
it 'should attempt ldap authentication' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
|
||||
it 'should return true when authentication is successful' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str).and_return(true)
|
||||
|
||||
expect(subject.authenticate(auth, username_str, password_str)).to be true
|
||||
end
|
||||
|
||||
it 'should return false when authentication fails' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base, username_str, password_str).and_return(false)
|
||||
|
||||
expect(subject.authenticate(auth, username_str, password_str)).to be false
|
||||
end
|
||||
|
||||
context 'with an alternate port' do
|
||||
let(:alternate_port) { 636 }
|
||||
before(:each) do
|
||||
auth[:ldap]['port'] = alternate_port
|
||||
end
|
||||
|
||||
it 'should specify the alternate port when authenticating' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(alternate_port, host, user_object, base, username_str, password_str)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple search bases' do
|
||||
let(:base) {
|
||||
[
|
||||
'ou=user,dc=test,dc=com',
|
||||
'ou=service,ou=user,dc=test,dc=com'
|
||||
]
|
||||
}
|
||||
before(:each) do
|
||||
auth[:ldap]['base'] = base
|
||||
end
|
||||
|
||||
it 'should attempt to bind with each base' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str)
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
|
||||
it 'should not search the second base when the first binds' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(true)
|
||||
expect(subject).to_not receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
|
||||
it 'should search the second base when the first bind fails' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str)
|
||||
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
|
||||
it 'should return true when any bind succeeds' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str).and_return(true)
|
||||
|
||||
expect(subject.authenticate(auth, username_str, password_str)).to be true
|
||||
end
|
||||
|
||||
it 'should return false when all bind attempts fail' do
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[0], username_str, password_str).and_return(false)
|
||||
expect(subject).to receive(:authenticate_ldap).with(default_port, host, user_object, base[1], username_str, password_str).and_return(false)
|
||||
|
||||
expect(subject.authenticate(auth, username_str, password_str)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with unknown provider' do
|
||||
let(:auth) {
|
||||
{
|
||||
'provider': 'mystery'
|
||||
}
|
||||
}
|
||||
it 'should return false' do
|
||||
expect(subject).to receive(:authenticate).with(auth, username_str, password_str).and_return(false)
|
||||
subject.authenticate(auth, username_str, password_str)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#authenticate_ldap' do
|
||||
let(:port) { 389 }
|
||||
let(:host) { 'ldap.example.com' }
|
||||
let(:user_object) { 'uid' }
|
||||
let(:base) { 'ou=users,dc=example,dc=com' }
|
||||
let(:username_str) { 'admin' }
|
||||
let(:password_str) { 's3cr3t' }
|
||||
let(:ldap) { double('ldap') }
|
||||
it 'should create a new ldap connection' do
|
||||
allow(ldap).to receive(:bind)
|
||||
expect(Net::LDAP).to receive(:new).with(
|
||||
:host => host,
|
||||
:port => port,
|
||||
:encryption => {
|
||||
:method => :start_tls,
|
||||
:tls_options => { :ssl_version => 'TLSv1' }
|
||||
},
|
||||
:base => base,
|
||||
:auth => {
|
||||
:method => :simple,
|
||||
:username => "#{user_object}=#{username_str},#{base}",
|
||||
:password => password_str
|
||||
}
|
||||
).and_return(ldap)
|
||||
|
||||
subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)
|
||||
end
|
||||
|
||||
it 'should return true when a bind is successful' do
|
||||
expect(Net::LDAP).to receive(:new).and_return(ldap)
|
||||
expect(ldap).to receive(:bind).and_return(true)
|
||||
|
||||
expect(subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)).to be true
|
||||
end
|
||||
|
||||
it 'should return false when a bind fails' do
|
||||
expect(Net::LDAP).to receive(:new).and_return(ldap)
|
||||
expect(ldap).to receive(:bind).and_return(false)
|
||||
|
||||
expect(subject.authenticate_ldap(port, host, user_object, base, username_str, password_str)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue