Merge branch '61927-skeleton-pages-internal-api' into 'master'

Add skeleton Pages internal API

See merge request gitlab-org/gitlab-ce!32732
This commit is contained in:
Kamil Trzciński 2019-09-09 13:27:11 +00:00
commit cbb35ea882
8 changed files with 132 additions and 1 deletions

1
.gitignore vendored
View File

@ -65,6 +65,7 @@ eslint-report.html
/vendor/gitaly-ruby
/builds*
/.gitlab_workhorse_secret
/.gitlab_pages_shared_secret
/webpack-report/
/knapsack/
/rspec_flaky/

View File

@ -321,6 +321,9 @@ production: &base
# external_https: ["1.1.1.1:443", "[2001::1]:443"] # If defined, enables custom domain and certificate support in GitLab Pages
admin:
address: unix:/home/git/gitlab/tmp/sockets/private/pages-admin.socket # TCP connections are supported too (e.g. tcp://host:port)
# File that contains the shared secret key for verifying access for gitlab-pages.
# Default is '.gitlab_pages_shared_secret' relative to Rails.root (i.e. root of the GitLab app).
# secret_file: /home/git/gitlab/.gitlab_pages_shared_secret
## Mattermost
## For enabling Add to Mattermost button

View File

@ -292,6 +292,7 @@ Settings.pages['artifacts_server'] ||= Settings.pages['enabled'] if Settings.pa
Settings.pages['admin'] ||= Settingslogic.new({})
Settings.pages.admin['certificate'] ||= ''
Settings.pages['secret_file'] ||= Rails.root.join('.gitlab_pages_shared_secret')
#
# Geo

View File

@ -119,6 +119,7 @@ module API
mount ::API::GroupVariables
mount ::API::ImportGithub
mount ::API::Internal::Base
mount ::API::Internal::Pages
mount ::API::Issues
mount ::API::JobArtifacts
mount ::API::Jobs

27
lib/api/internal/pages.rb Normal file
View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module API
# Pages Internal API
module Internal
class Pages < Grape::API
before do
not_found! unless Feature.enabled?(:pages_internal_api)
authenticate_gitlab_pages_request!
end
helpers do
def authenticate_gitlab_pages_request!
unauthorized! unless Gitlab::Pages.verify_api_request(headers)
end
end
namespace 'internal' do
namespace 'pages' do
get "/" do
status :ok
end
end
end
end
end
end

View File

@ -1,7 +1,22 @@
# frozen_string_literal: true
module Gitlab
module Pages
class Pages
VERSION = File.read(Rails.root.join("GITLAB_PAGES_VERSION")).strip.freeze
INTERNAL_API_REQUEST_HEADER = 'Gitlab-Pages-Api-Request'.freeze
include JwtAuthenticatable
class << self
def verify_api_request(request_headers)
decode_jwt_for_issuer('gitlab-pages', request_headers[INTERNAL_API_REQUEST_HEADER])
rescue JWT::DecodeError
false
end
def secret_path
Gitlab.config.pages.secret_file
end
end
end
end

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Pages do
let(:pages_shared_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
before do
allow(described_class).to receive(:secret).and_return(pages_shared_secret)
end
describe '.verify_api_request' do
let(:payload) { { 'iss' => 'gitlab-pages' } }
it 'returns false if fails to validate the JWT' do
encoded_token = JWT.encode(payload, 'wrongsecret', 'HS256')
headers = { described_class::INTERNAL_API_REQUEST_HEADER => encoded_token }
expect(described_class.verify_api_request(headers)).to eq(false)
end
it 'returns the decoded JWT' do
encoded_token = JWT.encode(payload, described_class.secret, 'HS256')
headers = { described_class::INTERNAL_API_REQUEST_HEADER => encoded_token }
expect(described_class.verify_api_request(headers)).to eq([{ "iss" => "gitlab-pages" }, { "alg" => "HS256" }])
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
require 'spec_helper'
describe API::Internal::Pages do
describe "GET /internal/pages" do
let(:pages_shared_secret) { SecureRandom.random_bytes(Gitlab::Pages::SECRET_LENGTH) }
before do
allow(Gitlab::Pages).to receive(:secret).and_return(pages_shared_secret)
end
def query_host(host, headers = {})
get api("/internal/pages"), headers: headers, params: { host: host }
end
context 'feature flag disabled' do
before do
stub_feature_flags(pages_internal_api: false)
end
it 'responds with 404 Not Found' do
query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(404)
end
end
context 'feature flag enabled' do
context 'not authenticated' do
it 'responds with 401 Unauthorized' do
query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(401)
end
end
context 'authenticated' do
def query_host(host)
jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
super(host, headers)
end
it 'responds with 200 OK' do
query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(200)
end
end
end
end
end