Commit a6d89b00 authored by Nick Thomas's avatar Nick Thomas

Merge branch '32095-allow-administrators-to-disable-gitlab-pages-access' into 'master'

Allow administrators to force access control for gitlab pages (disable public pages)

See merge request gitlab-org/gitlab!22003
parents b3a5416b 7d216055
...@@ -82,6 +82,11 @@ export default { ...@@ -82,6 +82,11 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
pagesAccessControlForced: {
type: Boolean,
required: false,
default: false,
},
pagesHelpPath: { pagesHelpPath: {
type: String, type: String,
required: false, required: false,
...@@ -130,10 +135,22 @@ export default { ...@@ -130,10 +135,22 @@ export default {
}, },
pagesFeatureAccessLevelOptions() { pagesFeatureAccessLevelOptions() {
if (this.visibilityLevel !== visibilityOptions.PUBLIC) { const options = [featureAccessLevelMembers];
return this.featureAccessLevelOptions.concat([[30, PAGE_FEATURE_ACCESS_LEVEL]]);
if (this.pagesAccessControlForced) {
if (this.visibilityLevel === visibilityOptions.INTERNAL) {
options.push(featureAccessLevelEveryone);
}
} else {
if (this.visibilityLevel !== visibilityOptions.PRIVATE) {
options.push(featureAccessLevelEveryone);
}
if (this.visibilityLevel !== visibilityOptions.PUBLIC) {
options.push([30, PAGE_FEATURE_ACCESS_LEVEL]);
}
} }
return this.featureAccessLevelOptions; return options;
}, },
repositoryEnabled() { repositoryEnabled() {
......
...@@ -202,6 +202,7 @@ module ApplicationSettingsHelper ...@@ -202,6 +202,7 @@ module ApplicationSettingsHelper
:enabled_git_access_protocol, :enabled_git_access_protocol,
:enforce_terms, :enforce_terms,
:first_day_of_week, :first_day_of_week,
:force_pages_access_control,
:gitaly_timeout_default, :gitaly_timeout_default,
:gitaly_timeout_medium, :gitaly_timeout_medium,
:gitaly_timeout_fast, :gitaly_timeout_fast,
......
...@@ -587,6 +587,7 @@ module ProjectsHelper ...@@ -587,6 +587,7 @@ module ProjectsHelper
lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs'), lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs'),
pagesAvailable: Gitlab.config.pages.enabled, pagesAvailable: Gitlab.config.pages.enabled,
pagesAccessControlEnabled: Gitlab.config.pages.access_control, pagesAccessControlEnabled: Gitlab.config.pages.access_control,
pagesAccessControlForced: ::Gitlab::Pages.access_control_is_forced?,
pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control-core') pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control-core')
} }
end end
......
...@@ -97,7 +97,13 @@ class ProjectFeature < ApplicationRecord ...@@ -97,7 +97,13 @@ class ProjectFeature < ApplicationRecord
default_value_for :wiki_access_level, value: ENABLED, allows_nil: false default_value_for :wiki_access_level, value: ENABLED, allows_nil: false
default_value_for :repository_access_level, value: ENABLED, allows_nil: false default_value_for :repository_access_level, value: ENABLED, allows_nil: false
default_value_for(:pages_access_level, allows_nil: false) { |feature| feature.project&.public? ? ENABLED : PRIVATE } default_value_for(:pages_access_level, allows_nil: false) do |feature|
if ::Gitlab::Pages.access_control_is_forced?
PRIVATE
else
feature.project&.public? ? ENABLED : PRIVATE
end
end
def feature_available?(feature, user) def feature_available?(feature, user)
# This feature might not be behind a feature flag at all, so default to true # This feature might not be behind a feature flag at all, so default to true
...@@ -137,6 +143,8 @@ class ProjectFeature < ApplicationRecord ...@@ -137,6 +143,8 @@ class ProjectFeature < ApplicationRecord
def public_pages? def public_pages?
return true unless Gitlab.config.pages.access_control return true unless Gitlab.config.pages.access_control
return false if ::Gitlab::Pages.access_control_is_forced?
pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public? pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public?
end end
......
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
.form-text.text-muted .form-text.text-muted
= _("Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled") = _("Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled")
= link_to icon('question-circle'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership') = link_to icon('question-circle'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership')
- if Gitlab.config.pages.access_control
.form-group
.form-check
= f.check_box :force_pages_access_control, class: 'form-check-input'
= f.label :force_pages_access_control, class: 'form-check-label' do
= _("Disable public access to Pages sites")
.form-text.text-muted
= _("Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance.")
= link_to icon('question-circle'), help_page_path('administration/pages/index.md', anchor: 'disabling-public-access-to-all-pages-websites')
%h5 %h5
= _("Configure Let's Encrypt") = _("Configure Let's Encrypt")
%p %p
......
---
title: Allow administrators to enforce access control for all pages web-sites
merge_request: 22003
author:
type: added
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddForcePagesAccessControlToApplicationSettings < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_column :application_settings, :force_pages_access_control, :boolean, null: false, default: false
end
end
...@@ -364,6 +364,7 @@ ActiveRecord::Schema.define(version: 2020_01_08_233040) do ...@@ -364,6 +364,7 @@ ActiveRecord::Schema.define(version: 2020_01_08_233040) do
t.string "encrypted_slack_app_secret_iv", limit: 255 t.string "encrypted_slack_app_secret_iv", limit: 255
t.text "encrypted_slack_app_verification_token" t.text "encrypted_slack_app_verification_token"
t.string "encrypted_slack_app_verification_token_iv", limit: 255 t.string "encrypted_slack_app_verification_token_iv", limit: 255
t.boolean "force_pages_access_control", default: false, null: false
t.boolean "updating_name_disabled_for_users", default: false, null: false t.boolean "updating_name_disabled_for_users", default: false, null: false
t.integer "instance_administrators_group_id" t.integer "instance_administrators_group_id"
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id" t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id"
......
...@@ -307,6 +307,27 @@ Pages access control is disabled by default. To enable it: ...@@ -307,6 +307,27 @@ Pages access control is disabled by default. To enable it:
1. [Reconfigure GitLab][reconfigure]. 1. [Reconfigure GitLab][reconfigure].
1. Users can now configure it in their [projects' settings](../../user/project/pages/pages_access_control.md). 1. Users can now configure it in their [projects' settings](../../user/project/pages/pages_access_control.md).
#### Disabling public access to all Pages websites
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/32095) in GitLab 12.7.
You can enforce [Access Control](#access-control) for all GitLab Pages websites hosted
on your GitLab instance. By doing so, only logged-in users will have access to them.
This setting overrides Access Control set by users in individual projects.
This can be useful to preserve information published with Pages websites to the users
of your instance only.
To do that:
1. Navigate to your instance's **Admin Area > Settings > Preferences** and expand **Pages** settings.
1. Check the **Disable public access to Pages sites** checkbox.
1. Click **Save changes**.
CAUTION: **Warning:**
This action will not make all currently public web-sites private until they redeployed.
This issue among others will be resolved by
[changing GitLab Pages configuration mechanism](https://gitlab.com/gitlab-org/gitlab-pages/issues/282).
### Running behind a proxy ### Running behind a proxy
Like the rest of GitLab, Pages can be used in those environments where external Like the rest of GitLab, Pages can be used in those environments where external
......
...@@ -18,6 +18,11 @@ module Gitlab ...@@ -18,6 +18,11 @@ module Gitlab
def secret_path def secret_path
Gitlab.config.pages.secret_file Gitlab.config.pages.secret_file
end end
def access_control_is_forced?
::Gitlab.config.pages.access_control &&
::Gitlab::CurrentSettings.current_application_settings.force_pages_access_control
end
end end
end end
end end
...@@ -847,6 +847,9 @@ msgstr "" ...@@ -847,6 +847,9 @@ msgstr ""
msgid "Access to '%{classification_label}' not allowed" msgid "Access to '%{classification_label}' not allowed"
msgstr "" msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
msgid "AccessDropdown|Groups" msgid "AccessDropdown|Groups"
msgstr "" msgstr ""
...@@ -6324,6 +6327,9 @@ msgstr "" ...@@ -6324,6 +6327,9 @@ msgstr ""
msgid "Disable group Runners" msgid "Disable group Runners"
msgstr "" msgstr ""
msgid "Disable public access to Pages sites"
msgstr ""
msgid "Disable shared Runners" msgid "Disable shared Runners"
msgstr "" msgstr ""
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Pages do describe Gitlab::Pages do
using RSpec::Parameterized::TableSyntax
let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) } let(:pages_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
before do before do
...@@ -26,4 +28,24 @@ describe Gitlab::Pages do ...@@ -26,4 +28,24 @@ describe Gitlab::Pages do
expect(described_class.verify_api_request(headers)).to eq([{ "iss" => "gitlab-pages" }, { "alg" => "HS256" }]) expect(described_class.verify_api_request(headers)).to eq([{ "iss" => "gitlab-pages" }, { "alg" => "HS256" }])
end end
end end
describe '.access_control_is_forced?' do
subject { described_class.access_control_is_forced? }
where(:access_control_is_enabled, :access_control_is_forced, :result) do
false | false | false
false | true | false
true | false | false
true | true | true
end
with_them do
before do
stub_pages_setting(access_control: access_control_is_enabled)
stub_application_setting(force_pages_access_control: access_control_is_forced)
end
it { is_expected.to eq(result) }
end
end
end end
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe ProjectFeature do describe ProjectFeature do
using RSpec::Parameterized::TableSyntax
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -121,13 +123,14 @@ describe ProjectFeature do ...@@ -121,13 +123,14 @@ describe ProjectFeature do
end end
context 'public features' do context 'public features' do
it "does not allow public for other than pages" do features = %w(issues wiki builds merge_requests snippets repository)
features = %w(issues wiki builds merge_requests snippets repository)
project_feature = project.project_feature
features.each do |feature| features.each do |feature|
it "does not allow public access level for #{feature}" do
project_feature = project.project_feature
field = "#{feature}_access_level".to_sym field = "#{feature}_access_level".to_sym
project_feature.update_attribute(field, ProjectFeature::PUBLIC) project_feature.update_attribute(field, ProjectFeature::PUBLIC)
expect(project_feature.valid?).to be_falsy expect(project_feature.valid?).to be_falsy
end end
end end
...@@ -158,12 +161,13 @@ describe ProjectFeature do ...@@ -158,12 +161,13 @@ describe ProjectFeature do
end end
describe 'default pages access level' do describe 'default pages access level' do
subject { project.project_feature.pages_access_level } subject { project_feature.pages_access_level }
before do let(:project_feature) do
# project factory overrides all values in project_feature after creation # project factory overrides all values in project_feature after creation
project.project_feature.destroy! project.project_feature.destroy!
project.build_project_feature.save! project.build_project_feature.save!
project.project_feature
end end
context 'when new project is private' do context 'when new project is private' do
...@@ -182,6 +186,14 @@ describe ProjectFeature do ...@@ -182,6 +186,14 @@ describe ProjectFeature do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
it { is_expected.to eq(ProjectFeature::ENABLED) } it { is_expected.to eq(ProjectFeature::ENABLED) }
context 'when access control is forced on the admin level' do
before do
allow(::Gitlab::Pages).to receive(:access_control_is_forced?).and_return(true)
end
it { is_expected.to eq(ProjectFeature::PRIVATE) }
end
end end
end end
...@@ -189,53 +201,59 @@ describe ProjectFeature do ...@@ -189,53 +201,59 @@ describe ProjectFeature do
it 'returns true if Pages access controll is not enabled' do it 'returns true if Pages access controll is not enabled' do
stub_config(pages: { access_control: false }) stub_config(pages: { access_control: false })
project_feature = described_class.new project_feature = described_class.new(pages_access_level: described_class::PRIVATE)
expect(project_feature.public_pages?).to eq(true) expect(project_feature.public_pages?).to eq(true)
end end
context 'Pages access control is enabled' do context 'when Pages access control is enabled' do
before do before do
stub_config(pages: { access_control: true }) stub_config(pages: { access_control: true })
end end
it 'returns true if Pages access level is public' do where(:project_visibility, :pages_access_level, :result) do
project_feature = described_class.new(pages_access_level: described_class::PUBLIC) :private | ProjectFeature::PUBLIC | true
:internal | ProjectFeature::PUBLIC | true
expect(project_feature.public_pages?).to eq(true) :internal | ProjectFeature::ENABLED | false
:public | ProjectFeature::ENABLED | true
:private | ProjectFeature::PRIVATE | false
:public | ProjectFeature::PRIVATE | false
end end
it 'returns true if Pages access level is enabled and the project is public' do with_them do
project = build(:project, :public) let(:project_feature) do
project = build(:project, project_visibility)
project_feature = described_class.new(project: project, pages_access_level: described_class::ENABLED) project_feature = project.project_feature
project_feature.update!(pages_access_level: pages_access_level)
expect(project_feature.public_pages?).to eq(true) project_feature
end end
it 'returns false if pages or the project are not public' do it 'properly handles project and Pages visibility settings' do
project = build(:project, :private) expect(project_feature.public_pages?).to eq(result)
end
project_feature = described_class.new(project: project, pages_access_level: described_class::ENABLED) it 'returns false if access_control is forced on the admin level' do
stub_application_setting(force_pages_access_control: true)
expect(project_feature.public_pages?).to eq(false) expect(project_feature.public_pages?).to eq(false)
end
end end
end end
end
describe '#private_pages?' do describe '#private_pages?' do
subject(:project_feature) { described_class.new } subject(:project_feature) { described_class.new }
it 'returns false if public_pages? is true' do it 'returns false if public_pages? is true' do
expect(project_feature).to receive(:public_pages?).and_return(true) expect(project_feature).to receive(:public_pages?).and_return(true)
expect(project_feature.private_pages?).to eq(false) expect(project_feature.private_pages?).to eq(false)
end end
it 'returns true if public_pages? is false' do it 'returns true if public_pages? is false' do
expect(project_feature).to receive(:public_pages?).and_return(false) expect(project_feature).to receive(:public_pages?).and_return(false)
expect(project_feature.private_pages?).to eq(true) expect(project_feature.private_pages?).to eq(true)
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