Commit 6268ee84 authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Merge branch 'jej/prevent-enabling-group-managed-accounts-when-SSO-not-linked' into 'master'

Require group owner to have linked SAML before enabling Group Managed Accounts

Closes #38021 and #39183

See merge request gitlab-org/gitlab!21721
parents 71f20670 2b9997d5
---
title: Require group owner to have linked SAML before enabling Group Managed Accounts
merge_request: 21721
author:
type: fixed
...@@ -22,6 +22,7 @@ module GroupSaml ...@@ -22,6 +22,7 @@ module GroupSaml
updated = saml_provider.update(params) updated = saml_provider.update(params)
if updated && saml_provider.enforced_group_managed_accounts? && !group_managed_accounts_was_enforced if updated && saml_provider.enforced_group_managed_accounts? && !group_managed_accounts_was_enforced
require_linked_saml_to_enable_group_managed!
cleanup_members! cleanup_members!
end end
end end
...@@ -29,10 +30,21 @@ module GroupSaml ...@@ -29,10 +30,21 @@ module GroupSaml
private private
def require_linked_saml_to_enable_group_managed!
return if saml_provider.identities.for_user(current_user).exists?
add_error!(_("Group Owner must have signed in with SAML before enabling Group Managed Accounts"))
end
def cleanup_members! def cleanup_members!
return if GroupManagedAccounts::CleanUpMembersService.new(current_user, group).execute return if GroupManagedAccounts::CleanUpMembersService.new(current_user, group).execute
saml_provider.errors.add(:base, _("Can't remove group members without group managed account")) add_error!(_("Can't remove group members without group managed account"))
end
def add_error!(message)
saml_provider.errors.add(:base, message)
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
end end
......
...@@ -116,7 +116,7 @@ describe Groups::SamlProvidersController do ...@@ -116,7 +116,7 @@ describe Groups::SamlProvidersController do
end end
describe 'PUT #update' do describe 'PUT #update' do
subject { put :update, params: { group_id: group, saml_provider: { enforced_sso: 'true', enforced_group_managed_accounts: 'true' } } } subject { put :update, params: { group_id: group, saml_provider: { enforced_sso: 'true' } } }
before do before do
group.add_owner(user) group.add_owner(user)
...@@ -148,29 +148,52 @@ describe Groups::SamlProvidersController do ...@@ -148,29 +148,52 @@ describe Groups::SamlProvidersController do
end end
end end
context 'group_managed_accounts feature flag enabled' do context 'enabling group managed when owner has linked identity' do
subject { put :update, params: { group_id: group, saml_provider: { enforced_sso: 'true', enforced_group_managed_accounts: 'true' } } }
before do before do
stub_feature_flags(group_managed_accounts: true) create(:group_saml_identity, saml_provider: saml_provider, user: user)
end end
it 'updates the flags' do context 'group_managed_accounts feature flag enabled' do
expect do before do
subject stub_feature_flags(group_managed_accounts: true)
saml_provider.reload end
end.to change { saml_provider.enforced_group_managed_accounts? }.to(true)
it 'updates the flags' do
expect do
subject
saml_provider.reload
end.to change { saml_provider.enforced_group_managed_accounts? }.to(true)
end
end
context 'group_managed_accounts feature flag disabled' do
before do
stub_feature_flags(group_managed_accounts: false)
end
it 'does not update the setting' do
expect do
subject
saml_provider.reload
end.not_to change { saml_provider.enforced_group_managed_accounts? }.from(false)
end
end end
end end
context 'group_managed_accounts feature flag disabled' do context 'enabling group managed when owner has not linked identity' do
subject { put :update, params: { group_id: group, saml_provider: { enforced_sso: 'true', enforced_group_managed_accounts: 'true' } } }
before do before do
stub_feature_flags(group_managed_accounts: false) stub_feature_flags(group_managed_accounts: true)
end end
it 'does not update the setting' do it 'does not update update the flags' do
expect do expect do
subject subject
saml_provider.reload saml_provider.reload
end.not_to change { saml_provider.enforced_group_managed_accounts? }.from(false) end.not_to change { saml_provider.enforced_group_managed_accounts? }
end end
end end
end end
......
...@@ -117,6 +117,10 @@ describe 'SAML provider settings' do ...@@ -117,6 +117,10 @@ describe 'SAML provider settings' do
end end
context 'enforced_group_managed_accounts enabled', :js do context 'enforced_group_managed_accounts enabled', :js do
before do
create(:group_saml_identity, saml_provider: saml_provider, user: user)
end
it 'updates the flag' do it 'updates the flag' do
stub_feature_flags(group_managed_accounts: true) stub_feature_flags(group_managed_accounts: true)
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe GroupSaml::SamlProvider::CreateService do describe GroupSaml::SamlProvider::CreateService do
subject(:service) { described_class.new(nil, group, params: params) } let(:current_user) { build_stubbed(:user) }
subject(:service) { described_class.new(current_user, group, params: params) }
let(:group) { create :group } let(:group) { create :group }
......
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
require 'spec_helper' require 'spec_helper'
describe GroupSaml::SamlProvider::UpdateService do describe GroupSaml::SamlProvider::UpdateService do
subject(:service) { described_class.new(nil, saml_provider, params: params) } let(:current_user) { create(:user) }
subject(:service) { described_class.new(current_user, saml_provider, params: params) }
let(:saml_provider) do let(:saml_provider) do
create :saml_provider, enabled: false, enforced_sso: false, enforced_group_managed_accounts: enforced_group_managed_accounts create :saml_provider, enabled: false, enforced_sso: false
end end
let(:group) { saml_provider.group } let(:group) { saml_provider.group }
include_examples 'base SamlProvider service' include_examples 'base SamlProvider service'
include_examples 'SamlProvider service toggles Group Managed Accounts'
end end
...@@ -6,19 +6,11 @@ shared_examples 'base SamlProvider service' do ...@@ -6,19 +6,11 @@ shared_examples 'base SamlProvider service' do
sso_url: 'https://test', sso_url: 'https://test',
certificate_fingerprint: fingerprint, certificate_fingerprint: fingerprint,
enabled: true, enabled: true,
enforced_sso: true, enforced_sso: true
enforced_group_managed_accounts: true
} }
end end
let(:enforced_group_managed_accounts) { false }
let(:fingerprint) { '11:22:33:44:55:66:77:88:99:11:22:33:44:55:66:77:88:99' } let(:fingerprint) { '11:22:33:44:55:66:77:88:99:11:22:33:44:55:66:77:88:99' }
let(:cleanup_members_service_spy) { spy('GroupSaml::GroupManagedAccounts::CleanUpMembersService') }
before do
allow(GroupSaml::GroupManagedAccounts::CleanUpMembersService)
.to receive(:new).with(nil, group).and_return(cleanup_members_service_spy)
end
it 'updates SAML provider with given params' do it 'updates SAML provider with given params' do
expect do expect do
...@@ -28,10 +20,33 @@ shared_examples 'base SamlProvider service' do ...@@ -28,10 +20,33 @@ shared_examples 'base SamlProvider service' do
.and change { group.saml_provider&.certificate_fingerprint }.to(fingerprint) .and change { group.saml_provider&.certificate_fingerprint }.to(fingerprint)
.and change { group.saml_provider&.enabled? }.to(true) .and change { group.saml_provider&.enabled? }.to(true)
.and change { group.saml_provider&.enforced_sso? }.to(true) .and change { group.saml_provider&.enforced_sso? }.to(true)
.and change { group.saml_provider&.enforced_group_managed_accounts? }.to(true)
end end
end
shared_examples 'SamlProvider service toggles Group Managed Accounts' do
let(:cleanup_members_service_spy) { spy('GroupSaml::GroupManagedAccounts::CleanUpMembersService') }
before do
allow(GroupSaml::GroupManagedAccounts::CleanUpMembersService)
.to receive(:new).with(current_user, group).and_return(cleanup_members_service_spy)
end
context 'when enabling enforced_group_managed_accounts' do
let(:params) do
attributes_for(:saml_provider, :enforced_group_managed_accounts)
end
before do
create(:group_saml_identity, user: current_user, saml_provider: saml_provider)
end
it 'updates enforced_group_managed_accounts boolean' do
expect do
service.execute
group.reload
end.to change { group.saml_provider&.enforced_group_managed_accounts? }.to(true)
end
context 'when enforced_group_managed_accounts is enabled' do
it 'cleans up group members' do it 'cleans up group members' do
service.execute service.execute
...@@ -66,11 +81,34 @@ shared_examples 'base SamlProvider service' do ...@@ -66,11 +81,34 @@ shared_examples 'base SamlProvider service' do
end.not_to change { group.saml_provider } end.not_to change { group.saml_provider }
end end
end end
context 'when owner has not linked SAML yet' do
before do
Identity.delete_all
end
it 'adds an error warning that the owner must first link SAML' do
service.execute
expect(service.saml_provider.errors[:base]).to eq(["Group Owner must have signed in with SAML before enabling Group Managed Accounts"])
end
it 'does not attempt member cleanup' do
service.execute
expect(cleanup_members_service_spy).not_to have_received(:execute)
end
end
end end
context 'when group managed accounts was enabled beforehand' do context 'when group managed accounts was enabled beforehand' do
let(:enforced_group_managed_accounts) { true } let(:params) do
let(:params) { { enforced_group_managed_accounts: true } } attributes_for(:saml_provider, :enforced_group_managed_accounts)
end
before do
saml_provider.update!(enforced_group_managed_accounts: true)
end
it 'does not clean up group members' do it 'does not clean up group members' do
service.execute service.execute
...@@ -80,10 +118,15 @@ shared_examples 'base SamlProvider service' do ...@@ -80,10 +118,15 @@ shared_examples 'base SamlProvider service' do
end end
context 'when enforced_group_managed_accounts is disabled' do context 'when enforced_group_managed_accounts is disabled' do
let(:enforced_group_managed_accounts) { true } before do
let(:params) { { enforced_group_managed_accounts: false } } saml_provider.update!(enforced_group_managed_accounts: true)
end
let(:params) do
attributes_for(:saml_provider, enabled: true, enforced_sso: true, enforced_group_managed_accounts: false)
end
it 'does not clean up group members' do it 'does not clean up group members' do
service.execute service.execute
expect(cleanup_members_service_spy).not_to have_received(:execute) expect(cleanup_members_service_spy).not_to have_received(:execute)
......
...@@ -9235,6 +9235,9 @@ msgstr "" ...@@ -9235,6 +9235,9 @@ msgstr ""
msgid "Group ID: %{group_id}" msgid "Group ID: %{group_id}"
msgstr "" msgstr ""
msgid "Group Owner must have signed in with SAML before enabling Group Managed Accounts"
msgstr ""
msgid "Group Runners" msgid "Group Runners"
msgstr "" msgstr ""
......
...@@ -9,6 +9,11 @@ module QA ...@@ -9,6 +9,11 @@ module QA
element :sign_out_and_register_button element :sign_out_and_register_button
element :new_user_email_field element :new_user_email_field
element :new_user_username_field element :new_user_username_field
element :new_user_register_button
end
def click_register_button
click_element :new_user_register_button
end end
def click_signout_and_register_button def click_signout_and_register_button
......
...@@ -5,15 +5,23 @@ module QA ...@@ -5,15 +5,23 @@ module QA
module Saml module Saml
def self.idp_base_url def self.idp_base_url
host = QA::Runtime::Env.simple_saml_hostname || 'localhost' host = QA::Runtime::Env.simple_saml_hostname || 'localhost'
"https://#{host}:8443/simplesaml/saml2/idp" "https://#{host}:8443/simplesaml"
end end
def self.idp_sso_url def self.idp_sso_url
"#{idp_base_url}/SSOService.php" "#{idp_base_url}/saml2/idp/SSOService.php"
end
def self.idp_sign_out_url
"#{idp_base_url}/module.php/core/authenticate.php?as=example-userpass&logout"
end
def self.idp_signed_out_url
"#{idp_base_url}/logout.php"
end end
def self.idp_metadata_url def self.idp_metadata_url
"#{idp_base_url}/metadata.php" "#{idp_base_url}/saml2/idp/metadata.php"
end end
def self.idp_issuer def self.idp_issuer
......
...@@ -184,6 +184,9 @@ module QA ...@@ -184,6 +184,9 @@ module QA
end end
@managed_group_url = setup_and_enable_group_managed_accounts @managed_group_url = setup_and_enable_group_managed_accounts
Page::Main::Menu.perform(&:sign_out_if_signed_in)
logout_from_idp
end end
it 'removes existing users from the group, forces existing users to create a new account and allows to leave group' do it 'removes existing users from the group, forces existing users to create a new account and allows to leave group' do
...@@ -203,7 +206,7 @@ module QA ...@@ -203,7 +206,7 @@ module QA
new_username = EE::Page::Group::SamlSSOSignUp.perform(&:current_username) new_username = EE::Page::Group::SamlSSOSignUp.perform(&:current_username)
EE::Page::Group::SamlSSOSignUp.perform(&:click_signout_and_register_button) EE::Page::Group::SamlSSOSignUp.perform(&:click_register_button)
expect(page).to have_text("Sign up was successful! Please confirm your email to sign in.") expect(page).to have_text("Sign up was successful! Please confirm your email to sign in.")
...@@ -298,20 +301,22 @@ module QA ...@@ -298,20 +301,22 @@ module QA
end end
def setup_and_enable_group_managed_accounts def setup_and_enable_group_managed_accounts
Page::Main::Login.perform(&:sign_in_using_credentials) unless Page::Main::Menu.perform(&:signed_in?) setup_and_enable_enforce_sso
Support::Retrier.retry_on_exception do Support::Retrier.retry_on_exception do
@group.visit! # We must sign in with SAML before enabling Group Managed Accounts
EE::Page::Group::Settings::SamlSSO.perform do |saml_sso|
saml_sso.click_user_login_url_link
end
EE::Page::Group::SamlSSOSignIn.perform(&:click_sign_in)
login_to_idp_if_required_and_expect_success('user1', 'user1pass')
Page::Group::Menu.perform(&:go_to_saml_sso_group_settings) Page::Group::Menu.perform(&:go_to_saml_sso_group_settings)
EE::Page::Group::Settings::SamlSSO.perform do |saml_sso| EE::Page::Group::Settings::SamlSSO.perform do |saml_sso|
saml_sso.enforce_sso
saml_sso.enable_group_managed_accounts saml_sso.enable_group_managed_accounts
saml_sso.set_id_provider_sso_url(EE::Runtime::Saml.idp_sso_url)
saml_sso.set_cert_fingerprint(EE::Runtime::Saml.idp_certificate_fingerprint)
saml_sso.click_save_changes saml_sso.click_save_changes
saml_sso.user_login_url_link_text saml_sso.user_login_url_link_text
...@@ -331,6 +336,11 @@ module QA ...@@ -331,6 +336,11 @@ module QA
Resource::User.fabricate_via_api! Resource::User.fabricate_via_api!
end end
def logout_from_idp
page.visit EE::Runtime::Saml.idp_sign_out_url
Support::Waiter.wait { current_url == EE::Runtime::Saml.idp_signed_out_url }
end
def reset_idp_session def reset_idp_session
Runtime::Logger.debug(%Q[Visiting IDP url at "#{EE::Runtime::Saml.idp_sso_url}"]) Runtime::Logger.debug(%Q[Visiting IDP url at "#{EE::Runtime::Saml.idp_sso_url}"])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment