Commit ae49dd01 authored by Thong Kuah's avatar Thong Kuah

Merge branch '12189-sso-enforcement-should-enforce-on-subgroups' into 'master'

Resolve "SSO enforcement should enforce on subgroups"

Closes #12189

See merge request gitlab-org/gitlab-ee!14364
parents bf9225b9 7637c145
...@@ -20,7 +20,7 @@ module EE ...@@ -20,7 +20,7 @@ module EE
end end
def sso_redirect_url def sso_redirect_url
sso_group_saml_providers_url(root_group, token: root_group.saml_discovery_token) sso_group_saml_providers_url(root_group, url_params)
end end
module ControllerActions module ControllerActions
...@@ -59,6 +59,13 @@ module EE ...@@ -59,6 +59,13 @@ module EE
def root_group def root_group
@root_group ||= group.root_ancestor @root_group ||= group.root_ancestor
end end
def url_params
{
token: root_group.saml_discovery_token,
redirect: "/#{routable.full_path}"
}
end
end end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
class Groups::SsoController < Groups::ApplicationController class Groups::SsoController < Groups::ApplicationController
include InternalRedirect
skip_before_action :group skip_before_action :group
before_action :authenticate_user!, only: [:unlink] before_action :authenticate_user!, only: [:unlink]
...@@ -13,7 +14,8 @@ class Groups::SsoController < Groups::ApplicationController ...@@ -13,7 +14,8 @@ class Groups::SsoController < Groups::ApplicationController
layout 'devise' layout 'devise'
def saml def saml
@group_path = params[:group_id] @redirect_path = safe_redirect_path(params[:redirect]) || group_path(unauthenticated_group)
@group_path = unauthenticated_group.path
@group_name = unauthenticated_group.full_name @group_name = unauthenticated_group.full_name
@group_saml_identity = linked_identity @group_saml_identity = linked_identity
@idp_url = unauthenticated_group.saml_provider.sso_url @idp_url = unauthenticated_group.saml_provider.sso_url
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
- if @group_saml_identity || !user_signed_in? - if @group_saml_identity || !user_signed_in?
%p= _("This will redirect you to an external sign in page.") %p= _("This will redirect you to an external sign in page.")
= saml_link _('Sign in with Single Sign-On'), @group_path, html_class: 'btn btn-success btn-block qa-saml-sso-signin-button' = saml_link _('Sign in with Single Sign-On'), @group_path, html_class: 'btn btn-success btn-block qa-saml-sso-signin-button', redirect: @redirect_path
- else - else
.card.card-body.bs-callout-warning .card.card-body.bs-callout-warning
= _("Only proceed if you trust %{idp_url} to control your GitLab account sign in.") % { idp_url: @idp_url } = _("Only proceed if you trust %{idp_url} to control your GitLab account sign in.") % { idp_url: @idp_url }
......
---
title: Enforce SSO on subgroups and projects
merge_request: 14364
author:
type: fixed
...@@ -23,10 +23,11 @@ module Gitlab ...@@ -23,10 +23,11 @@ module Gitlab
end end
def self.group_access_restricted?(group) def self.group_access_restricted?(group)
return false unless ::Feature.enabled?(:enforced_sso_requires_session, group)
return false unless group return false unless group
return false unless group.root_ancestor
return false unless ::Feature.enabled?(:enforced_sso_requires_session, group.root_ancestor)
saml_provider = group&.root_ancestor&.saml_provider saml_provider = group.root_ancestor.saml_provider
return false unless saml_provider return false unless saml_provider
......
...@@ -81,7 +81,9 @@ describe EE::RoutableActions::SsoEnforcementRedirect do ...@@ -81,7 +81,9 @@ describe EE::RoutableActions::SsoEnforcementRedirect do
describe '#sso_redirect_url' do describe '#sso_redirect_url' do
shared_examples 'a routable SSO url' do shared_examples 'a routable SSO url' do
it 'returns the SSO url for the root group' do it 'returns the SSO url for the root group' do
expect(subject.sso_redirect_url).to match(/groups\/#{root_group.to_param}\/-\/saml\/sso\?token=/) redirect_url = CGI.escape("/#{subject.routable.full_path}")
expect(subject.sso_redirect_url).to match(/groups\/#{root_group.to_param}\/-\/saml\/sso\?redirect=#{redirect_url}&token=/)
end end
end end
......
...@@ -42,7 +42,7 @@ describe RoutableActions do ...@@ -42,7 +42,7 @@ describe RoutableActions do
get :show, params: request_params(routable) get :show, params: request_params(routable)
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(response.location).to match(/groups\/.*\/-\/saml\/sso\?token=/) expect(response.location).to match(/groups\/.*\/-\/saml\/sso\?redirect=.+&token=/)
end end
it 'does not redirect on POST requests' do it 'does not redirect on POST requests' do
......
...@@ -87,7 +87,7 @@ describe GroupsController do ...@@ -87,7 +87,7 @@ describe GroupsController do
get :show, params: { id: group } get :show, params: { id: group }
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(response.location).to match(/groups\/#{group.to_param}\/-\/saml\/sso\?token=/) expect(response.location).to match(/groups\/#{group.to_param}\/-\/saml\/sso\?redirect=.+&token=/)
end end
end end
......
...@@ -19,6 +19,13 @@ describe Groups::SsoController do ...@@ -19,6 +19,13 @@ describe Groups::SsoController do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
end end
it 'malicious redirect parameter falls back to group_path' do
get :saml, params: { group_id: group, redirect: '///malicious-url' }
expect(response).to have_gitlab_http_status(200)
expect(assigns[:redirect_path]).to eq(group_path(group))
end
it 'passes group name to the view' do it 'passes group name to the view' do
get :saml, params: { group_id: group } get :saml, params: { group_id: group }
......
...@@ -20,7 +20,7 @@ describe 'SAML access enforcement' do ...@@ -20,7 +20,7 @@ describe 'SAML access enforcement' do
visit group_path(group) visit group_path(group)
expect(page).to have_content("SAML SSO Sign in to \"#{group.name}\"") expect(page).to have_content("SAML SSO Sign in to \"#{group.name}\"")
expect(current_url).to match(/groups\/#{group.to_param}\/-\/saml\/sso\?token=/) expect(current_url).to match(/groups\/#{group.to_param}\/-\/saml\/sso\?redirect=.+&token=/)
end end
end end
......
...@@ -79,4 +79,45 @@ describe Gitlab::Auth::GroupSaml::SsoEnforcer do ...@@ -79,4 +79,45 @@ describe Gitlab::Auth::GroupSaml::SsoEnforcer do
expect(subject).not_to be_access_restricted expect(subject).not_to be_access_restricted
end end
end end
describe '.group_access_restricted?' do
let(:root_group) { create(:group, saml_provider: create(:saml_provider, enabled: true, enforced_sso: true)) }
context 'is restricted' do
before do
stub_feature_flags(enforced_sso_requires_session: { enabled: true, thing: root_group })
end
it 'for a group' do
expect(described_class).to be_group_access_restricted(root_group)
end
it 'for a subgroup' do
sub_group = create(:group, parent: root_group)
expect(described_class).to be_group_access_restricted(sub_group)
end
it 'for a project' do
project = create(:project, group: root_group)
expect(described_class).to be_group_access_restricted(project)
end
end
context 'is not restricted' do
it 'for the group without configured saml_provider' do
group = create(:group)
stub_feature_flags(enforced_sso_requires_session: { enabled: true, thing: group })
expect(described_class).not_to be_group_access_restricted(group)
end
it 'for the group without the feature flag' do
stub_feature_flags(enforced_sso_requires_session: { enabled: false, thing: root_group })
expect(described_class).not_to be_group_access_restricted(root_group)
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