Commit b39935f7 authored by Gabriel Mazetto's avatar Gabriel Mazetto

Authenticate Geo requests using X-Gitlab-Token

parent e6757060
......@@ -18,7 +18,8 @@ class GeoNode < ActiveRecord::Base
host: lambda { Gitlab.config.gitlab.host },
port: 80,
relative_url_root: '',
primary: false
primary: false,
token: lambda { SecureRandom.hex(20) }
accepts_nested_attributes_for :geo_node_key
......
class AddTokenToGeoNode < ActiveRecord::Migration
def change
add_column :geo_nodes, :token, :string
# Add token to existing nodes
GeoNode.where(token: nil).each do |node|
node.token = SecureRandom.hex(20)
node.save!
end
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160413115152) do
ActiveRecord::Schema.define(version: 20160414032323) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -420,6 +420,7 @@ ActiveRecord::Schema.define(version: 20160413115152) do
t.boolean "primary"
t.integer "geo_node_key_id"
t.integer "oauth_application_id"
t.string "token"
end
add_index "geo_nodes", ["geo_node_key_id"], name: "index_geo_nodes_on_geo_node_key_id", using: :btree
......
module API
class Geo < Grape::API
before { authenticated_as_admin! }
resource :geo do
# Enqueue a batch of IDs of modified projects to have their
# repositories updated
......@@ -9,6 +7,7 @@ module API
# Example request:
# POST /geo/refresh_projects
post 'refresh_projects' do
authenticated_as_admin!
required_attributes! [:projects]
::Geo::ScheduleRepoUpdateService.new(params[:projects]).execute
end
......@@ -19,6 +18,7 @@ module API
# Example request:
# POST /geo/refresh_wikis
post 'refresh_wikis' do
authenticated_as_admin!
required_attributes! [:projects]
::Geo::ScheduleWikiRepoUpdateService.new(params[:projects]).execute
end
......@@ -28,6 +28,7 @@ module API
# Example request:
# POST /geo/receive_events
post 'receive_events' do
authenticate_by_gitlab_geo_token!
required_attributes! %w(event_name)
case params['event_name']
......
......@@ -113,6 +113,13 @@ module API
end
end
def authenticate_by_gitlab_geo_token!
token = headers['X-Gitlab-Token'].try(:chomp)
unless token && Devise.secure_compare(geo_token, token)
unauthorized!
end
end
def authenticated_as_admin!
forbidden! unless current_user.is_admin?
end
......@@ -374,6 +381,10 @@ module API
File.read(Gitlab.config.gitlab_shell.secret_file).chomp
end
def geo_token
Gitlab::Geo.current_node.token
end
def handle_member_errors(errors)
error!(errors[:access_level], 422) if errors[:access_level].any?
not_found!(errors)
......
......@@ -4,6 +4,7 @@ describe API::API, api: true do
include ApiHelpers
let(:admin) { create(:admin) }
let(:user) { create(:user) }
let(:geo_node) { build(:geo_node) }
describe 'POST /geo/refresh_projects' do
before(:each) { allow_any_instance_of(::Geo::ScheduleRepoUpdateService).to receive(:execute) }
......@@ -20,7 +21,15 @@ describe API::API, api: true do
end
describe 'POST /geo/receive_events' do
before(:each) { allow_any_instance_of(::Geo::ScheduleKeyChangeService).to receive(:execute) }
before(:each) do
allow_any_instance_of(::Geo::ScheduleKeyChangeService).to receive(:execute)
allow(Gitlab::Geo).to receive(:current_node) { geo_node }
end
let(:geo_token_header) do
{ 'X-Gitlab-Token' => geo_node.token }
end
let(:key_create_payload) do
{
'event_name' => 'key_create',
......@@ -44,18 +53,23 @@ describe API::API, api: true do
end
it 'enqueues on disk key creation if admin and correct params' do
post api('/geo/receive_events', admin), key_create_payload
post api('/geo/receive_events'), key_create_payload, geo_token_header
expect(response.status).to eq 201
end
it 'enqueues on disk key removal if admin and correct params' do
post api('/geo/receive_events', admin), key_destroy_payload
post api('/geo/receive_events'), key_destroy_payload, geo_token_header
expect(response.status).to eq 201
end
it 'denies access if not admin' do
post api('/geo/receive_events', user)
expect(response.status).to eq 403
it 'denies access if token is not present' do
post api('/geo/receive_events')
expect(response.status).to eq 401
end
it 'denies access if token is invalid' do
post api('/geo/receive_events'), nil, { 'X-Gitlab-Token' => 'nothing' }
expect(response.status).to eq 401
end
end
end
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