diff --git a/CHANGELOG b/CHANGELOG
index 3da5583d452eb4eec6be3937422f494a4e087ed7..8ef934bf80d303343c51265a42d1d04804753cc1 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 1e3083cce55a5a0a9019767f96785fa66a656ff0..590b8f54363bf06a0d738d1a38d47f80be57c95e 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 5f65dd3aff08942c433529328f8ec9e413decbb7..cbdf285989819b6a7959eaa6d131046c169ef20e 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 62c3fa8de531a75f4ac77067b99cd299c61b2d72..40a8b7940d9eb1a1e7d1b1c80cb1b26a50918886 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 6e580c62ccd74aea671b5a13699c379eb74b8013..78c0b79d2bd82ca2def8a020f14768bc0c27cb46 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 c533659b600f8d0a37b30e6374efee32cc14f6cc..601df5c18df14c353313da58554c7f6236d9582b 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 9051a493b9b119c490369baae73364fda66cd455..0f097f86816555156cea7ca9db87042035fc537c 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 f312a7ccca3618f59f60e139e72af2d5d2eca10f..88787576dd3f2ae059cde9c2b6a501dcf4934b22 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 5fa6eacd23453868df893fb54c5a7572b6c3a879..7bf618d60b9a1b329d38d8f6da015b5646b0a92b 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 cb0f871897a346b5dd7a954b3a3ac6ad1d65e0f3..4f7e1d2f302fc31029b2883b0cbdfa971c8aac33 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 6b69cb53b2c6bad66dc972023c3e12f476b4dd18..c578097376a632d349d73257be0072d40b0dc8bc 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 0326a8823e975c20a7a02825ba1b1da94f27868f..4bdb68a3698ffe4b7fe46dbd1aeb41e80ad12658 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 c1f70bc1866a65c38b0362fab15bea0536f52a2a..eb325576e4f99d340e900282ed7eb2d93edb0482 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -43,6 +43,12 @@
           = link_to "(?)", help_page_path("integration", "bitbucket")
           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
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 84b3f44c0adfddee1f4590d049b185ae8f6d9ca6..3b82d8e686f37d7075be2a475368ec1b652e7c4a 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 0000000000000000000000000000000000000000..013904b3f4f3832ff19eadac179298b3f51adca9
--- /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 c1e88c1ed7ed2c1cc35f6e2fd980b651f5ad6112..f6465136e6a51c4de2f6f5b3a5782ae44595a249 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 53a12d2a455884d7aa7aec6af0e63fc61cabc528..cf7a828d91e0b30f9edb90e0845cfff14560572a 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 0000000000000000000000000000000000000000..51d7996effd06e67322e9347c9292f12e5de530f
--- /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 0000000000000000000000000000000000000000..66fd9491e854f7cb4a8ac51f931e9b96575d4e14
Binary files /dev/null and b/doc/administration/img/access_restrictions.png differ
diff --git a/doc/administration/img/restricted_url.png b/doc/administration/img/restricted_url.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a677433dcf097c5b026415a09b8951dd7bcc431
Binary files /dev/null and b/doc/administration/img/restricted_url.png differ
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 741c5a295818e5f22fb85ae2c244ffbb0ac2703d..d9b68eaeadfd165b571594a5838d57f52f0a7c9b 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 b32503e8516b7608eae864a99e46be97d89818db..d5dfba5e0cc989246613daa82ea5b3618f801f96 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 420c6883c45a0913da78ebdb87738cdb1812319f..57c41b4129835d9735bfa6eb22cd85ea8c357125 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 d2a0e316cbe65ee9ae7ab0ce36b4e24d6e940a92..7679c7e4bb8e4192918417c4859214213150406b 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 0000000000000000000000000000000000000000..21aefc884be91b22c6192554fb99392f0375dfdb
--- /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 0000000000000000000000000000000000000000..5b1c0460274087b2b7f3fab5ba8849d356c4e39e
--- /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 9b7986fa12d6dd6d73212bcd786f9d957e953648..c79ba11f782dbe0e946e483a41db568908f47be3 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 77ecfce6f17f01eee7f8fcc938408efaa5ae11fe..4244b807d416a074c11383bcc361502632e7f6ec 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 fcea45f19bad486070cd0f8ea58e64d5075859e4..e567d36afa8bf4472bc2efdcc55732d180235cb8 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