Commit e15bb700 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '80-geo-enforce-repository-jwt-scopes' into 'master'

Geo: Enforce repository JWT scopes

Closes #10540

See merge request gitlab-org/gitlab-ee!10303
parents 36664bd6 08eeba0d
...@@ -271,7 +271,6 @@ questions from [owasp.org](https://www.owasp.org). ...@@ -271,7 +271,6 @@ questions from [owasp.org](https://www.owasp.org).
- LFS and File ID. - LFS and File ID.
- Upload and File ID. - Upload and File ID.
- Job Artifact and File ID. - Job Artifact and File ID.
- Geo JWTs scopes are not enforced for Git Access yet, but will be in a future version (currently scheduled for GitLab 11.10).
### What access requirements have been defined for URI and Service calls? ### What access requirements have been defined for URI and Service calls?
......
...@@ -48,6 +48,7 @@ module EE ...@@ -48,6 +48,7 @@ module EE
def authenticate_user def authenticate_user
return super unless geo_request? return super unless geo_request?
return render_bad_geo_auth('Bad token') unless decoded_authorization return render_bad_geo_auth('Bad token') unless decoded_authorization
return render_bad_geo_auth('Unauthorized scope') unless jwt_scope_valid?
# grant access # grant access
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code, :push_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables @authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code, :push_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
...@@ -57,6 +58,14 @@ module EE ...@@ -57,6 +58,14 @@ module EE
render_bad_geo_auth("Invalid signature time ") render_bad_geo_auth("Invalid signature time ")
end end
def jwt_scope_valid?
decoded_authorization[:scope] == repository.full_path
end
def repository
wiki? ? project.wiki.repository : project.repository
end
def decoded_authorization def decoded_authorization
strong_memoize(:decoded_authorization) do strong_memoize(:decoded_authorization) do
::Gitlab::Geo::JwtRequestDecoder.new(request.headers['Authorization']).decode ::Gitlab::Geo::JwtRequestDecoder.new(request.headers['Authorization']).decode
......
...@@ -101,7 +101,7 @@ module Geo ...@@ -101,7 +101,7 @@ module Geo
# Build a JWT header for authentication # Build a JWT header for authentication
def jwt_authentication_header def jwt_authentication_header
authorization = ::Gitlab::Geo::RepoSyncRequest.new( authorization = ::Gitlab::Geo::RepoSyncRequest.new(
scope: project.repository.full_path scope: repository.full_path
).authorization ).authorization
{ "http.#{remote_url}.extraHeader" => "Authorization: #{authorization}" } { "http.#{remote_url}.extraHeader" => "Authorization: #{authorization}" }
......
---
title: Enforce Geo JWT tokens scope for repository sync
merge_request: 10303
author:
type: changed
...@@ -12,7 +12,7 @@ describe "Git HTTP requests (Geo)" do ...@@ -12,7 +12,7 @@ describe "Git HTTP requests (Geo)" do
set(:secondary) { create(:geo_node) } set(:secondary) { create(:geo_node) }
# Ensure the token always comes from the real time of the request # Ensure the token always comes from the real time of the request
let!(:auth_token) { Gitlab::Geo::BaseRequest.new(scope: "repository-#{project.id}").authorization } let!(:auth_token) { Gitlab::Geo::BaseRequest.new(scope: project.full_path).authorization }
let!(:user) { create(:user) } let!(:user) { create(:user) }
let!(:user_without_any_access) { create(:user) } let!(:user_without_any_access) { create(:user) }
let!(:user_without_push_access) { create(:user) } let!(:user_without_push_access) { create(:user) }
...@@ -21,6 +21,7 @@ describe "Git HTTP requests (Geo)" do ...@@ -21,6 +21,7 @@ describe "Git HTTP requests (Geo)" do
let!(:key_for_user_without_push_access) { create(:key, user: user_without_push_access) } let!(:key_for_user_without_push_access) { create(:key, user: user_without_push_access) }
let(:env) { valid_geo_env } let(:env) { valid_geo_env }
let(:auth_token_with_invalid_scope) { Gitlab::Geo::BaseRequest.new(scope: "invalid").authorization }
before do before do
project.add_maintainer(user) project.add_maintainer(user)
...@@ -346,6 +347,53 @@ describe "Git HTTP requests (Geo)" do ...@@ -346,6 +347,53 @@ describe "Git HTTP requests (Geo)" do
end end
end end
end end
context 'invalid scope' do
subject do
make_request
response
end
def make_request
get "/#{repository_path}.git/info/refs", params: { service: 'git-upload-pack' }, headers: env
end
shared_examples_for 'unauthorized because of invalid scope' do
it { is_expected.to have_gitlab_http_status(:unauthorized) }
it 'returns correct error' do
expect(subject.parsed_body).to eq('Geo JWT authentication failed: Unauthorized scope')
end
end
context 'invalid scope of Geo JWT token' do
let(:repository_path) { project.full_path }
let(:env) { geo_env(auth_token_with_invalid_scope) }
include_examples 'unauthorized because of invalid scope'
end
context 'Geo JWT token scopes for wiki and repository are not interchangeable' do
context 'for a repository but using a wiki scope' do
let(:repository_path) { project.full_path }
let(:scope) { project.wiki.full_path }
let(:auth_token_with_valid_wiki_scope) { Gitlab::Geo::BaseRequest.new(scope: scope).authorization }
let(:env) { geo_env(auth_token_with_valid_wiki_scope) }
include_examples 'unauthorized because of invalid scope'
end
context 'for a wiki but using a repository scope' do
let(:project) { create(:project, :wiki_repo) }
let(:repository_path) { project.wiki.full_path }
let(:scope) { project.full_path }
let(:auth_token_with_valid_repository_scope) { Gitlab::Geo::BaseRequest.new(scope: scope).authorization }
let(:env) { geo_env(auth_token_with_valid_repository_scope) }
include_examples 'unauthorized because of invalid scope'
end
end
end
end end
def valid_geo_env def valid_geo_env
......
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