diff --git a/qa/qa.rb b/qa/qa.rb index 237086996fdbae5131dbbeeef18f4941c5997a53..e084ef17985df4ef510668e98eb346a9cb314639 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -114,6 +114,7 @@ module Instance module Integration autoload :Github, 'qa/scenario/test/integration/github' autoload :LDAPNoTLS, 'qa/scenario/test/integration/ldap_no_tls' + autoload :LDAPNoServer, 'qa/scenario/test/integration/ldap_no_server' autoload :LDAPTLS, 'qa/scenario/test/integration/ldap_tls' autoload :InstanceSAML, 'qa/scenario/test/integration/instance_saml' autoload :OAuth, 'qa/scenario/test/integration/oauth' @@ -394,6 +395,7 @@ module Service autoload :KubernetesCluster, 'qa/service/kubernetes_cluster' autoload :Omnibus, 'qa/service/omnibus' autoload :Runner, 'qa/service/runner' + autoload :LDAP, 'qa/service/ldap' module ClusterProvider autoload :Base, 'qa/service/cluster_provider/base' diff --git a/qa/qa/fixtures/ldap/admin/1_add_nodes.ldif b/qa/qa/fixtures/ldap/admin/1_add_nodes.ldif new file mode 100644 index 0000000000000000000000000000000000000000..1476f53a0b952867b408de125b5af3b47c048fe9 --- /dev/null +++ b/qa/qa/fixtures/ldap/admin/1_add_nodes.ldif @@ -0,0 +1,7 @@ +dn: ou=Global Groups,dc=example,dc=org +objectClass: organizationalUnit +ou: Global Groups + +dn: ou=People,ou=Global Groups,dc=example,dc=org +objectClass: organizationalUnit +ou: People diff --git a/qa/qa/fixtures/ldap/admin/2_add_users.ldif b/qa/qa/fixtures/ldap/admin/2_add_users.ldif new file mode 100644 index 0000000000000000000000000000000000000000..00ba2fe8397993e753fdda5fb87ea11ddcb21eea --- /dev/null +++ b/qa/qa/fixtures/ldap/admin/2_add_users.ldif @@ -0,0 +1,63 @@ + +# 1. hruser1 + +dn: uid=hruser1,ou=People,ou=Global Groups,dc=example,dc=org +cn: HR User 1 +givenName: HR +sn: User1 +uid: hruser1 +uidNumber: 5000 +gidNumber: 10000 +homeDirectory: /home/hruser1 +mail: hruser1@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI + +# 2. adminuser1 + +dn: uid=adminuser1,ou=People,ou=Global Groups,dc=example,dc=org +cn: Admin User 1 +givenName: Admin +sn: User1 +uid: adminuser1 +uidNumber: 5009 +gidNumber: 10009 +homeDirectory: /home/adminuser1 +mail: adminuser1@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI + +# 2. adminuser2 + +dn: uid=adminuser2,ou=People,ou=Global Groups,dc=example,dc=org +cn: Admin User 2 +givenName: Admin +sn: User1 +uid: adminuser2 +uidNumber: 5010 +gidNumber: 10010 +homeDirectory: /home/adminuser2 +mail: adminuser2@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI diff --git a/qa/qa/fixtures/ldap/admin/3_add_groups.ldif b/qa/qa/fixtures/ldap/admin/3_add_groups.ldif new file mode 100644 index 0000000000000000000000000000000000000000..db8b15bc9ea8e97fc68d42b5ac76acb644d4aa8f --- /dev/null +++ b/qa/qa/fixtures/ldap/admin/3_add_groups.ldif @@ -0,0 +1,16 @@ +# 1. Human Resources + +dn: cn=Human Resources,ou=Global Groups,dc=example,dc=org +objectClass: groupofnames +cn: Human Resources +description: Human Resources +member: uid=hruser1,ou=People,ou=Global Groups,dc=example,dc=org + +# 2. Admin + +dn: cn=AdminGroup,ou=Global Groups,dc=example,dc=org +objectClass: groupofnames +cn: AdminGroup +description: Human Resources +member: uid=adminuser1,ou=People,ou=Global Groups,dc=example,dc=org +member: uid=adminuser2,ou=People,ou=Global Groups,dc=example,dc=org diff --git a/qa/qa/fixtures/ldap/non_admin/1_add_nodes.ldif b/qa/qa/fixtures/ldap/non_admin/1_add_nodes.ldif new file mode 100644 index 0000000000000000000000000000000000000000..1476f53a0b952867b408de125b5af3b47c048fe9 --- /dev/null +++ b/qa/qa/fixtures/ldap/non_admin/1_add_nodes.ldif @@ -0,0 +1,7 @@ +dn: ou=Global Groups,dc=example,dc=org +objectClass: organizationalUnit +ou: Global Groups + +dn: ou=People,ou=Global Groups,dc=example,dc=org +objectClass: organizationalUnit +ou: People diff --git a/qa/qa/fixtures/ldap/non_admin/2_add_users.ldif b/qa/qa/fixtures/ldap/non_admin/2_add_users.ldif new file mode 100644 index 0000000000000000000000000000000000000000..cf8accc97e147a83eacc75766eb87f6deb48fd61 --- /dev/null +++ b/qa/qa/fixtures/ldap/non_admin/2_add_users.ldif @@ -0,0 +1,61 @@ + +# 1. Human Resources + +dn: uid=hruser1,ou=People,ou=Global Groups,dc=example,dc=org +cn: HR User 1 +givenName: HR +sn: User1 +uid: hruser1 +uidNumber: 5000 +gidNumber: 10000 +homeDirectory: /home/hruser1 +mail: hruser1@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI + +# 2. Admin + +dn: uid=adminuser1,ou=People,ou=Global Groups,dc=example,dc=org +cn: Admin User 1 +givenName: Admin +sn: User1 +uid: adminuser1 +uidNumber: 5009 +gidNumber: 10009 +homeDirectory: /home/adminuser1 +mail: adminuser1@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI + +dn: uid=adminuser2,ou=People,ou=Global Groups,dc=example,dc=org +cn: Admin User 2 +givenName: Admin +sn: User1 +uid: adminuser2 +uidNumber: 5010 +gidNumber: 10010 +homeDirectory: /home/adminuser2 +mail: adminuser2@example.org +objectClass: top +objectClass: posixAccount +objectClass: shadowAccount +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +loginShell: /bin/bash +# hashed value for 'password' +userPassword: {SSHA}ICMhr6Jxt5bk2awD7HL7GxRTM3BZ1pFI diff --git a/qa/qa/fixtures/ldap/non_admin/3_add_groups.ldif b/qa/qa/fixtures/ldap/non_admin/3_add_groups.ldif new file mode 100644 index 0000000000000000000000000000000000000000..65487a3b2c6cfeab2d206839e543697f010233f1 --- /dev/null +++ b/qa/qa/fixtures/ldap/non_admin/3_add_groups.ldif @@ -0,0 +1,16 @@ +# 1. Human Resources + +dn: cn=Human Resources,ou=Global Groups,dc=example,dc=org +objectClass: groupofnames +cn: Human Resources +description: Human Resources +member: uid=hruser1,ou=People,ou=Global Groups,dc=example,dc=org +member: uid=adminuser1,ou=People,ou=Global Groups,dc=example,dc=org + +# 2. Admin + +dn: cn=AdminGroup,ou=Global Groups,dc=example,dc=org +objectClass: groupofnames +cn: AdminGroup +description: Human Resources +member: uid=adminuser2,ou=People,ou=Global Groups,dc=example,dc=org diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index c373ec6d4fdc98bcd3c0d3a6e7a0f7f092720584..6e266e26d789cd6aede94df513530ed27c79c175 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -87,7 +87,7 @@ def sign_in_using_ldap_credentials(user:) click_element :sign_in_button end - Page::Main::Menu.perform(&:has_personal_area?) + Page::Main::Menu.perform(&:signed_in?) end def self.path diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb index 3391ef454ee3c5cd0cb80f0c2af03fcdfc49df38..bff1b4cc836f96ca869b0b984c84dfbe685612ff 100644 --- a/qa/qa/page/main/menu.rb +++ b/qa/qa/page/main/menu.rb @@ -96,6 +96,10 @@ def has_admin_area_link?(wait: Capybara.default_max_wait_time) has_element?(:admin_area_link, wait: wait) end + def has_no_admin_area_link?(wait: Capybara.default_max_wait_time) + has_no_element?(:admin_area_link, wait: wait) + end + def click_stop_impersonation_link click_element(:stop_impersonation_link) end diff --git a/qa/qa/scenario/test/integration/ldap_no_server.rb b/qa/qa/scenario/test/integration/ldap_no_server.rb new file mode 100644 index 0000000000000000000000000000000000000000..be71fc0ef6d5108b9c0eabf3345f3113306f0975 --- /dev/null +++ b/qa/qa/scenario/test/integration/ldap_no_server.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module QA + module Scenario + module Test + module Integration + class LDAPNoServer < Test::Instance::All + tags :ldap_no_server + end + end + end + end +end diff --git a/qa/qa/service/ldap.rb b/qa/qa/service/ldap.rb new file mode 100644 index 0000000000000000000000000000000000000000..7a02cebeb8f982bd17fc770fd22ff4407061aea9 --- /dev/null +++ b/qa/qa/service/ldap.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module QA + module Service + class LDAP + include Service::Shellout + + def initialize(volume) + @image = 'osixia/openldap:latest' + @name = 'ldap-server' + @network = Runtime::Scenario.attributes[:network] || 'test' + @volume = volume + end + + def network + shell "docker network inspect #{@network}" + rescue CommandError + 'bridge' + else + @network + end + + def pull + shell "docker pull #{@image}" + end + + def host_name + "#{@name}.#{network}" + end + + def register! + shell <<~CMD.tr("\n", ' ') + docker run -d --rm + --network #{network} + --hostname #{host_name} + --name #{@name} + -p 389:389 + --volume #{volume_or_fixture(@volume)}:/container/service/slapd/assets/config/bootstrap/ldif/custom + #{@image} --copy-service + CMD + end + + def remove! + shell "docker rm -f #{@name}" if running? + end + + def running? + `docker ps -f name=#{@name}`.include?(@name) + end + + def volume_or_fixture(volume_name) + if volume_exists?(volume_name) + volume_name + else + File.expand_path("../fixtures/ldap/#{volume_name}", __dir__) + end + end + + def volume_exists?(volume_name) + `docker volume ls -q -f name=#{volume_name}`.include?(volume_name) + end + end + end +end diff --git a/qa/qa/specs/features/ee/browser_ui/1_manage/ldap/admin_ldap_sync_spec.rb b/qa/qa/specs/features/ee/browser_ui/1_manage/ldap/admin_ldap_sync_spec.rb index abe27ab30ae2a1af59c924196baca6896677beaf..3092123ba2914b2eb7d9aa6414244bfdcdf0a936 100644 --- a/qa/qa/specs/features/ee/browser_ui/1_manage/ldap/admin_ldap_sync_spec.rb +++ b/qa/qa/specs/features/ee/browser_ui/1_manage/ldap/admin_ldap_sync_spec.rb @@ -1,27 +1,62 @@ # frozen_string_literal: true - module QA - context 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do + context 'Manage', :orchestrated, :ldap_no_server do describe 'LDAP admin sync' do - it 'Syncs admin users' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) + before do + run_ldap_service_with_user_as('admin') - Page::Main::Login.perform do |login_page| - user = Struct.new(:ldap_username, :ldap_password).new('adminuser1', 'password') + Runtime::Browser.visit(:gitlab, Page::Main::Login) - login_page.sign_in_using_ldap_credentials(user: user) - end + login_with_ldap_admin_user + end + it 'sets and removes user\'s admin status' do Page::Main::Menu.perform do |menu| - expect(menu).to have_personal_area - - # The ldap_sync_worker_cron job is set to run every minute admin_synchronised = menu.wait(max: 80, interval: 1, reload: true) do menu.has_admin_area_link? end expect(admin_synchronised).to be_truthy end + + remove_ldap_service_with_user_as('admin') + + run_ldap_service_with_user_as('non_admin') + + login_with_ldap_admin_user + + Page::Main::Menu.perform do |menu| + admin_removed = menu.wait(max: 80, interval: 1, reload: true) do + menu.has_no_admin_area_link? + end + + expect(admin_removed).to be_truthy + end + end + + after do + remove_ldap_service_with_user_as('non_admin') + end + + def run_ldap_service_with_user_as(user_status) + Service::LDAP.new(user_status).tap do |runner| + runner.pull + runner.register! + end + end + + def remove_ldap_service_with_user_as(user_status) + Service::LDAP.new(user_status).remove! + end + + def login_with_ldap_admin_user + Page::Main::Login.perform do |login_page| + user = Struct.new(:ldap_username, :ldap_password).new('adminuser1', 'password') + + QA::Support::Retrier.retry_until(exit_on_failure: true, sleep_interval: 3, max_attempts: 5) do + login_page.sign_in_using_ldap_credentials(user) + end + end end end end diff --git a/qa/spec/scenario/test/integration/ldap_spec.rb b/qa/spec/scenario/test/integration/ldap_spec.rb index b6d798bf504d7cb3d5b83bcfc691ad41ff8d5f26..86747cd8eb71c02f764d75ed2f24b3d6c149ac15 100644 --- a/qa/spec/scenario/test/integration/ldap_spec.rb +++ b/qa/spec/scenario/test/integration/ldap_spec.rb @@ -8,6 +8,14 @@ end end +describe QA::Scenario::Test::Integration::LDAPNoServer do + context '#perform' do + it_behaves_like 'a QA scenario class' do + let(:tags) { [:ldap_no_server] } + end + end +end + describe QA::Scenario::Test::Integration::LDAPTLS do context '#perform' do it_behaves_like 'a QA scenario class' do