Allows a setting and configuration option to allow access to APIV3. Setting allows us to selectively enable this for cloud instances too. https://community.openproject.com/wp/30007pull/8582/head
parent
38d2707946
commit
86b8ffc326
@ -0,0 +1,48 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
class Settings::ApiController < SettingsController |
||||
include AdminSettingsUpdater |
||||
|
||||
menu_item :settings_api |
||||
|
||||
def show |
||||
render template: 'settings/_api' |
||||
end |
||||
|
||||
def default_breadcrumb |
||||
t(:label_api_access_key_type) |
||||
end |
||||
|
||||
def settings_params |
||||
super.tap do |settings| |
||||
settings["apiv3_cors_origins"] = settings["apiv3_cors_origins"].split(/\r?\n/) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,49 @@ |
||||
<%#-- copyright |
||||
OpenProject is an open source project management software. |
||||
Copyright (C) 2012-2020 the OpenProject GmbH |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License version 3. |
||||
|
||||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
Copyright (C) 2010-2013 the ChiliProject Team |
||||
|
||||
This program is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU General Public License |
||||
as published by the Free Software Foundation; either version 2 |
||||
of the License, or (at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
|
||||
See docs/COPYRIGHT.rdoc for more details. |
||||
|
||||
++#%> |
||||
<%= toolbar title: t(:label_api_access_key_type) %> |
||||
|
||||
<%= styled_form_tag(update_api_settings_path, method: :patch) do %> |
||||
<section class="form--section"> |
||||
<fieldset class="form--fieldset"> |
||||
<legend class="form--fieldset-legend">Cross-Origin Resource Sharing (CORS)</legend> |
||||
</fieldset> |
||||
<div class="form--field"> |
||||
<%= setting_check_box :apiv3_cors_enabled %> |
||||
</div> |
||||
<div class="form--field"> |
||||
<%= setting_text_area :apiv3_cors_origins, rows: 5, container_class: '-wide' %> |
||||
<div class="form--field-instructions"> |
||||
<p><%= t(:text_line_separated) %></p> |
||||
<p><%= t(:setting_apiv3_cors_origins_text_html, |
||||
origin_link: ::OpenProject::Static::Links[:origin_mdn_documentation][:href]) %></p> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
<%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> |
||||
<% end %> |
@ -0,0 +1,38 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
Rails.application.config.middleware.insert_before 0, Rack::Cors do |
||||
allow do |
||||
origins { |source, env| ::API::V3::CORS.allowed?(source) } |
||||
resource '/api/v3*', |
||||
headers: :any, |
||||
methods: :any, |
||||
credentials: true, |
||||
if: proc { ::API::V3::CORS.enabled? } |
||||
end |
||||
end |
@ -0,0 +1,24 @@ |
||||
--- |
||||
sidebar_navigation: |
||||
title: API settings |
||||
description: Settings for API functionality of OpenProject |
||||
robots: index, follow |
||||
keywords: API settings |
||||
--- |
||||
# API system settings |
||||
|
||||
In the API settings, you can selectively control whether foreign applications may access your OpenProject |
||||
API endpoints from within the browser. |
||||
|
||||
## Cross-Origin Resource Sharing (CORS) |
||||
|
||||
To enable CORS headers being returned by the [OpenProject APIv3](https://docs.openproject.org/api/), |
||||
enable the check box on this page. |
||||
|
||||
You will then have to enter the allowed values for the Origin header that OpenProject will allow access to. |
||||
This is necessary, since authenticated resources of OpenProject cannot be accessible to all origins with the `*` header value. |
||||
|
||||
For more information on the concepts of Cross-Origin Resource Sharing (CORS), please see: |
||||
|
||||
- [an overview of CORS from MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). |
||||
- [a tutorial on CORS by Auth0](https://auth0.com/blog/cors-tutorial-a-guide-to-cross-origin-resource-sharing/) |
@ -0,0 +1,50 @@ |
||||
#-- encoding: UTF-8 |
||||
|
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
# CORS helper methods for the API v3 |
||||
module API |
||||
module V3 |
||||
module CORS |
||||
## |
||||
# Returns whether CORS headers should |
||||
# be set on the APIv3 resources |
||||
def self.enabled? |
||||
Setting.apiv3_cors_enabled? |
||||
end |
||||
|
||||
## |
||||
# Determine whether the given origin is included |
||||
# in the allowed origin list |
||||
def self.allowed?(source) |
||||
Setting.apiv3_cors_origins.include?(source) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,100 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'spec_helper' |
||||
require 'rack/test' |
||||
|
||||
describe 'API v3 CORS headers', |
||||
type: :request, |
||||
content_type: :json do |
||||
include Rack::Test::Methods |
||||
include Capybara::RSpecMatchers |
||||
include API::V3::Utilities::PathHelper |
||||
|
||||
context 'with setting enabled', |
||||
with_settings: { apiv3_cors_enabled: true } do |
||||
|
||||
context 'with allowed origin set to specific values', |
||||
with_settings: { apiv3_cors_origins: %w[https://foo.example.com bla.test] } do |
||||
|
||||
it 'outputs CORS headers', :aggregate_failures do |
||||
options '/api/v3', |
||||
nil, |
||||
'HTTP_ORIGIN' => 'https://foo.example.com', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' |
||||
|
||||
expect(last_response.headers['Access-Control-Allow-Origin']).to eq('https://foo.example.com') |
||||
expect(last_response.headers['Access-Control-Allow-Methods']).to eq('GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS') |
||||
expect(last_response.headers['Access-Control-Allow-Headers']).to eq('test') |
||||
expect(last_response.headers).to have_key('Access-Control-Max-Age') |
||||
end |
||||
|
||||
it 'rejects CORS headers for invalid origin' do |
||||
options '/api/v3', |
||||
nil, |
||||
'HTTP_ORIGIN' => 'invalid.example.com', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' |
||||
|
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Origin' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Methods' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Headers' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Max-Age' |
||||
end |
||||
|
||||
# CORS needs to output headers even if you're unauthorized to allow authentication |
||||
# to happen |
||||
it 'returns the CORS header on an unauthorized resource as well', :aggregate_failures do |
||||
options '/api/v3/work_packages/form', |
||||
nil, |
||||
'HTTP_ORIGIN' => 'https://foo.example.com' |
||||
|
||||
expect(last_response.headers['Access-Control-Allow-Origin']).to eq('https://foo.example.com') |
||||
expect(last_response.headers['Access-Control-Allow-Methods']).to eq('GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS') |
||||
expect(last_response.headers).to have_key('Access-Control-Max-Age') |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'when disabled', |
||||
with_settings: { apiv3_cors_enabled: false, apiv3_cors_origins: %w[foo.example.com] } do |
||||
it 'does not output CORS headers even though origin matches', :aggregate_failures do |
||||
options '/api/v3', |
||||
nil, |
||||
'HTTP_ORIGIN' => 'foo.example.com', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', |
||||
'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' |
||||
|
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Origin' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Methods' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Allow-Headers' |
||||
expect(last_response.headers).not_to have_key 'Access-Control-Max-Age' |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue