summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2016-07-05 22:57:19 +0000
committerDouwe Maan <douwe@gitlab.com>2016-07-05 22:57:19 +0000
commitcfd5870b62e9d76e564ffc64db1d1281b4a363bb (patch)
tree34adec49220b96c99aea7139cd0794405ecd7b8d
parent1141eaf5c83f927ccc064b6c5d162081fdd22894 (diff)
parent0bdf6fe4ba90f0a1dc7777d17651667776dfb91b (diff)
downloadgitlab-ce-cfd5870b62e9d76e564ffc64db1d1281b4a363bb.tar.gz
Merge branch 'allow-disabling-of-git-access-protocol' into 'master'
Add setting that allows admins to choose which Git access protocols are enabled. ## What does this MR do? It allows admins to disable one of the two protocols for Git access. They can choose to enable just SSH, HTTP or allow both. If one of them is disabled, the clone URL in the project will show only the allowed protocol, and no dropdown to change protocols will be presented. ## What are the relevant issue numbers? Full implementation on GitLab's side for #18601 GitLab Shell implementation: gitlab-org/gitlab-shell!62 GitLab Workhorse implementation: gitlab-org/gitlab-workhorse!51 ## Screenshots (if relevant) ![Screen_Shot_2016-06-16_at_12.26.19_PM](/uploads/bad845142e9704a7385b2eaca51fd4eb/Screen_Shot_2016-06-16_at_12.26.19_PM.png) ![Screen_Shot_2016-06-20_at_4.24.54_PM](/uploads/6e452dd269e06f0be23841ce93866ed6/Screen_Shot_2016-06-20_at_4.24.54_PM.png) /cc @jschatz1 this MR touches the UI. Please review. See merge request !4696
-rw-r--r--CHANGELOG1
-rw-r--r--app/assets/stylesheets/framework/buttons.scss18
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/projects/git_http_controller.rb24
-rw-r--r--app/helpers/application_settings_helper.rb22
-rw-r--r--app/helpers/branches_helper.rb2
-rw-r--r--app/helpers/button_helper.rb16
-rw-r--r--app/helpers/projects_helper.rb10
-rw-r--r--app/models/application_setting.rb3
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/services/commits/change_service.rb2
-rw-r--r--app/services/files/base_service.rb2
-rw-r--r--app/views/admin/application_settings/_form.html.haml6
-rw-r--r--app/views/shared/_clone_panel.html.haml23
-rw-r--r--db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb11
-rw-r--r--db/schema.rb1
-rw-r--r--doc/README.md1
-rw-r--r--doc/administration/access_restrictions.md38
-rw-r--r--doc/administration/img/access_restrictions.pngbin0 -> 317529 bytes
-rw-r--r--doc/administration/img/restricted_url.pngbin0 -> 188210 bytes
-rw-r--r--doc/api/settings.md1
-rw-r--r--lib/api/internal.rb7
-rw-r--r--lib/gitlab/git/hook.rb4
-rw-r--r--lib/gitlab/git_access.rb11
-rw-r--r--lib/gitlab/protocol_access.rb13
-rw-r--r--spec/features/admin/admin_disables_git_access_protocol_spec.rb66
-rw-r--r--spec/lib/gitlab/git_access_spec.rb39
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb2
-rw-r--r--spec/requests/api/internal_spec.rb71
29 files changed, 360 insertions, 37 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3da5583d452..8ef934bf80d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -23,6 +23,7 @@ v 8.10.0 (unreleased)
- Add notification settings dropdown for groups
- Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Todos !3188 (Robert Schilling)
+ - Add "Enabled Git access protocols" to Application Settings
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- PipelinesFinder uses git cache data
- Check for conflicts with existing Project's wiki path when creating a new project.
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 1e3083cce55..590b8f54363 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -281,3 +281,21 @@
color: $gl-icon-color;
}
}
+
+.clone-dropdown-btn a {
+ color: $dropdown-link-color;
+ &:hover {
+ text-decoration: none;
+ }
+}
+
+.btn-static {
+ background-color: $background-color !important;
+ border: 1px solid lightgrey;
+ cursor: default;
+ &:active {
+ -moz-box-shadow: inset 0 0 0 white;
+ -webkit-box-shadow: inset 0 0 0 white;
+ box-shadow: inset 0 0 0 white;
+ }
+}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 5f65dd3aff0..cbdf2859898 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -110,6 +110,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:send_user_confirmation_email,
:container_registry_token_expire_delay,
:repository_storage,
+ :enabled_git_access_protocol,
restricted_visibility_levels: [],
import_sources: [],
disabled_oauth_sign_in_sources: []
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index 62c3fa8de53..40a8b7940d9 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -19,6 +19,8 @@ class Projects::GitHttpController < Projects::ApplicationController
render_ok
elsif receive_pack? && receive_pack_allowed?
render_ok
+ elsif http_blocked?
+ render_not_allowed
else
render_not_found
end
@@ -154,6 +156,10 @@ class Projects::GitHttpController < Projects::ApplicationController
render plain: 'Not Found', status: :not_found
end
+ def render_not_allowed
+ render plain: download_access.message, status: :forbidden
+ end
+
def ci?
@ci.present?
end
@@ -162,12 +168,28 @@ class Projects::GitHttpController < Projects::ApplicationController
return false unless Gitlab.config.gitlab_shell.upload_pack
if user
- Gitlab::GitAccess.new(user, project).download_access_check.allowed?
+ download_access.allowed?
else
ci? || project.public?
end
end
+ def access
+ return @access if defined?(@access)
+
+ @access = Gitlab::GitAccess.new(user, project, 'http')
+ end
+
+ def download_access
+ return @download_access if defined?(@download_access)
+
+ @download_access = access.check('git-upload-pack')
+ end
+
+ def http_blocked?
+ !access.protocol_allowed?
+ end
+
def receive_pack_allowed?
return false unless Gitlab.config.gitlab_shell.receive_pack
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 6e580c62ccd..78c0b79d2bd 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -31,6 +31,28 @@ module ApplicationSettingsHelper
current_application_settings.akismet_enabled?
end
+ def allowed_protocols_present?
+ current_application_settings.enabled_git_access_protocol.present?
+ end
+
+ def enabled_protocol
+ case current_application_settings.enabled_git_access_protocol
+ when 'http'
+ gitlab_config.protocol
+ when 'ssh'
+ 'ssh'
+ end
+ end
+
+ def enabled_project_button(project, protocol)
+ case protocol
+ when 'ssh'
+ ssh_clone_button(project, 'bottom', append_link: false)
+ else
+ http_clone_button(project, 'bottom', append_link: false)
+ end
+ end
+
# Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect.
def restricted_level_checkboxes(help_block_id)
diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb
index c533659b600..601df5c18df 100644
--- a/app/helpers/branches_helper.rb
+++ b/app/helpers/branches_helper.rb
@@ -12,7 +12,7 @@ module BranchesHelper
def can_push_branch?(project, branch_name)
return false unless project.repository.branch_exists?(branch_name)
- ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(branch_name)
+ ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(branch_name)
end
def project_branches
diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 9051a493b9b..0f097f86816 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -40,33 +40,33 @@ module ButtonHelper
type: :button
end
- def http_clone_button(project)
+ def http_clone_button(project, placement = 'right', append_link: true)
klass = 'http-selector'
klass << ' has-tooltip' if current_user.try(:require_password?)
protocol = gitlab_config.protocol.upcase
- content_tag :a, protocol,
+ content_tag (append_link ? :a : :span), protocol,
class: klass,
- href: project.http_url_to_repo,
+ href: (project.http_url_to_repo if append_link),
data: {
html: true,
- placement: 'right',
+ placement: placement,
container: 'body',
title: "Set a password on your account<br>to pull or push via #{protocol}"
}
end
- def ssh_clone_button(project)
+ def ssh_clone_button(project, placement = 'right', append_link: true)
klass = 'ssh-selector'
klass << ' has-tooltip' if current_user.try(:require_ssh_key?)
- content_tag :a, 'SSH',
+ content_tag (append_link ? :a : :span), 'SSH',
class: klass,
- href: project.ssh_url_to_repo,
+ href: (project.ssh_url_to_repo if append_link),
data: {
html: true,
- placement: 'right',
+ placement: placement,
container: 'body',
title: 'Add an SSH key to your profile<br>to pull or push via SSH.'
}
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index f312a7ccca3..88787576dd3 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -206,10 +206,14 @@ module ProjectsHelper
end
def default_clone_protocol
- if !current_user || current_user.require_ssh_key?
- gitlab_config.protocol
+ if allowed_protocols_present?
+ enabled_protocol
else
- "ssh"
+ if !current_user || current_user.require_ssh_key?
+ gitlab_config.protocol
+ else
+ 'ssh'
+ end
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 5fa6eacd234..7bf618d60b9 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -59,6 +59,9 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
+ validates :enabled_git_access_protocol,
+ inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
+
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index cb0f871897a..4f7e1d2f302 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -481,7 +481,7 @@ class MergeRequest < ActiveRecord::Base
end
def can_be_merged_by?(user)
- ::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch)
+ ::Gitlab::GitAccess.new(user, project, 'web').can_push_to_branch?(target_branch)
end
def mergeable_ci_state?
diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb
index 6b69cb53b2c..c578097376a 100644
--- a/app/services/commits/change_service.rb
+++ b/app/services/commits/change_service.rb
@@ -23,7 +23,7 @@ module Commits
private
def check_push_permissions
- allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(@target_branch)
+ allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch)
unless allowed
raise ValidationError.new('You are not allowed to push into this branch')
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index 0326a8823e9..4bdb68a3698 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -43,7 +43,7 @@ module Files
end
def validate
- allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(@target_branch)
+ allowed = ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(@target_branch)
unless allowed
raise_error("You are not allowed to push into this branch")
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index c1f70bc1866..eb325576e4f 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -44,6 +44,12 @@
and GitLab.com
= link_to "(?)", help_page_path("integration", "gitlab")
.form-group
+ %label.control-label.col-sm-2 Enabled Git access protocols
+ .col-sm-10
+ = select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
+ %span.help-block#clone-protocol-help
+ Allow only the selected protocols to be used for Git access.
+ .form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :version_check_enabled do
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 84b3f44c0ad..3b82d8e686f 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -2,15 +2,20 @@
.git-clone-holder.input-group
.input-group-btn
- %a#clone-dropdown.clone-dropdown-btn.btn{href: '#', 'data-toggle' => 'dropdown'}
- %span
- = default_clone_protocol.upcase
- = icon('caret-down')
- %ul.dropdown-menu.dropdown-menu-right.clone-options-dropdown
- %li
- = ssh_clone_button(project)
- %li
- = http_clone_button(project)
+ -if allowed_protocols_present?
+ .clone-dropdown-btn.btn.btn-static
+ %span
+ = enabled_project_button(project, enabled_protocol)
+ - else
+ %a#clone-dropdown.clone-dropdown-btn.btn{href: '#', data: { toggle: 'dropdown' }}
+ %span
+ = default_clone_protocol.upcase
+ = icon('caret-down')
+ %ul.dropdown-menu.dropdown-menu-right.clone-options-dropdown
+ %li
+ = ssh_clone_button(project)
+ %li
+ = http_clone_button(project)
= text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true
.input-group-btn
diff --git a/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb b/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb
new file mode 100644
index 00000000000..013904b3f4f
--- /dev/null
+++ b/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb
@@ -0,0 +1,11 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+# rubocop:disable all
+
+class AddEnabledGitAccessProtocolsToApplicationSettings < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ def change
+ add_column :application_settings, :enabled_git_access_protocol, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c1e88c1ed7e..f6465136e6a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -86,6 +86,7 @@ ActiveRecord::Schema.define(version: 20160705163108) do
t.integer "container_registry_token_expire_delay", default: 5
t.text "after_sign_up_text"
t.string "repository_storage", default: "default"
+ t.string "enabled_git_access_protocol"
end
create_table "audit_events", force: :cascade do |t|
diff --git a/doc/README.md b/doc/README.md
index 53a12d2a455..cf7a828d91e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -21,6 +21,7 @@
## Administrator documentation
+- [Access restrictions](administration/access_restrictions.md) Define which Git access protocols can be used to talk to GitLab
- [Authentication/Authorization](administration/auth/README.md) Configure
external authentication with LDAP, SAML, CAS and additional Omniauth providers.
- [Custom Git hooks](administration/custom_hooks.md) Custom Git hooks (on the filesystem) for when webhooks aren't enough.
diff --git a/doc/administration/access_restrictions.md b/doc/administration/access_restrictions.md
new file mode 100644
index 00000000000..51d7996effd
--- /dev/null
+++ b/doc/administration/access_restrictions.md
@@ -0,0 +1,38 @@
+# Access Restrictions
+
+> **Note:** This feature is only available on versions 8.10 and above.
+
+With GitLab's Access restrictions you can choose which Git access protocols you
+want your users to use to communicate with GitLab. This feature can be enabled
+via the `Application Settings` in the Admin interface.
+
+The setting is called `Enabled Git access protocols`, and it gives you the option
+to choose between:
+
+- Both SSH and HTTP(S)
+- Only SSH
+- Only HTTP(s)
+
+![Settings Overview](img/access_restrictions.png)
+
+## Enabled Protocol
+
+When both SSH and HTTP(S) are enabled, GitLab will behave as usual, it will give
+your users the option to choose which protocol they would like to use.
+
+When you choose to allow only one of the protocols, a couple of things will happen:
+
+- The project page will only show the allowed protocol's URL, with no option to
+ change it.
+- A tooltip will be shown when you hover over the URL's protocol, if an action
+ on the user's part is required, e.g. adding an SSH key, or setting a password.
+
+![Project URL with SSH only access](img/restricted_url.png)
+
+On top of these UI restrictions, GitLab will deny all Git actions on the protocol
+not selected.
+
+> **Note:** Please keep in mind that disabling an access protocol does not actually
+ block access to the server itself. The ports used for the protocol, be it SSH or
+ HTTP, will still be accessible. What GitLab does is restrict access on the
+ application level. \ No newline at end of file
diff --git a/doc/administration/img/access_restrictions.png b/doc/administration/img/access_restrictions.png
new file mode 100644
index 00000000000..66fd9491e85
--- /dev/null
+++ b/doc/administration/img/access_restrictions.png
Binary files differ
diff --git a/doc/administration/img/restricted_url.png b/doc/administration/img/restricted_url.png
new file mode 100644
index 00000000000..0a677433dcf
--- /dev/null
+++ b/doc/administration/img/restricted_url.png
Binary files differ
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 741c5a29581..d9b68eaeadf 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -68,6 +68,7 @@ PUT /application/settings
| `after_sign_out_path` | string | no | Where to redirect users after logout |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes |
| `repository_storage` | string | no | Storage path for new projects. The value should be the name of one of the repository storage paths defined in your gitlab.yml |
+| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols.
```bash
curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/application/settings?signup_enabled=false&default_project_visibility=1
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index b32503e8516..d5dfba5e0cc 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -13,6 +13,7 @@ module API
# action - git action (git-upload-pack or git-receive-pack)
# ref - branch name
# forced_push - forced_push
+ # protocol - Git access protocol being used, e.g. HTTP or SSH
#
helpers do
@@ -46,11 +47,13 @@ module API
User.find_by(id: params[:user_id])
end
+ protocol = params[:protocol]
+
access =
if wiki?
- Gitlab::GitAccessWiki.new(actor, project)
+ Gitlab::GitAccessWiki.new(actor, project, protocol)
else
- Gitlab::GitAccess.new(actor, project)
+ Gitlab::GitAccess.new(actor, project, protocol)
end
access_status = access.check(params[:action], params[:changes])
diff --git a/lib/gitlab/git/hook.rb b/lib/gitlab/git/hook.rb
index 420c6883c45..57c41b41298 100644
--- a/lib/gitlab/git/hook.rb
+++ b/lib/gitlab/git/hook.rb
@@ -1,6 +1,7 @@
module Gitlab
module Git
class Hook
+ GL_PROTOCOL = 'web'.freeze
attr_reader :name, :repo_path, :path
def initialize(name, repo_path)
@@ -34,7 +35,8 @@ module Gitlab
vars = {
'GL_ID' => gl_id,
- 'PWD' => repo_path
+ 'PWD' => repo_path,
+ 'GL_PROTOCOL' => GL_PROTOCOL
}
options = {
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index d2a0e316cbe..7679c7e4bb8 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -3,11 +3,12 @@ module Gitlab
DOWNLOAD_COMMANDS = %w{ git-upload-pack git-upload-archive }
PUSH_COMMANDS = %w{ git-receive-pack }
- attr_reader :actor, :project
+ attr_reader :actor, :project, :protocol
- def initialize(actor, project)
+ def initialize(actor, project, protocol)
@actor = actor
@project = project
+ @protocol = protocol
end
def user
@@ -49,6 +50,8 @@ module Gitlab
end
def check(cmd, changes = nil)
+ return build_status_object(false, "Git access over #{protocol.upcase} is not allowed") unless protocol_allowed?
+
unless actor
return build_status_object(false, "No user or key was provided.")
end
@@ -164,6 +167,10 @@ module Gitlab
Gitlab::ForcePushCheck.force_push?(project, oldrev, newrev)
end
+ def protocol_allowed?
+ Gitlab::ProtocolAccess.allowed?(protocol)
+ end
+
private
def protected_branch_action(oldrev, newrev, branch_name)
diff --git a/lib/gitlab/protocol_access.rb b/lib/gitlab/protocol_access.rb
new file mode 100644
index 00000000000..21aefc884be
--- /dev/null
+++ b/lib/gitlab/protocol_access.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module ProtocolAccess
+ def self.allowed?(protocol)
+ if protocol == 'web'
+ true
+ elsif current_application_settings.enabled_git_access_protocol.blank?
+ true
+ else
+ protocol == current_application_settings.enabled_git_access_protocol
+ end
+ end
+ end
+end
diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
new file mode 100644
index 00000000000..5b1c0460274
--- /dev/null
+++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
@@ -0,0 +1,66 @@
+require 'rails_helper'
+
+feature 'Admin disables Git access protocol', feature: true do
+ let(:project) { create(:empty_project, :empty_repo) }
+ let(:admin) { create(:admin) }
+
+ background do
+ login_as(admin)
+ end
+
+ context 'with HTTP disabled' do
+ background do
+ disable_http_protocol
+ end
+
+ scenario 'shows only SSH url' do
+ visit_project
+
+ expect(page).to have_content("git clone #{project.ssh_url_to_repo}")
+ expect(page).not_to have_selector('#clone-dropdown')
+ end
+ end
+
+ context 'with SSH disabled' do
+ background do
+ disable_ssh_protocol
+ end
+
+ scenario 'shows only HTTP url' do
+ visit_project
+
+ expect(page).to have_content("git clone #{project.http_url_to_repo}")
+ expect(page).not_to have_selector('#clone-dropdown')
+ end
+ end
+
+ context 'with nothing disabled' do
+ background do
+ create(:personal_key, user: admin)
+ end
+
+ scenario 'shows default SSH url and protocol selection dropdown' do
+ visit_project
+
+ expect(page).to have_content("git clone #{project.ssh_url_to_repo}")
+ expect(page).to have_selector('#clone-dropdown')
+ end
+
+ end
+
+ def visit_project
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ def disable_http_protocol
+ visit admin_application_settings_path
+ find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[2]').select_option
+ click_on 'Save'
+ end
+
+ def disable_ssh_protocol
+ visit admin_application_settings_path
+ find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[3]').select_option
+ click_on 'Save'
+ end
+end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 9b7986fa12d..c79ba11f782 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GitAccess, lib: true do
- let(:access) { Gitlab::GitAccess.new(actor, project) }
+ let(:access) { Gitlab::GitAccess.new(actor, project, 'web') }
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:actor) { user }
@@ -67,6 +67,43 @@ describe Gitlab::GitAccess, lib: true do
end
end
+ describe '#check with single protocols allowed' do
+ def disable_protocol(protocol)
+ settings = ::ApplicationSetting.create_from_defaults
+ settings.update_attribute(:enabled_git_access_protocol, protocol)
+ end
+
+ context 'ssh disabled' do
+ before do
+ disable_protocol('ssh')
+ @acc = Gitlab::GitAccess.new(actor, project, 'ssh')
+ end
+
+ it 'blocks ssh git push' do
+ expect(@acc.check('git-receive-pack').allowed?).to be_falsey
+ end
+
+ it 'blocks ssh git pull' do
+ expect(@acc.check('git-upload-pack').allowed?).to be_falsey
+ end
+ end
+
+ context 'http disabled' do
+ before do
+ disable_protocol('http')
+ @acc = Gitlab::GitAccess.new(actor, project, 'http')
+ end
+
+ it 'blocks http push' do
+ expect(@acc.check('git-receive-pack').allowed?).to be_falsey
+ end
+
+ it 'blocks http git pull' do
+ expect(@acc.check('git-upload-pack').allowed?).to be_falsey
+ end
+ end
+ end
+
describe 'download_access_check' do
describe 'master permissions' do
before { project.team << [user, :master] }
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 77ecfce6f17..4244b807d41 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GitAccessWiki, lib: true do
- let(:access) { Gitlab::GitAccessWiki.new(user, project) }
+ let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web') }
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index fcea45f19ba..e567d36afa8 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -207,26 +207,86 @@ describe API::API, api: true do
expect(json_response["status"]).to be_falsey
end
end
+
+ context 'ssh access has been disabled' do
+ before do
+ settings = ::ApplicationSetting.create_from_defaults
+ settings.update_attribute(:enabled_git_access_protocol, 'http')
+ end
+
+ it 'rejects the SSH push' do
+ push(key, project)
+
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq 'Git access over SSH is not allowed'
+ end
+
+ it 'rejects the SSH pull' do
+ pull(key, project)
+
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq 'Git access over SSH is not allowed'
+ end
+ end
+
+ context 'http access has been disabled' do
+ before do
+ settings = ::ApplicationSetting.create_from_defaults
+ settings.update_attribute(:enabled_git_access_protocol, 'ssh')
+ end
+
+ it 'rejects the HTTP push' do
+ push(key, project, 'http')
+
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
+ end
+
+ it 'rejects the HTTP pull' do
+ pull(key, project, 'http')
+
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
+ end
+ end
+
+ context 'web actions are always allowed' do
+ it 'allows WEB push' do
+ settings = ::ApplicationSetting.create_from_defaults
+ settings.update_attribute(:enabled_git_access_protocol, 'ssh')
+ project.team << [user, :developer]
+ push(key, project, 'web')
+
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to be_truthy
+ end
+ end
end
- def pull(key, project)
+ def pull(key, project, protocol = 'ssh')
post(
api("/internal/allowed"),
key_id: key.id,
project: project.path_with_namespace,
action: 'git-upload-pack',
- secret_token: secret_token
+ secret_token: secret_token,
+ protocol: protocol
)
end
- def push(key, project)
+ def push(key, project, protocol = 'ssh')
post(
api("/internal/allowed"),
changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
key_id: key.id,
project: project.path_with_namespace,
action: 'git-receive-pack',
- secret_token: secret_token
+ secret_token: secret_token,
+ protocol: protocol
)
end
@@ -237,7 +297,8 @@ describe API::API, api: true do
key_id: key.id,
project: project.path_with_namespace,
action: 'git-upload-archive',
- secret_token: secret_token
+ secret_token: secret_token,
+ protocol: 'ssh'
)
end
end