summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Vosmaer <jacob@gitlab.com>2016-07-01 11:46:56 +0200
committerJacob Vosmaer <jacob@gitlab.com>2016-07-01 11:46:56 +0200
commit4bcad1cbddca92e27c19a1c6c0872a01ef318f69 (patch)
treeba21af2122f707aa39066ac51f220804c39e63f1
parent2efee5f6410f4e8e40e9b0339393de80f4affdde (diff)
downloadgitlab-ce-4bcad1cbddca92e27c19a1c6c0872a01ef318f69.tar.gz
Groundwork for Kerberos SPNEGO (EE feature)
-rw-r--r--app/controllers/projects/git_http_controller.rb39
-rw-r--r--app/helpers/kerberos_spnego_helper.rb9
-rw-r--r--spec/requests/git_http_spec.rb27
3 files changed, 59 insertions, 16 deletions
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index f907d63258b..62c3fa8de53 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -1,4 +1,9 @@
+# This file should be identical in GitLab Community Edition and Enterprise Edition
+
class Projects::GitHttpController < Projects::ApplicationController
+ include ActionController::HttpAuthentication::Basic
+ include KerberosSpnegoHelper
+
attr_reader :user
# Git clients will not know what authenticity token to send along
@@ -40,9 +45,12 @@ class Projects::GitHttpController < Projects::ApplicationController
private
def authenticate_user
- return if project && project.public? && upload_pack?
+ if project && project.public? && upload_pack?
+ return # Allow access
+ end
- authenticate_or_request_with_http_basic do |login, password|
+ if allow_basic_auth? && basic_auth_provided?
+ login, password = user_name_and_password(request)
auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
if auth_result.type == :ci && upload_pack?
@@ -53,8 +61,31 @@ class Projects::GitHttpController < Projects::ApplicationController
@user = auth_result.user
end
- ci? || user
+ if ci? || user
+ return # Allow access
+ end
+ elsif allow_kerberos_spnego_auth? && spnego_provided?
+ @user = find_kerberos_user
+
+ if user
+ send_final_spnego_response
+ return # Allow access
+ end
end
+
+ send_challenges
+ render plain: "HTTP Basic: Access denied\n", status: 401
+ end
+
+ def basic_auth_provided?
+ has_basic_credentials?(request)
+ end
+
+ def send_challenges
+ challenges = []
+ challenges << 'Basic realm="GitLab"' if allow_basic_auth?
+ challenges << spnego_challenge if allow_kerberos_spnego_auth?
+ headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
end
def ensure_project_found!
@@ -120,7 +151,7 @@ class Projects::GitHttpController < Projects::ApplicationController
end
def render_not_found
- render text: 'Not Found', status: :not_found
+ render plain: 'Not Found', status: :not_found
end
def ci?
diff --git a/app/helpers/kerberos_spnego_helper.rb b/app/helpers/kerberos_spnego_helper.rb
new file mode 100644
index 00000000000..f5b0aa7549a
--- /dev/null
+++ b/app/helpers/kerberos_spnego_helper.rb
@@ -0,0 +1,9 @@
+module KerberosSpnegoHelper
+ def allow_basic_auth?
+ true # different behavior in GitLab Enterprise Edition
+ end
+
+ def allow_kerberos_spnego_auth?
+ false # different behavior in GitLab Enterprise Edition
+ end
+end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index bae56334be4..82ab582beac 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -350,23 +350,23 @@ describe 'Git HTTP requests', lib: true do
end
def clone_get(project, options={})
- get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password))
+ get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def clone_post(project, options={})
- post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password))
+ post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def push_get(project, options={})
- get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password))
+ get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def push_post(project, options={})
- post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password))
+ post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
- def download(project, user: nil, password: nil)
- args = [project, { user: user, password: password }]
+ def download(project, user: nil, password: nil, spnego_request_token: nil)
+ args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }]
clone_get(*args)
yield response
@@ -375,8 +375,8 @@ describe 'Git HTTP requests', lib: true do
yield response
end
- def upload(project, user: nil, password: nil)
- args = [project, { user: user, password: password }]
+ def upload(project, user: nil, password: nil, spnego_request_token: nil)
+ args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }]
push_get(*args)
yield response
@@ -385,11 +385,14 @@ describe 'Git HTTP requests', lib: true do
yield response
end
- def auth_env(user, password)
+ def auth_env(user, password, spnego_request_token)
+ env = {}
if user && password
- { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password) }
- else
- {}
+ env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user, password)
+ elsif spnego_request_token
+ env['HTTP_AUTHORIZATION'] = "Negotiate #{::Base64.strict_encode64('opaque_request_token')}"
end
+
+ env
end
end