enforces authorization for experimental api

pull/1902/head
Jens Ulferts 10 years ago
parent f91256fef9
commit 3c730ef131
  1. 20
      app/controllers/api/experimental/api_controller.rb
  2. 47
      app/controllers/api/experimental/groups_controller.rb
  3. 4
      app/controllers/api/experimental/projects_controller.rb
  4. 6
      app/controllers/api/experimental/queries_controller.rb
  5. 8
      app/controllers/api/experimental/users_controller.rb
  6. 3
      app/controllers/api/experimental/versions_controller.rb
  7. 24
      app/controllers/api/experimental/work_packages_controller.rb
  8. 21
      lib/redmine.rb
  9. 103
      spec/controllers/api/experimental/projects_controller_spec.rb
  10. 242
      spec/controllers/api/experimental/queries_controller_spec.rb
  11. 82
      spec/controllers/api/experimental/users_controller_spec.rb
  12. 16
      spec/controllers/api/experimental/versions_controller_spec.rb
  13. 59
      spec/controllers/api/experimental/work_packages_controller_spec.rb

@ -28,23 +28,13 @@
module Api
module Experimental
module ApiController
include ::Api::V2::ApiController
extend ::Api::V2::ApiController::ClassMethods
def api_version
/api\/experimental\//
def self.included(base)
base.class_eval do
skip_before_filter :disable_api
prepend_before_filter :disable_everything_except_api
end
end
permeate_permissions :authorize,
:apply_at_timestamp,
:determine_base,
:find_all_projects_by_project_id,
:find_project_by_project_id,
:jump_to_project_menu_item,
:find_optional_project_and_raise_error
end
end
end

@ -1,47 +0,0 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# 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-2013 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 doc/COPYRIGHT.rdoc for more details.
#++
module Api
module Experimental
class GroupsController < ApplicationController
include ::Api::Experimental::ApiController
def index
@groups = Group.all
respond_to do |format|
format.api
end
end
end
end
end

@ -33,7 +33,9 @@ module Api
class ProjectsController < ApplicationController
include ::Api::Experimental::ApiController
before_filter :find_project, except: [:index]
before_filter :find_project,
:authorize, except: [:index]
before_filter :authorize_global, only: [:index]
def index
# Note: Ordering by project hierarchy by default

@ -33,9 +33,9 @@ module Api::Experimental
unloadable
include ApiController
include Concerns::GrapeRouting
include Concerns::ColumnData
include Concerns::QueryLoading
include Api::Experimental::Concerns::GrapeRouting
include Api::Experimental::Concerns::ColumnData
include Api::Experimental::Concerns::QueryLoading
include QueriesHelper
include ExtendedHTTP

@ -31,10 +31,10 @@ module Api
module Experimental
class UsersController < ApplicationController
before_filter :find_optional_project, only: [:index]
include ::Api::Experimental::ApiController
before_filter :find_optional_project
def index
@users = if @project
projects_principals
@ -73,10 +73,6 @@ module Api
principals.sort
end
def find_optional_project
@project = Project.find(params[:project_id]) unless params[:project_id].blank?
end
end
end
end

@ -31,7 +31,8 @@ module Api
module Experimental
class VersionsController < ApplicationController
before_filter :find_project
before_filter :find_project,
:authorize
include ::Api::Experimental::ApiController

@ -44,11 +44,8 @@ module Api
include SortHelper
include ExtendedHTTP
# before_filter :authorize # TODO specify authorization
before_filter :authorize_request, only: [:column_data]
before_filter :find_optional_project, only: [:index, :column_sums]
before_filter :load_query, only: [:index, :column_sums]
before_filter :find_optional_project
before_filter :load_query, only: [:index]
before_filter :assign_work_packages, only: [:index]
def index
@ -85,13 +82,6 @@ module Api
}
end
def column_sums
raise 'API Error' unless params[:column_names]
column_names = params[:column_names]
@column_sums = columns_total_sums(column_names, all_query_work_packages)
end
private
def setup_context_menu_actions
@ -127,16 +117,6 @@ module Api
render_404
end
def authorize_request
# TODO: need to give this action a global role i think. tried making load_column_data role in reminde.rb
# but couldn't get it working.
# authorize_global unless performed?
end
def find_optional_project
@project = Project.find(params[:project_id]) if params[:project_id]
end
def assign_work_packages
@work_packages = current_work_packages(@project) unless performed?
end

@ -106,12 +106,21 @@ Redmine::AccessControl.map do |map|
:auto_complete => [:issues],
:versions => [:index, :show, :status_by],
:journals => [:index, :diff],
:queries => [:index, :create, :update, :available_columns, :custom_field_filters, :grouped],
:work_packages => [:show, :index],
:work_packages_api => [:get],
:'work_packages/reports' => [:report, :report_details],
:planning_elements => [:index, :all, :show, :recycle_bin],
:planning_element_journals => [:index]}
:planning_element_journals => [:index],
:'api/experimental/queries' => [:available_columns,
:custom_field_filters,
:grouped],
:'api/experimental/users' => [:index],
:'api/experimental/versions' => [:index],
:'api/experimental/projects' => [:show,
:sub_projects,
:index],
:'api/experimental/work_packages' => [:index,
:column_data] }
map.permission :export_work_packages, {:'work_packages' => [:index, :all]}
map.permission :add_work_packages, { :issues => [:new, :create, :update_form],
:'issues/previews' => :create,
@ -137,8 +146,12 @@ Redmine::AccessControl.map do |map|
map.permission :manage_work_package_relations, {:work_package_relations => [:create, :destroy]}
map.permission :manage_subtasks, {}
# Queries
map.permission :manage_public_queries, {:queries => [:new, :edit, :star, :unstar, :destroy]}, :require => :member
map.permission :save_queries, {:queries => [:new, :edit, :star, :unstar, :destroy]}, :require => :loggedin
map.permission :manage_public_queries, { :'api/experimental/queries' => [:create,
:update,
:destroy],
:queries => [:star, :unstar] }, :require => :member
map.permission :save_queries, { :'api/experimental/queries' => [:create, :update, :destroy],
:'queries' => [:star, :unstar] }, :require => :loggedin
# Watchers
map.permission :view_work_package_watchers, {}
map.permission :add_work_package_watchers, {:watchers => [:new, :create]}

@ -0,0 +1,103 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# 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-2013 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 doc/COPYRIGHT.rdoc for more details.
#++
require File.expand_path('../../../../spec_helper', __FILE__)
describe Api::Experimental::ProjectsController, type: :controller do
let(:current_user) do
FactoryGirl.create(:user, member_in_project: project,
member_through_role: role)
end
let(:project) { FactoryGirl.create(:project) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_work_packages]) }
before do
allow(User).to receive(:current).and_return(current_user)
allow(Project).to receive(:find).and_return(project)
end
describe '#index' do
before do
get 'index', format: 'xml'
end
context 'with the necessary permissions' do
it 'should respond with 200' do
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
expect(response.response_code).to eql(403)
end
end
end
describe '#show' do
before do
get 'show', format: 'xml', project_id: project.identifier
end
context 'with the necessary permissions' do
it 'should respond with 200' do
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
expect(response.response_code).to eql(403)
end
end
end
describe '#sub_projects' do
before do
get 'sub_projects', format: 'xml', project_id: project.identifier
end
context 'with the necessary permissions' do
it 'should respond with 200' do
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
expect(response.response_code).to eql(403)
end
end
end
end

@ -29,7 +29,15 @@
require File.expand_path('../../../../spec_helper', __FILE__)
describe Api::Experimental::QueriesController, :type => :controller do
let(:current_user) { FactoryGirl.create(:admin) }
let(:current_user) do
FactoryGirl.create(:user, member_in_project: project,
member_through_role: role)
end
let(:project) { FactoryGirl.create(:project) }
let(:role) do
FactoryGirl.create(:role, permissions: [:view_work_packages,
:save_queries])
end
before do
allow(User).to receive(:current).and_return(current_user)
@ -49,6 +57,20 @@ describe Api::Experimental::QueriesController, :type => :controller do
get :available_columns, format: :xml
expect(response).to render_template('api/experimental/queries/available_columns', formats: %w(api))
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
get :available_columns, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
get :available_columns, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
describe '#custom_field_filters' do
@ -63,6 +85,224 @@ describe Api::Experimental::QueriesController, :type => :controller do
get :custom_field_filters, format: :xml
expect(response).to render_template('api/experimental/queries/custom_field_filters', formats: %w(api))
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
get :custom_field_filters, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
get :custom_field_filters, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
describe '#grouped' do
context 'within a project' do
it 'responds with 200' do
get :grouped, format: :xml, project_id: project.id
end
end
context 'without a project' do
it 'responds with 200' do
get :grouped, format: :xml
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
post :grouped, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
post :grouped, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
describe '#create' do
context 'within a project' do
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'project_id' => project.id,
'format' => 'xml' }
end
it 'responds with 200' do
post :create, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without a project' do
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'format' => 'xml' }
end
it 'responds with 200' do
post :create, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
post :create, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
post :create, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
describe '#update' do
context 'within a project' do
let(:query) { FactoryGirl.create(:query, project: project) }
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'query_id' => query.id,
'id' => query.id,
'project_id' => project.id,
'format' => 'xml' }
end
it 'responds with 200' do
post :update, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without a project' do
let(:query) { FactoryGirl.create(:query, project: nil) }
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'query_id' => query.id,
'id' => query.id,
'format' => 'xml' }
end
it 'responds with 200' do
post :update, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
post :update, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
post :update, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
describe '#destroy' do
context 'within a project' do
let(:query) { FactoryGirl.create(:query, project: project) }
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'query_id' => query.id,
'id' => query.id,
'project_id' => project.id,
'format' => 'xml' }
end
it 'responds with 200' do
delete :destroy, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without a project' do
let(:query) { FactoryGirl.create(:query, project: nil) }
let(:valid_params) do
{ 'c' => ['type', 'status', 'priority', 'assigned_to'],
'f' => ['status_id'],
'group_by' => '',
'is_public' => 'false',
'name' => 'sdfsdfsdf',
'op' => { 'status_id' => 'o' },
'sort' => 'parent:desc',
'query_id' => query.id,
'id' => query.id,
'format' => 'xml' }
end
it 'responds with 200' do
delete :destroy, valid_params
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403 to global request' do
delete :destroy, format: :xml
expect(response.response_code).to eql(403)
end
it 'should respond with 403 to project scoped request' do
delete :destroy, format: :xml, project_id: project.id
expect(response.response_code).to eql(403)
end
end
end
end

@ -0,0 +1,82 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# 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-2013 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 doc/COPYRIGHT.rdoc for more details.
#++
require File.expand_path('../../../../spec_helper', __FILE__)
describe Api::Experimental::UsersController, type: :controller do
let(:current_user) { FactoryGirl.create(:user, member_in_project: project, member_through_role: role) }
let(:project) { FactoryGirl.create(:project) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_work_packages]) }
before do
allow(User).to receive(:current).and_return(current_user)
allow(Project).to receive(:find).and_return(project)
end
describe '#index' do
context 'without a project' do
before do
get 'index', format: 'xml'
end
context 'with the necessary permissions' do
it 'should respond with 200' do
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
expect(response.response_code).to eql(403)
end
end
end
context 'with a project' do
before do
get 'index', project_id: project.id, format: 'xml'
end
context 'with the necessary permissions' do
it 'should respond with 200' do
expect(response.response_code).to eql(200)
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
expect(response.response_code).to eql(403)
end
end
end
end
end

@ -29,8 +29,12 @@
require File.expand_path('../../../../spec_helper', __FILE__)
describe Api::Experimental::VersionsController, :type => :controller do
let(:current_user) { FactoryGirl.create(:admin) }
let(:current_user) do
FactoryGirl.create(:user, member_in_project: project,
member_through_role: role)
end
let(:project) { FactoryGirl.create(:project) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_work_packages]) }
before do
allow(User).to receive(:current).and_return(current_user)
@ -60,6 +64,14 @@ describe Api::Experimental::VersionsController, :type => :controller do
expect(assigns(:versions).size).to eq 2
end
end
end
context 'when lacking the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should respond with 403' do
get 'index', format: 'xml', project_id: 1
expect(response.response_code).to eql(403)
end
end
end
end

@ -36,16 +36,14 @@ describe Api::Experimental::WorkPackagesController, :type => :controller do
let(:project_2) { FactoryGirl.create(:project,
types: [type],
is_public: false) }
let(:role) { FactoryGirl.create(:role,
permissions: [:view_work_packages,
let(:role) do
FactoryGirl.create(:role, permissions: [:view_work_packages,
:add_work_packages,
:edit_work_packages,
:move_work_packages,
:delete_work_packages]) }
let(:member) { FactoryGirl.create(:member,
project: project_1,
principal: user,
roles: [role]) }
:delete_work_packages,
:log_time])
end
let(:status_1) { FactoryGirl.create(:status) }
let(:work_package_1) { FactoryGirl.create(:work_package,
author: user,
@ -65,11 +63,12 @@ describe Api::Experimental::WorkPackagesController, :type => :controller do
let(:query_1) { FactoryGirl.create(:query,
project: project_1) }
let(:current_user) { FactoryGirl.create(:admin) }
let(:current_user) do
FactoryGirl.create(:user, member_in_project: project_1,
member_through_role: role)
end
before do
member
allow(User).to receive(:current).and_return(current_user)
end
@ -146,6 +145,14 @@ describe Api::Experimental::WorkPackagesController, :type => :controller do
context 'with default query' do
let(:work_packages) { [work_package_1, work_package_2, work_package_3] }
before do
# As work_package_3 is in project_2 we need to make the
# current user a member
FactoryGirl.create(:member, project: project_2,
principal: current_user,
roles: [role])
end
it 'assigns work packages array + actions' do
get 'index', format: 'xml'
@ -154,6 +161,22 @@ describe Api::Experimental::WorkPackagesController, :type => :controller do
end
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should return 403 for the global action' do
get 'index', format: 'xml'
expect(response.response_code).to eql(403)
end
it 'should return 403 for the project based action' do
get 'index', format: 'xml', project_id: project_1.id
expect(response.response_code).to eql(403)
end
end
end
describe '#column_data' do
@ -210,6 +233,22 @@ describe Api::Experimental::WorkPackagesController, :type => :controller do
expect(response).to render_template('api/experimental/work_packages/column_data', formats: %w(api))
end
end
context 'without the necessary permissions' do
let(:role) { FactoryGirl.create(:role, permissions: []) }
it 'should return 403 for the global action' do
get 'column_data', format: 'xml'
expect(response.response_code).to eql(403)
end
it 'should return 403 for the project based action' do
get 'column_data', format: 'xml', project_id: project_1.id
expect(response.response_code).to eql(403)
end
end
end
end

Loading…
Cancel
Save