Commit 4ee67f15 authored by Drew Blessing's avatar Drew Blessing

Sync groups on sign-in for GitLab.com Group SAML

This MR enables Group SAML Group Sync by default, as well
as addressing a minor policy issue and moving the feature
from Ultimate/Gold to Premium/Bronze.
parent 2e70a5d2
...@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267020 ...@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267020
milestone: '13.6' milestone: '13.6'
type: development type: development
group: group::access group: group::access
default_enabled: false default_enabled: true
...@@ -242,6 +242,42 @@ For example, to unlink the `MyOrg` account, the following **Disconnect** button ...@@ -242,6 +242,42 @@ For example, to unlink the `MyOrg` account, the following **Disconnect** button
![Unlink Group SAML](img/unlink_group_saml.png) ![Unlink Group SAML](img/unlink_group_saml.png)
## Group Sync
When the SAML response includes a user and their group memberships from the SAML identity provider,
GitLab uses that information to automatically manage that user's GitLab group memberships.
Ensure your SAML identity provider sends an attribute statement named `Groups` or `groups` like the following:
```xml
<saml:AttributeStatement>
<saml:Attribute Name="Groups">
<saml:AttributeValue xsi:type="xs:string">Developers</saml:AttributeValue>
<saml:AttributeValue xsi:type="xs:string">Product Managers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
```
When SAML SSO is enabled for the top-level group, `Maintainer` and `Owner` level users
see a new menu item in group **Settings -> SAML Group Links**. Each group can specify
one or more group links to map a SAML identity provider group name to a GitLab access level.
![SAML Group Links navigation](img/saml_group_links_nav_v13_6.png)
To link the SAML `Freelancers` group in the attribute statement example above:
1. Enter `Freelancers` in the `SAML Group Name` field.
1. Choose the desired `Access Level`.
1. **Save** the group link.
1. Repeat to add additional group links if desired.
![SAML Group Links](img/saml_group_links_v13_6.png)
If a user is a member of multiple SAML groups mapped to the same GitLab group,
the user gets the highest access level from the groups. For example, if one group
is linked as `Guest` and another `Maintainer`, a user in both groups gets `Maintainer`
access.
## Glossary ## Glossary
| Term | Description | | Term | Description |
......
...@@ -30,7 +30,7 @@ module Groups ...@@ -30,7 +30,7 @@ module Groups
private private
def require_saml_group_links_enabled def require_saml_group_links_enabled
render_404 unless ::Feature.enabled?(:saml_group_links, group) render_404 unless ::Feature.enabled?(:saml_group_links, group, default_enabled: true)
end end
def authorize_admin_saml_group_links! def authorize_admin_saml_group_links!
......
...@@ -7,7 +7,7 @@ module EE ...@@ -7,7 +7,7 @@ module EE
end end
def show_saml_group_links_in_sidebar?(group) def show_saml_group_links_in_sidebar?(group)
::Feature.enabled?(:saml_group_links, group) && can?(current_user, :admin_saml_group_links, group) can?(current_user, :admin_saml_group_links, group)
end end
def saml_link_for_provider(text, provider, **args) def saml_link_for_provider(text, provider, **args)
......
...@@ -227,7 +227,7 @@ module EE ...@@ -227,7 +227,7 @@ module EE
end end
def saml_group_sync_available? def saml_group_sync_available?
::Feature.enabled?(:saml_group_links, self) && ::Feature.enabled?(:saml_group_links, self, default_enabled: true) &&
feature_available?(:group_saml_group_sync) && root_ancestor.saml_enabled? feature_available?(:group_saml_group_sync) && root_ancestor.saml_enabled?
end end
......
...@@ -91,6 +91,7 @@ class License < ApplicationRecord ...@@ -91,6 +91,7 @@ class License < ApplicationRecord
group_project_templates group_project_templates
group_repository_analytics group_repository_analytics
group_saml group_saml
group_saml_group_sync
group_wikis group_wikis
incident_sla incident_sla
ide_schema_config ide_schema_config
...@@ -145,7 +146,6 @@ class License < ApplicationRecord ...@@ -145,7 +146,6 @@ class License < ApplicationRecord
license_scanning license_scanning
personal_access_token_expiration_policy personal_access_token_expiration_policy
enforce_pat_expiration enforce_pat_expiration
group_saml_group_sync
prometheus_alerts prometheus_alerts
pseudonymizer pseudonymizer
release_evidence_test_artifacts release_evidence_test_artifacts
......
...@@ -78,7 +78,7 @@ module EE ...@@ -78,7 +78,7 @@ module EE
end end
condition(:group_saml_group_sync_available, scope: :subject) do condition(:group_saml_group_sync_available, scope: :subject) do
@subject.feature_available?(:group_saml_group_sync) @subject.saml_group_sync_available?
end end
condition(:group_timelogs_available) do condition(:group_timelogs_available) do
...@@ -205,7 +205,7 @@ module EE ...@@ -205,7 +205,7 @@ module EE
rule { group_saml_config_enabled & group_saml_available & (admin | owner) }.enable :admin_group_saml rule { group_saml_config_enabled & group_saml_available & (admin | owner) }.enable :admin_group_saml
rule { group_saml_group_sync_available & group_saml_enabled & can?(:admin_group_saml) }.policy do rule { group_saml_config_enabled & group_saml_group_sync_available & (admin | owner) }.policy do
enable :admin_saml_group_links enable :admin_saml_group_links
end end
......
---
title: Sync groups on sign-in for GitLab.com Group SAML
merge_request: 47445
author:
type: added
...@@ -37,35 +37,20 @@ RSpec.describe EE::SamlProvidersHelper do ...@@ -37,35 +37,20 @@ RSpec.describe EE::SamlProvidersHelper do
describe '#show_saml_group_links_in_sidebar?' do describe '#show_saml_group_links_in_sidebar?' do
subject { helper.show_saml_group_links_in_sidebar?(group) } subject { helper.show_saml_group_links_in_sidebar?(group) }
context 'when the feature is disabled' do context 'when the user can admin saml group links' do
before do before do
stub_feature_flags(saml_group_links: false)
stub_can(:admin_saml_group_links, true) stub_can(:admin_saml_group_links, true)
end end
it { is_expected.to eq(false) } it { is_expected.to eq(true) }
end end
context 'when the feature is enabled' do context 'when the user cannot admin saml group links' do
before do before do
stub_feature_flags(saml_group_links: true) stub_can(:admin_saml_group_links, false)
end
context 'when the user can admin saml group links' do
before do
stub_can(:admin_saml_group_links, true)
end
it { is_expected.to eq(true) }
end end
context 'when the user cannot admin saml group links' do it { is_expected.to eq(false) }
before do
stub_can(:admin_saml_group_links, false)
end
it { is_expected.to eq(false) }
end
end end
end end
end end
...@@ -285,11 +285,11 @@ RSpec.describe GroupPolicy do ...@@ -285,11 +285,11 @@ RSpec.describe GroupPolicy do
end end
describe 'per group SAML' do describe 'per group SAML' do
context 'when group_saml is unavailable' do def stub_group_saml_config(enabled)
def stub_group_saml_config(enabled) allow(::Gitlab::Auth::GroupSaml::Config).to receive_messages(enabled?: enabled)
allow(::Gitlab::Auth::GroupSaml::Config).to receive_messages(enabled?: enabled) end
end
context 'when group_saml is unavailable' do
let(:current_user) { owner } let(:current_user) { owner }
context 'when group saml config is disabled' do context 'when group saml config is disabled' do
...@@ -347,12 +347,13 @@ RSpec.describe GroupPolicy do ...@@ -347,12 +347,13 @@ RSpec.describe GroupPolicy do
context 'when group_saml_group_sync is licensed' do context 'when group_saml_group_sync is licensed' do
before do before do
stub_group_saml_config(true)
stub_application_setting(check_namespace_plan: true) stub_application_setting(check_namespace_plan: true)
end end
before_all do before_all do
create(:license, plan: License::ULTIMATE_PLAN) create(:license, plan: License::ULTIMATE_PLAN)
create(:gitlab_subscription, :gold, namespace: group) create(:gitlab_subscription, :silver, namespace: group)
end end
context 'without an enabled SAML provider' do context 'without an enabled SAML provider' do
...@@ -398,6 +399,15 @@ RSpec.describe GroupPolicy do ...@@ -398,6 +399,15 @@ RSpec.describe GroupPolicy do
it { is_expected.to be_allowed(:admin_saml_group_links) } it { is_expected.to be_allowed(:admin_saml_group_links) }
end end
context 'when the group is a subgroup' do
let_it_be(:subgroup) { create(:group, :private, parent: group) }
let(:current_user) { owner }
subject { described_class.new(current_user, subgroup) }
it { is_expected.to be_allowed(:admin_saml_group_links) }
end
end end
end end
......
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