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:
commit
cbb35ea882
8 changed files with 132 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -65,6 +65,7 @@ eslint-report.html
|
|||
/vendor/gitaly-ruby
|
||||
/builds*
|
||||
/.gitlab_workhorse_secret
|
||||
/.gitlab_pages_shared_secret
|
||||
/webpack-report/
|
||||
/knapsack/
|
||||
/rspec_flaky/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
27
lib/api/internal/pages.rb
Normal 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
|
|
@ -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
|
||||
|
|
29
spec/lib/gitlab/pages_spec.rb
Normal file
29
spec/lib/gitlab/pages_spec.rb
Normal 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
|
54
spec/requests/api/internal/pages_spec.rb
Normal file
54
spec/requests/api/internal/pages_spec.rb
Normal 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
|
Loading…
Reference in a new issue