Commit 7637c145 authored by Adam Hegyi's avatar Adam Hegyi Committed by Thong Kuah

Redirect to the exact group after Group SAML login

This change initiates SSO login when an unauthanticated user tries
to access a group, subgroup or a project when the group_saml feature is
enabled.
parent bf9225b9
......@@ -20,7 +20,7 @@ module EE
end
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
module ControllerActions
......@@ -59,6 +59,13 @@ module EE
def root_group
@root_group ||= group.root_ancestor
end
def url_params
{
token: root_group.saml_discovery_token,
redirect: "/#{routable.full_path}"
}
end
end
end
end
# frozen_string_literal: true
class Groups::SsoController < Groups::ApplicationController
include InternalRedirect
skip_before_action :group
before_action :authenticate_user!, only: [:unlink]
......@@ -13,7 +14,8 @@ class Groups::SsoController < Groups::ApplicationController
layout 'devise'
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_saml_identity = linked_identity
@idp_url = unauthenticated_group.saml_provider.sso_url
......
......@@ -13,7 +13,7 @@
- if @group_saml_identity || !user_signed_in?
%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
.card.card-body.bs-callout-warning
= _("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
end
def self.group_access_restricted?(group)
return false unless ::Feature.enabled?(:enforced_sso_requires_session, 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
......
......@@ -81,7 +81,9 @@ describe EE::RoutableActions::SsoEnforcementRedirect do
describe '#sso_redirect_url' do
shared_examples 'a routable SSO url' 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
......
......@@ -42,7 +42,7 @@ describe RoutableActions do
get :show, params: request_params(routable)
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
it 'does not redirect on POST requests' do
......
......@@ -87,7 +87,7 @@ describe GroupsController do
get :show, params: { id: group }
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
......
......@@ -19,6 +19,13 @@ describe Groups::SsoController do
expect(response).to have_gitlab_http_status(200)
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
get :saml, params: { group_id: group }
......
......@@ -20,7 +20,7 @@ describe 'SAML access enforcement' do
visit group_path(group)
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
......
......@@ -79,4 +79,45 @@ describe Gitlab::Auth::GroupSaml::SsoEnforcer do
expect(subject).not_to be_access_restricted
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
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