Authenticate Geo node status endpoint by Geo node token

parent 6c308a02
...@@ -2,18 +2,15 @@ module Geo ...@@ -2,18 +2,15 @@ module Geo
class NodeStatusService class NodeStatusService
include HTTParty include HTTParty
KEYS = %w(health repositories repositories_synced repositories_failed).freeze
# HTTParty timeout # HTTParty timeout
default_timeout Gitlab.config.gitlab.geo_status_timeout default_timeout Gitlab.config.gitlab.geo_status_timeout
def call(status_url) def call(status_url)
keys = %w(health repositories repositories_synced repositories_failed)
values = values =
begin begin
response = self.class.get(status_url, response = self.class.get(status_url, headers: headers)
headers: {
'Content-Type' => 'application/json',
'PRIVATE-TOKEN' => private_token
})
if response.success? || response.redirection? if response.success? || response.redirection?
response.parsed_response.values_at(*keys) response.parsed_response.values_at(*keys)
...@@ -24,14 +21,13 @@ module Geo ...@@ -24,14 +21,13 @@ module Geo
[e.message] [e.message]
end end
GeoNodeStatus.new(keys.zip(values).to_h) GeoNodeStatus.new(KEYS.zip(values).to_h)
end end
private private
def private_token def headers
# TODO: should we ask admin user to be defined as part of configuration? Gitlab::Geo::BaseRequest.new.headers
@private_token ||= User.find_by(admin: true).authentication_token
end end
end end
end end
...@@ -33,7 +33,7 @@ module API ...@@ -33,7 +33,7 @@ module API
# Example request: # Example request:
# GET /geo/status # GET /geo/status
get 'status' do get 'status' do
authenticated_as_admin! authenticate_by_gitlab_geo_node_token!
require_node_to_be_secondary! require_node_to_be_secondary!
present GeoNodeStatus.new, with: Entities::GeoNodeStatus present GeoNodeStatus.new, with: Entities::GeoNodeStatus
...@@ -90,12 +90,20 @@ module API ...@@ -90,12 +90,20 @@ module API
end end
helpers do helpers do
def authenticate_by_gitlab_geo_node_token!
auth_header = headers['Authorization']
unless auth_header && Gitlab::Geo::JwtRequestDecoder.new(auth_header).decode
unauthorized!
end
end
def require_node_to_be_enabled! def require_node_to_be_enabled!
forbidden! 'Geo node is disabled.' unless Gitlab::Geo.current_node.enabled? forbidden! 'Geo node is disabled.' unless Gitlab::Geo.current_node&.enabled?
end end
def require_node_to_be_secondary! def require_node_to_be_secondary!
forbidden! 'Geo node is disabled.' unless Gitlab::Geo.current_node.secondary? forbidden! 'Geo node is not secondary node.' unless Gitlab::Geo.current_node&.secondary?
end end
end end
end end
......
...@@ -2,11 +2,12 @@ require 'spec_helper' ...@@ -2,11 +2,12 @@ require 'spec_helper'
describe API::Geo, api: true do describe API::Geo, api: true do
include ApiHelpers include ApiHelpers
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:user) { create(:user) } let(:user) { create(:user) }
let!(:geo_node) { create(:geo_node, :primary) } let!(:primary_node) { create(:geo_node, :primary) }
let(:geo_token_header) do let(:geo_token_header) do
{ 'X-Gitlab-Token' => geo_node.system_hook.token } { 'X-Gitlab-Token' => primary_node.system_hook.token }
end end
before(:each) do before(:each) do
...@@ -27,7 +28,7 @@ describe API::Geo, api: true do ...@@ -27,7 +28,7 @@ describe API::Geo, api: true do
describe 'POST /geo/refresh_wikis disabled node' do describe 'POST /geo/refresh_wikis disabled node' do
it 'responds with forbidden' do it 'responds with forbidden' do
geo_node.enabled = false primary_node.enabled = false
post api('/geo/refresh_wikis', admin), nil post api('/geo/refresh_wikis', admin), nil
...@@ -37,7 +38,7 @@ describe API::Geo, api: true do ...@@ -37,7 +38,7 @@ describe API::Geo, api: true do
describe 'POST /geo/receive_events disabled node' do describe 'POST /geo/receive_events disabled node' do
it 'responds with forbidden' do it 'responds with forbidden' do
geo_node.enabled = false primary_node.enabled = false
post api('/geo/receive_events'), nil, geo_token_header post api('/geo/receive_events'), nil, geo_token_header
...@@ -125,7 +126,7 @@ describe API::Geo, api: true do ...@@ -125,7 +126,7 @@ describe API::Geo, api: true do
let(:lfs_object) { create(:lfs_object, :with_file) } let(:lfs_object) { create(:lfs_object, :with_file) }
let(:req_header) do let(:req_header) do
transfer = Gitlab::Geo::LfsTransfer.new(lfs_object) transfer = Gitlab::Geo::LfsTransfer.new(lfs_object)
Gitlab::Geo::TransferRequest.new(transfer.request_data).header Gitlab::Geo::TransferRequest.new(transfer.request_data).headers
end end
before do before do
...@@ -156,4 +157,42 @@ describe API::Geo, api: true do ...@@ -156,4 +157,42 @@ describe API::Geo, api: true do
end end
end end
end end
describe 'GET /geo/status' do
let!(:secondary_node) { create(:geo_node) }
let(:request) { Gitlab::Geo::BaseRequest.new }
it 'responds with 401 with invalid auth header' do
get api('/geo/status'), nil, Authorization: 'Test'
expect(response.status).to eq 401
end
context 'when requesting secondary node with valid auth header' do
before(:each) do
allow(Gitlab::Geo).to receive(:current_node) { secondary_node }
allow(request).to receive(:requesting_node) { primary_node }
end
it 'responds with 200' do
get api('/geo/status'), nil, request.headers
expect(response.status).to eq 200
expect(response.headers['Content-Type']).to eq('application/json')
end
end
context 'when requesting primary node with valid auth header' do
before(:each) do
allow(Gitlab::Geo).to receive(:current_node) { primary_node }
allow(request).to receive(:requesting_node) { secondary_node }
end
it 'responds with 403' do
get api('/geo/status'), nil, request.headers
expect(response).to have_http_status(403)
end
end
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