From 33401ff1448ff55b38b8ca1e6a2ad49f39e9fd64 Mon Sep 17 00:00:00 2001
From: Brian Kabiro <4353908-briankabiro@users.noreply.gitlab.com>
Date: Wed, 15 Apr 2020 12:09:59 +0000
Subject: [PATCH] Restrict access when restricted visibility level is public

Some organizations prefer to have all Gitlab related data private
but it is currently possible for non-authenticated users to access
certain pages e.g /public and /explore

This change makes it possible to restrict access by
checking if `public` is included in the restricted visibility
level setting.

* require authentication for /explore, /help, and /public for non-authenticated users.
* remove the Explore link from the sign in page.
* redirect an unauthenticated user attempting to access /help to https://docs.gitlab.com/.
---
 app/controllers/application_controller.rb     |  4 +++
 .../explore/application_controller.rb         |  2 +-
 app/controllers/help_controller.rb            |  2 +-
 app/helpers/explore_helper.rb                 |  4 +++
 app/views/layouts/devise.html.haml            |  6 ++--
 app/views/layouts/devise_empty.html.haml      |  5 +--
 doc/install/aws/index.md                      |  2 +-
 doc/public_access/public_access.md            | 10 ++++++
 .../visibility_and_access_controls.md         |  2 +-
 ...ss-control-for-restricted-public-level.yml |  5 +++
 ee/spec/features/users/login_spec.rb          | 31 +++++++++++++++++++
 ee/spec/features/users/signup_spec.rb         | 25 +++++++++++++++
 .../explore/groups_controller_spec.rb         | 14 +++++++++
 .../explore/projects_controller_spec.rb       | 12 +++++++
 spec/controllers/help_controller_spec.rb      | 14 +++++++++
 spec/features/explore/groups_spec.rb          | 12 +++++++
 .../explore/user_explores_projects_spec.rb    | 11 +++++++
 17 files changed, 153 insertions(+), 8 deletions(-)
 create mode 100644 ee/changelogs/unreleased/18165-add-access-control-for-restricted-public-level.yml
 create mode 100644 ee/spec/features/users/signup_spec.rb

diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c5c586ea48922..b2496427924a0 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -496,6 +496,10 @@ def should_enforce_terms?
     html_request? && !devise_controller?
   end
 
+  def public_visibility_restricted?
+    Gitlab::CurrentSettings.restricted_visibility_levels.include? Gitlab::VisibilityLevel::PUBLIC
+  end
+
   def set_usage_stats_consent_flag
     return unless current_user
     return if sessionless_user?
diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb
index 8eee3742d89bd..9d33135d4c120 100644
--- a/app/controllers/explore/application_controller.rb
+++ b/app/controllers/explore/application_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class Explore::ApplicationController < ApplicationController
-  skip_before_action :authenticate_user!
+  skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
 
   layout 'explore'
 end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index 97895d6461ce7..91bba1eb617c3 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class HelpController < ApplicationController
-  skip_before_action :authenticate_user!
+  skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
 
   layout 'help'
 
diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb
index 1b36f60c3163b..b341cc795a026 100644
--- a/app/helpers/explore_helper.rb
+++ b/app/helpers/explore_helper.rb
@@ -51,6 +51,10 @@ def any_explore_nav_link?(links)
     links.any? { |link| explore_nav_link?(link) }
   end
 
+  def public_visibility_restricted?
+    Gitlab::CurrentSettings.restricted_visibility_levels.include? Gitlab::VisibilityLevel::PUBLIC
+  end
+
   private
 
   def get_explore_nav_links
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index d36e08f44a4ac..6a261bbbc4684 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -38,7 +38,9 @@
       %hr.footer-fixed
       .container.footer-container
         .footer-links
-          = link_to _("Explore"), explore_root_path
-          = link_to _("Help"), help_path
+          - if !public_visibility_restricted?
+            = link_to _("Explore"), explore_root_path
+            = link_to _("Help"), help_path
           = link_to _("About GitLab"), "https://about.gitlab.com/"
+
       = footer_message
diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml
index ff2b00ea3763c..6ac80a5aba3fd 100644
--- a/app/views/layouts/devise_empty.html.haml
+++ b/app/views/layouts/devise_empty.html.haml
@@ -14,7 +14,8 @@
     %hr
     .container
       .footer-links
-        = link_to _("Explore"), explore_root_path
-        = link_to _("Help"), help_path
+        - if !public_visibility_restricted?
+          = link_to _("Explore"), explore_root_path
+          = link_to _("Help"), help_path
         = link_to _("About GitLab"), "https://about.gitlab.com/"
     = footer_message
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 109cd635dc060..d510dff82ddda 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -205,7 +205,7 @@ On the EC2 dashboard, look for Load Balancer in the left navigation bar:
 1. Click **Configure Health Check** and set up a health check for your EC2 instances.
    1. For **Ping Protocol**, select HTTP.
    1. For **Ping Port**, enter 80.
-   1. For **Ping Path**, enter `/explore`. (We use `/explore` as it's a public endpoint that does
+   1. For **Ping Path**, enter `/users/sign_in`. (We use `/users/sign_in` as it's a public endpoint that does
    not require authorization.)
    1. Keep the default **Advanced Details** or adjust them according to your needs.
 1. Click **Add EC2 Instances** but, as we don't have any instances to add yet, come back
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index d7b2222fa06b0..0ca2da1db6397 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -69,6 +69,16 @@ you are privileged to.
 
 If the public level is restricted, user profiles are only visible to logged in users.
 
+## Visibility of pages
+
+By default, the following directories are visible to unauthenticated users:
+
+- Public access (`/public`).
+- Explore (`/explore`).
+- Help (`/help`).
+
+However, if the access level of the `/public` directory is restricted, these directories are visible only to logged in users.
+
 ## Restricting the use of public or internal projects
 
 You can restrict the use of visibility levels for users when they create a project or a
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 704dd89ede255..f827fed833be0 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -91,7 +91,7 @@ For more details on group visibility, see [Public access](../../../public_access
 
 ## Restricted visibility levels
 
-To set the available visibility levels for new projects and snippets:
+To set the available visibility levels for projects, snippets, and selected pages:
 
 1. Check the desired visibility levels.
 1. Click **Save changes**.
diff --git a/ee/changelogs/unreleased/18165-add-access-control-for-restricted-public-level.yml b/ee/changelogs/unreleased/18165-add-access-control-for-restricted-public-level.yml
new file mode 100644
index 0000000000000..16e35e3b11d5f
--- /dev/null
+++ b/ee/changelogs/unreleased/18165-add-access-control-for-restricted-public-level.yml
@@ -0,0 +1,5 @@
+---
+title: Restrict page access when restricted level is public
+merge_request: 22522
+author: briankabiro
+type: added
diff --git a/ee/spec/features/users/login_spec.rb b/ee/spec/features/users/login_spec.rb
index 175275a5b51e7..81bf6c271cc8e 100644
--- a/ee/spec/features/users/login_spec.rb
+++ b/ee/spec/features/users/login_spec.rb
@@ -186,4 +186,35 @@
       end
     end
   end
+
+  describe 'restricted visibility levels' do
+    context 'contains public level' do
+      before do
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+      end
+
+      it 'hides Explore link' do
+        visit new_user_session_path
+
+        expect(page).to have_no_link("Explore")
+      end
+
+      it 'hides help link' do
+        visit new_user_session_path
+
+        expect(page).to have_no_link("Help")
+      end
+    end
+
+    context 'does not contain public level' do
+      it 'displays Explore and Help links' do
+        visit new_user_session_path
+
+        href = find_link("Help")[:href]
+
+        expect(href).to eq("/help")
+        expect(page).to have_link("Explore")
+      end
+    end
+  end
 end
diff --git a/ee/spec/features/users/signup_spec.rb b/ee/spec/features/users/signup_spec.rb
new file mode 100644
index 0000000000000..1ae08f8e6f012
--- /dev/null
+++ b/ee/spec/features/users/signup_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Signup' do
+  context 'almost there page' do
+    context 'when public visibility is restricted' do
+      before do
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+      end
+
+      it 'hides Explore link' do
+        visit users_almost_there_path
+
+        expect(page).to have_no_link("Explore")
+      end
+
+      it 'hides help link' do
+        visit users_almost_there_path
+
+        expect(page).to have_no_link("Help")
+      end
+    end
+  end
+end
diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb
index 5a32d8ca0d3ca..eccbd7fa14dbd 100644
--- a/spec/controllers/explore/groups_controller_spec.rb
+++ b/spec/controllers/explore/groups_controller_spec.rb
@@ -22,4 +22,18 @@
 
     expect(assigns(:groups)).to contain_exactly(member_of_group, public_group)
   end
+
+  context 'restricted visibility level is public' do
+    before do
+      sign_out(user)
+
+      stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+    end
+
+    it 'redirects to login page' do
+      get :index
+
+      expect(response).to redirect_to new_user_session_path
+    end
+  end
 end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index c2cd29eb0365d..00cc2d5a81c90 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -171,5 +171,17 @@
         get :index, params: { sort: sorting_param }
       end
     end
+
+    context 'restricted visibility level is public' do
+      before do
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+      end
+
+      it 'redirects to login page' do
+        get :index
+
+        expect(response).to redirect_to new_user_session_path
+      end
+    end
   end
 end
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index e010cac2f7353..f03fee8d3ae69 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -79,6 +79,20 @@
         expect(assigns[:help_index]).to eq '[protocol-relative](//example.com)'
       end
     end
+
+    context 'restricted visibility set to public' do
+      before do
+        sign_out(user)
+
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+      end
+
+      it 'redirects to sign_in path' do
+        get :index
+
+        expect(response).to redirect_to(new_user_session_path)
+      end
+    end
   end
 
   describe 'GET #show' do
diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb
index eff63d6a788dd..50ec44580d2c8 100644
--- a/spec/features/explore/groups_spec.rb
+++ b/spec/features/explore/groups_spec.rb
@@ -89,5 +89,17 @@
     end
 
     it_behaves_like 'renders group in public groups area'
+
+    context 'when visibility is restricted to public' do
+      before do
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+      end
+
+      it 'redirects to the sign in page' do
+        visit explore_groups_path
+
+        expect(page).to have_current_path(new_user_session_path)
+      end
+    end
   end
 end
diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb
index c64709c0b5551..6adf51a1cf60f 100644
--- a/spec/features/explore/user_explores_projects_spec.rb
+++ b/spec/features/explore/user_explores_projects_spec.rb
@@ -16,6 +16,17 @@
 
       include_examples 'shows public projects'
     end
+
+    context 'when visibility is restricted to public' do
+      before do
+        stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+        visit(explore_projects_path)
+      end
+
+      it 'redirects to login page' do
+        expect(page).to have_current_path(new_user_session_path)
+      end
+    end
   end
 
   context 'when signed in' do
-- 
GitLab