From 1162d89ac49553c579ec4d049e74206893ff6302 Mon Sep 17 00:00:00 2001 From: Travis Miller Date: Mon, 13 Nov 2017 16:05:44 +0000 Subject: [PATCH] Add administrative endpoint to list all pages domains --- app/models/pages_domain.rb | 4 ++ .../39436-pages-api-administrative.yml | 5 ++ doc/api/pages_domains.md | 25 ++++++++++ lib/api/entities.rb | 20 +++++++- lib/api/helpers.rb | 9 ++++ lib/api/pages_domains.rb | 22 ++++++++- .../public_api/v4/pages_domain/basic.json | 18 +++++++ .../public_api/v4/pages_domain/detail.json | 20 ++++++++ .../public_api/v4/pages_domain_basics.json | 4 ++ .../schemas/public_api/v4/pages_domains.json | 21 +-------- spec/requests/api/pages_domains_spec.rb | 47 +++++++++++++++++++ 11 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 changelogs/unreleased/39436-pages-api-administrative.yml create mode 100644 spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/pages_domain/detail.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/pages_domain_basics.json diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb index 2e824cda525..43c77f3f2a2 100644 --- a/app/models/pages_domain.rb +++ b/app/models/pages_domain.rb @@ -69,6 +69,10 @@ class PagesDomain < ActiveRecord::Base current < x509.not_before || x509.not_after < current end + def expiration + x509&.not_after + end + def subject return unless x509 x509.subject.to_s diff --git a/changelogs/unreleased/39436-pages-api-administrative.yml b/changelogs/unreleased/39436-pages-api-administrative.yml new file mode 100644 index 00000000000..f38bbbd479c --- /dev/null +++ b/changelogs/unreleased/39436-pages-api-administrative.yml @@ -0,0 +1,5 @@ +--- +title: Add administrative endpoint to list all pages domains +merge_request: 15160 +author: Travis Miller +type: added diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md index 51962595e33..50685f335f7 100644 --- a/doc/api/pages_domains.md +++ b/doc/api/pages_domains.md @@ -4,6 +4,31 @@ Endpoints for connecting custom domain(s) and TLS certificates in [GitLab Pages] The GitLab Pages feature must be enabled to use these endpoints. Find out more about [administering](../administration/pages/index.md) and [using](../user/project/pages/index.md) the feature. +## List all pages domains + +Get a list of all pages domains. The user must have admin permissions. + +```http +GET /pages/domains +``` + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/pages/domains +``` + +```json +[ + { + "domain": "ssl.domain.example", + "url": "https://ssl.domain.example", + "certificate": { + "expired": false, + "expiration": "2020-04-12T14:32:00.000Z" + } + } +] +``` + ## List pages domains Get a list of project pages domains. The user must have permissions to view pages domains. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index a382db92e8d..16ae99b5c6c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1042,6 +1042,11 @@ module API expose :value end + class PagesDomainCertificateExpiration < Grape::Entity + expose :expired?, as: :expired + expose :expiration + end + class PagesDomainCertificate < Grape::Entity expose :subject expose :expired?, as: :expired @@ -1049,12 +1054,23 @@ module API expose :certificate_text end + class PagesDomainBasic < Grape::Entity + expose :domain + expose :url + expose :certificate, + as: :certificate_expiration, + if: ->(pages_domain, _) { pages_domain.certificate? }, + using: PagesDomainCertificateExpiration do |pages_domain| + pages_domain + end + end + class PagesDomain < Grape::Entity expose :domain expose :url expose :certificate, - if: ->(pages_domain, _) { pages_domain.certificate? }, - using: PagesDomainCertificate do |pages_domain| + if: ->(pages_domain, _) { pages_domain.certificate? }, + using: PagesDomainCertificate do |pages_domain| pages_domain end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 5f9b94cc89c..3c8960cb1ab 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -155,6 +155,11 @@ module API end end + def authenticated_with_full_private_access! + authenticate! + forbidden! unless current_user.full_private_access? + end + def authenticated_as_admin! authenticate! forbidden! unless current_user.admin? @@ -190,6 +195,10 @@ module API not_found! unless user_project.pages_available? end + def require_pages_config_enabled! + not_found! unless Gitlab.config.pages.enabled + end + def can?(object, action, subject = :global) Ability.allowed?(object, action, subject) end diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb index 259f3f34068..d7b613a717e 100644 --- a/lib/api/pages_domains.rb +++ b/lib/api/pages_domains.rb @@ -4,7 +4,6 @@ module API before do authenticate! - require_pages_enabled! end after_validation do @@ -29,10 +28,31 @@ module API end end + resource :pages do + before do + require_pages_config_enabled! + authenticated_with_full_private_access! + end + + desc "Get all pages domains" do + success Entities::PagesDomainBasic + end + params do + use :pagination + end + get "domains" do + present paginate(PagesDomain.all), with: Entities::PagesDomainBasic + end + end + params do requires :id, type: String, desc: 'The ID of a project' end resource :projects, requirements: { id: %r{[^/]+} } do + before do + require_pages_enabled! + end + desc 'Get all pages domains' do success Entities::PagesDomain end diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json new file mode 100644 index 00000000000..4ba6422406c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "domain": { "type": "string" }, + "url": { "type": "uri" }, + "certificate_expiration": { + "type": "object", + "properties": { + "expired": { "type": "boolean" }, + "expiration": { "type": "string" } + }, + "required": ["expired", "expiration"], + "additionalProperties": false + } + }, + "required": ["domain", "url"], + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domain/detail.json b/spec/fixtures/api/schemas/public_api/v4/pages_domain/detail.json new file mode 100644 index 00000000000..08db8d47050 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pages_domain/detail.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "properties": { + "domain": { "type": "string" }, + "url": { "type": "uri" }, + "certificate": { + "type": "object", + "properties": { + "subject": { "type": "string" }, + "expired": { "type": "boolean" }, + "certificate": { "type": "string" }, + "certificate_text": { "type": "string" } + }, + "required": ["subject", "expired"], + "additionalProperties": false + } + }, + "required": ["domain", "url"], + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domain_basics.json b/spec/fixtures/api/schemas/public_api/v4/pages_domain_basics.json new file mode 100644 index 00000000000..c7d86de7d8e --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/pages_domain_basics.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "pages_domain/basic.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domains.json b/spec/fixtures/api/schemas/public_api/v4/pages_domains.json index 0de1d0f1228..7c27218dc5a 100644 --- a/spec/fixtures/api/schemas/public_api/v4/pages_domains.json +++ b/spec/fixtures/api/schemas/public_api/v4/pages_domains.json @@ -1,23 +1,4 @@ { "type": "array", - "items": { - "type": "object", - "properties": { - "domain": { "type": "string" }, - "url": { "type": "uri" }, - "certificate": { - "type": "object", - "properties": { - "subject": { "type": "string" }, - "expired": { "type": "boolean" }, - "certificate": { "type": "string" }, - "certificate_text": { "type": "string" } - }, - "required": ["subject", "expired"], - "additionalProperties": false - } - }, - "required": ["domain", "url"], - "additionalProperties": false - } + "items": { "$ref": "pages_domain/detail.json" } } diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb index d13b3a958c9..d412b045e9f 100644 --- a/spec/requests/api/pages_domains_spec.rb +++ b/spec/requests/api/pages_domains_spec.rb @@ -3,6 +3,7 @@ require 'rails_helper' describe API::PagesDomains do set(:project) { create(:project) } set(:user) { create(:user) } + set(:admin) { create(:admin) } set(:pages_domain) { create(:pages_domain, domain: 'www.domain.test', project: project) } set(:pages_domain_secure) { create(:pages_domain, :with_certificate, :with_key, domain: 'ssl.domain.test', project: project) } @@ -23,12 +24,49 @@ describe API::PagesDomains do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) end + describe 'GET /pages/domains' do + context 'when pages is disabled' do + before do + allow(Gitlab.config.pages).to receive(:enabled).and_return(false) + end + + it_behaves_like '404 response' do + let(:request) { get api('/pages/domains', admin) } + end + end + + context 'when pages is enabled' do + context 'when authenticated as an admin' do + it 'returns paginated all pages domains' do + get api('/pages/domains', admin) + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain_basics') + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.size).to eq(3) + expect(json_response.last).to have_key('domain') + expect(json_response.last).to have_key('certificate_expiration') + expect(json_response.last['certificate_expiration']['expired']).to be true + expect(json_response.first).not_to have_key('certificate_expiration') + end + end + + context 'when authenticated as a non-member' do + it_behaves_like '403 response' do + let(:request) { get api('/pages/domains', user) } + end + end + end + end + describe 'GET /projects/:project_id/pages/domains' do shared_examples_for 'get pages domains' do it 'returns paginated pages domains' do get api(route, user) expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domains') expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(3) @@ -99,6 +137,7 @@ describe API::PagesDomains do get api(route_domain, user) expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(json_response['domain']).to eq(pages_domain.domain) expect(json_response['url']).to eq(pages_domain.url) expect(json_response['certificate']).to be_nil @@ -108,6 +147,7 @@ describe API::PagesDomains do get api(route_secure_domain, user) expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(json_response['domain']).to eq(pages_domain_secure.domain) expect(json_response['url']).to eq(pages_domain_secure.url) expect(json_response['certificate']['subject']).to eq(pages_domain_secure.subject) @@ -118,6 +158,7 @@ describe API::PagesDomains do get api(route_expired_domain, user) expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(json_response['certificate']['expired']).to be true end end @@ -187,6 +228,7 @@ describe API::PagesDomains do pages_domain = PagesDomain.find_by(domain: json_response['domain']) expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain.domain).to eq(params[:domain]) expect(pages_domain.certificate).to be_nil expect(pages_domain.key).to be_nil @@ -197,6 +239,7 @@ describe API::PagesDomains do pages_domain = PagesDomain.find_by(domain: json_response['domain']) expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain.domain).to eq(params_secure[:domain]) expect(pages_domain.certificate).to eq(params_secure[:certificate]) expect(pages_domain.key).to eq(params_secure[:key]) @@ -270,6 +313,7 @@ describe API::PagesDomains do pages_domain_secure.reload expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain_secure.certificate).to be_nil expect(pages_domain_secure.key).to be_nil end @@ -279,6 +323,7 @@ describe API::PagesDomains do pages_domain.reload expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain.certificate).to eq(params_secure[:certificate]) expect(pages_domain.key).to eq(params_secure[:key]) end @@ -288,6 +333,7 @@ describe API::PagesDomains do pages_domain_expired.reload expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain_expired.certificate).to eq(params_secure[:certificate]) expect(pages_domain_expired.key).to eq(params_secure[:key]) end @@ -297,6 +343,7 @@ describe API::PagesDomains do pages_domain_secure.reload expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/pages_domain/detail') expect(pages_domain_secure.certificate).to eq(params_secure_nokey[:certificate]) end