2018-02-06 23:56:53 +03:00
|
|
|
require "minitest/autorun"
|
2018-02-12 23:47:10 +03:00
|
|
|
require 'minitest/hooks/test'
|
2023-08-10 11:04:25 +03:00
|
|
|
require "pgls"
|
2011-05-24 13:14:26 +04:00
|
|
|
require 'yaml'
|
|
|
|
require 'fileutils'
|
2018-02-06 23:56:53 +03:00
|
|
|
require_relative 'ldap_server'
|
2011-05-18 17:45:08 +04:00
|
|
|
|
2018-02-06 23:56:53 +03:00
|
|
|
class TestPgLdapSync < Minitest::Test
|
2018-02-12 23:47:10 +03:00
|
|
|
include Minitest::Hooks
|
|
|
|
|
2018-03-13 18:21:20 +03:00
|
|
|
@@logid = 0
|
|
|
|
|
2011-05-24 13:14:26 +04:00
|
|
|
def log_and_run( *cmd )
|
2018-03-13 18:21:20 +03:00
|
|
|
if $DEBUG
|
|
|
|
puts cmd.join(' ')
|
|
|
|
system( *cmd )
|
|
|
|
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
|
|
|
|
else
|
|
|
|
fname = "temp/run_#{@@logid+=1}.log"
|
|
|
|
pid = Process.spawn( *cmd, [:out, :err] => [fname, "w"] )
|
|
|
|
Process.wait(pid)
|
|
|
|
unless $?.success?
|
|
|
|
$stderr.puts "Command failed: [%s]\n%s" % [cmd.join(' '), File.read(fname)]
|
|
|
|
end
|
2018-03-13 18:56:14 +03:00
|
|
|
File.unlink fname rescue nil # File is locked on Windows
|
2018-03-13 18:21:20 +03:00
|
|
|
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
|
|
|
|
end
|
2011-05-24 13:14:26 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
def start_ldap_server
|
2018-02-12 23:47:10 +03:00
|
|
|
@directory = [{}]
|
2011-05-24 13:14:26 +04:00
|
|
|
|
|
|
|
# Listen for incoming LDAP connections. For each one, create a Connection
|
|
|
|
# object, which will invoke a HashOperation object for each request.
|
|
|
|
|
|
|
|
@ldap_server = LDAP::Server.new(
|
|
|
|
:port => 1389,
|
|
|
|
:nodelay => true,
|
|
|
|
:listen => 10,
|
|
|
|
# :ssl_key_file => "key.pem",
|
|
|
|
# :ssl_cert_file => "cert.pem",
|
|
|
|
# :ssl_on_connect => true,
|
|
|
|
:operation_class => HashOperation,
|
2022-12-01 17:21:39 +03:00
|
|
|
:operation_args => @directory,
|
|
|
|
:attribute_range_limit => 2
|
2011-05-24 13:14:26 +04:00
|
|
|
)
|
|
|
|
@ldap_server.run_tcpserver
|
|
|
|
end
|
|
|
|
|
|
|
|
def stop_ldap_server
|
|
|
|
@ldap_server.stop
|
|
|
|
end
|
|
|
|
|
|
|
|
def start_pg_server
|
|
|
|
@port = 54321
|
|
|
|
ENV['PGPORT'] = @port.to_s
|
|
|
|
ENV['PGHOST'] = 'localhost'
|
2011-07-14 13:08:17 +04:00
|
|
|
unless File.exist?('temp/pg_data/PG_VERSION')
|
2011-05-24 13:14:26 +04:00
|
|
|
FileUtils.mkdir_p 'temp/pg_data'
|
2011-07-14 13:08:17 +04:00
|
|
|
log_and_run 'initdb', '-D', 'temp/pg_data', '--no-locale'
|
2011-05-24 13:14:26 +04:00
|
|
|
end
|
2011-07-07 17:06:34 +04:00
|
|
|
log_and_run 'pg_ctl', '-w', '-o', "-k.", '-D', 'temp/pg_data', 'start'
|
2018-03-13 18:21:20 +03:00
|
|
|
|
|
|
|
@pgconn = PG.connect dbname: 'postgres'
|
|
|
|
@pgconn.exec "SET client_min_messages to warning"
|
2011-05-24 13:14:26 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
def stop_pg_server
|
2018-03-13 18:21:20 +03:00
|
|
|
@pgconn.close if @pgconn
|
2011-07-07 17:06:34 +04:00
|
|
|
log_and_run 'pg_ctl', '-w', '-o', "-k.", '-D', 'temp/pg_data', 'stop'
|
2011-05-24 13:14:26 +04:00
|
|
|
end
|
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def before_all
|
|
|
|
super
|
|
|
|
ENV['LC_MESSAGES'] = 'C'
|
2011-05-24 13:14:26 +04:00
|
|
|
start_ldap_server
|
|
|
|
start_pg_server
|
|
|
|
end
|
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def after_all
|
|
|
|
super
|
2011-05-24 13:14:26 +04:00
|
|
|
stop_ldap_server
|
|
|
|
stop_pg_server
|
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def setup
|
2022-01-17 16:48:49 +03:00
|
|
|
@pgconn.exec "DROP ROLE IF EXISTS \"Fred\", fred, \"Wilma\", wilma, \"Flintstones\", \"flintstones\", \"Wilmas\", \"wilmas\", \"All Users\", double_user"
|
2018-03-13 18:21:20 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
def assert_role(role_name, attrs, member_of=[])
|
|
|
|
res = @pgconn.exec("SELECT * FROM pg_roles WHERE rolname = '#{@pgconn.escape_string(role_name)}'")
|
|
|
|
assert_equal 1, res.ntuples, "Role #{role_name} not found"
|
|
|
|
|
|
|
|
res2 = @pgconn.exec "SELECT pr.rolname FROM pg_auth_members pam JOIN pg_roles pr ON pr.oid=pam.roleid WHERE pam.member=#{res.to_a[0]['oid']}"
|
|
|
|
rolnames = res2.map{|t| t['rolname'] }
|
|
|
|
assert_equal member_of.sort, rolnames.sort
|
|
|
|
|
|
|
|
exp_attrs = []
|
|
|
|
exp_attrs << 'Cannot login' if res[0]['rolcanlogin'] != 't'
|
|
|
|
exp_attrs << 'Superuser' if res[0]['rolsuper'] == 't'
|
|
|
|
|
|
|
|
assert_equal attrs, exp_attrs.join(", ")
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
|
|
|
|
2018-03-13 18:21:20 +03:00
|
|
|
def refute_role(role_name)
|
|
|
|
res = @pgconn.exec("SELECT oid FROM pg_roles WHERE rolname = '#{@pgconn.escape_string(role_name)}'")
|
|
|
|
assert_equal 0, res.ntuples, "Role #{role_name} not found"
|
2011-07-07 18:14:37 +04:00
|
|
|
end
|
2018-03-13 18:21:20 +03:00
|
|
|
|
2011-07-14 13:08:17 +04:00
|
|
|
def exec_psql_du
|
|
|
|
text = if RUBY_PLATFORM=~/mingw|mswin/
|
|
|
|
`psql -c \\du postgres`
|
|
|
|
else
|
|
|
|
`psql -c \\\\du postgres`
|
|
|
|
end
|
|
|
|
puts text
|
|
|
|
return text
|
|
|
|
end
|
2011-05-24 13:14:26 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def load_ldap_fixture(fname)
|
|
|
|
yaml_fname = File.join(File.dirname(__FILE__), "fixtures/#{fname}.yaml")
|
|
|
|
@directory[0] = File.open(yaml_fname){|f| YAML::load(f.read) }
|
|
|
|
end
|
2011-05-24 13:14:26 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def sync_with_config(config="config-ldapdb")
|
2022-12-01 17:21:39 +03:00
|
|
|
PgLdapSync::Application.run(["-c", "test/fixtures/#{config}.yaml"] + ($DEBUG ? ["-vvv"] : ["--no-verbose"]))
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def sync_to_fixture(fixture: "ldapdb", config: "config-ldapdb")
|
|
|
|
load_ldap_fixture(fixture)
|
|
|
|
sync_with_config(config)
|
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2022-01-17 16:48:49 +03:00
|
|
|
def sync_change(fixture: "ldapdb", config: "config-ldapdb")
|
|
|
|
sync_to_fixture(fixture: fixture, config: config)
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
yield(@directory)
|
|
|
|
|
2022-01-17 16:48:49 +03:00
|
|
|
sync_with_config(config)
|
2018-03-13 18:21:20 +03:00
|
|
|
exec_psql_du if $DEBUG
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_invalid_config
|
|
|
|
assert_output(/key 'ldap_users:' is required/) do
|
|
|
|
assert_raises(PgLdapSync::InvalidConfig) do
|
|
|
|
sync_with_config("config-invalid")
|
|
|
|
end
|
|
|
|
end
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_base_users_groups_memberships
|
2018-03-13 18:21:20 +03:00
|
|
|
sync_change{}
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-03-13 18:21:20 +03:00
|
|
|
assert_role('All Users', 'Cannot login')
|
|
|
|
assert_role('Flintstones', 'Cannot login')
|
|
|
|
assert_role('Wilmas', 'Cannot login', ['All Users'])
|
2022-01-17 16:48:49 +03:00
|
|
|
assert_role('Fred', '', ['All Users', 'Flintstones'])
|
|
|
|
assert_role('Wilma', '', ['Flintstones', 'Wilmas'])
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def test_add_membership
|
2018-03-13 18:21:20 +03:00
|
|
|
sync_change do |dir|
|
2018-02-12 23:47:10 +03:00
|
|
|
# add 'Fred' to 'Wilmas'
|
|
|
|
@directory[0]['cn=Wilmas,dc=example,dc=com']['member'] << 'cn=Fred Flintstone,dc=example,dc=com'
|
|
|
|
end
|
2022-01-17 18:05:51 +03:00
|
|
|
refute_role('fred')
|
2022-01-17 16:48:49 +03:00
|
|
|
assert_role('Fred', '', ['All Users', 'Flintstones', 'Wilmas'])
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_add_membership_bothcase
|
|
|
|
sync_change(config: "config-ldapdb-bothcase") do |dir|
|
|
|
|
# add 'Fred' to 'Wilmas'
|
|
|
|
@directory[0]['cn=Wilmas,dc=example,dc=com']['member'] << 'cn=Fred Flintstone,dc=example,dc=com'
|
|
|
|
end
|
|
|
|
assert_role('fred', '', ['All Users', 'all users', 'Flintstones', 'flintstones', 'Wilmas', 'wilmas'])
|
2022-01-17 18:05:51 +03:00
|
|
|
assert_role('Fred', '', ['All Users', 'all users', 'Flintstones', 'flintstones', 'Wilmas', 'wilmas'])
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def test_revoke_membership
|
2018-03-13 18:21:20 +03:00
|
|
|
sync_change do |dir|
|
2018-02-12 23:47:10 +03:00
|
|
|
# revoke membership of 'wilma' to 'Flintstones'
|
|
|
|
dir[0]['cn=Flintstones,dc=example,dc=com']['member'].pop
|
|
|
|
end
|
2022-01-17 16:48:49 +03:00
|
|
|
assert_role('Wilma', '', ['Wilmas'])
|
2018-02-12 23:47:10 +03:00
|
|
|
end
|
2011-07-08 17:50:33 +04:00
|
|
|
|
2018-02-12 23:47:10 +03:00
|
|
|
def test_rename_role
|
2018-03-13 18:21:20 +03:00
|
|
|
sync_change do |dir|
|
2018-02-12 23:47:10 +03:00
|
|
|
# rename role 'wilma'
|
|
|
|
dir[0]['cn=Wilma Flintstone,dc=example,dc=com']['sAMAccountName'] = ['Wilma Flintstone']
|
|
|
|
end
|
2018-03-13 18:21:20 +03:00
|
|
|
refute_role('wilma')
|
2022-01-17 16:48:49 +03:00
|
|
|
refute_role('Wilma')
|
2018-03-13 18:21:20 +03:00
|
|
|
assert_role('Wilma Flintstone', '', ['Flintstones', 'Wilmas'])
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_dont_stop_on_error
|
|
|
|
log_and_run 'psql', '-e', '-c', "CREATE ROLE double_user LOGIN", 'postgres'
|
|
|
|
|
|
|
|
assert_raises(PgLdapSync::ErrorExit) do
|
|
|
|
sync_change do |dir|
|
|
|
|
dir[0]['cn=double_user,dc=example,dc=com'] = {'sAMAccountName' => 'double_user'}
|
|
|
|
end
|
|
|
|
end
|
2011-05-18 17:45:08 +04:00
|
|
|
end
|
|
|
|
end
|