Skip to content

Commit e2cb067

Browse files
authored
Merge pull request opf#6824 from opf/feature/oauth
[28952] OAuth provider for API authentication
2 parents 57874ef + 90cade5 commit e2cb067

50 files changed

Lines changed: 2238 additions & 23 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ gem 'rubytree', git: 'https://github.com/dr0verride/RubyTree.git', ref: '06f53ee
4141
gem 'rdoc', '>= 2.4.2'
4242

4343
gem 'omniauth', git: 'https://github.com/oliverguenther/omniauth', ref: '40c6f5f751d2da7cce5444bbd96c390c450440a9'
44+
gem 'doorkeeper', git: 'https://github.com/doorkeeper-gem/doorkeeper', ref: 'ce969eee6c16aa8082b0c77ebb5968d9e9b6a57b'
4445
gem 'request_store', '~> 1.4.1'
4546

4647
gem 'warden', '~> 1.2'

Gemfile.lock

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
GIT
2+
remote: https://github.com/doorkeeper-gem/doorkeeper
3+
revision: ce969eee6c16aa8082b0c77ebb5968d9e9b6a57b
4+
ref: ce969eee6c16aa8082b0c77ebb5968d9e9b6a57b
5+
specs:
6+
doorkeeper (5.0.2)
7+
railties (>= 4.2)
8+
19
GIT
210
remote: https://github.com/dr0verride/RubyTree.git
311
revision: 06f53ee78cc2a48377c1bd177d3bc83c1504701c
@@ -860,6 +868,7 @@ DEPENDENCIES
860868
database_cleaner (~> 1.6)
861869
date_validator (~> 0.9.0)
862870
delayed_job_active_record (~> 4.1.1)
871+
doorkeeper!
863872
equivalent-xml (~> 0.6)
864873
escape_utils (~> 1.0)
865874
factory_bot (~> 4.8)

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
require File.expand_path('../config/application', __FILE__)
3434

35-
OpenProject::Application.load_tasks
35+
OpenProject::Application.load_rake_tasks
3636

3737
Rake::Task[:default].clear
3838
task default: 'test:suite:run'

app/assets/stylesheets/content/_buttons.sass

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ html.-browser-windows.-browser-chrome
155155
border: none
156156
padding: 0 1px
157157

158+
&.-expand
159+
@include button-expand
160+
158161
&:visited, &:active
159162
@include varprop(color, content-link-color)
160163

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
module OAuth
2+
module Applications
3+
class RowCell < ::RowCell
4+
include ::IconsHelper
5+
include ::OAuthHelper
6+
include ::OpenProject::ObjectLinking
7+
8+
def application
9+
model
10+
end
11+
12+
def name
13+
link_to application.name, oauth_application_path(application)
14+
end
15+
16+
def owner
17+
link_to application.owner.name, user_path(application.owner)
18+
end
19+
20+
def confidential
21+
if application.confidential?
22+
op_icon 'icon icon-checkmark'
23+
end
24+
end
25+
26+
def redirect_uri
27+
urls = application.redirect_uri.split("\n")
28+
safe_join urls, '<br/>'.html_safe
29+
end
30+
31+
def client_credentials
32+
if user_id = application.client_credentials_user_id
33+
link_to_user User.find(user_id)
34+
else
35+
'-'
36+
end
37+
end
38+
39+
def confidential
40+
application.confidential
41+
end
42+
43+
def edit_link
44+
link_to(
45+
I18n.t(:button_edit),
46+
edit_oauth_application_path(application),
47+
class: "oauth-application--edit-link icon icon-edit"
48+
)
49+
end
50+
51+
def button_links
52+
[
53+
edit_link,
54+
delete_link(oauth_application_path(application))
55+
]
56+
end
57+
end
58+
end
59+
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require_dependency 'oauth/applications/row_cell'
2+
3+
module OAuth
4+
module Applications
5+
class TableCell < ::TableCell
6+
7+
8+
class << self
9+
def row_class
10+
::OAuth::Applications::RowCell
11+
end
12+
end
13+
14+
def initial_sort
15+
%i[id asc]
16+
end
17+
18+
def sortable?
19+
false
20+
end
21+
22+
def columns
23+
headers.map(&:first)
24+
end
25+
26+
def inline_create_link
27+
link_to new_oauth_application_path,
28+
aria: { label: t('oauth.application.new') },
29+
class: 'wp-inline-create--add-link',
30+
title: t('oauth.application.new') do
31+
op_icon('icon icon-add')
32+
end
33+
end
34+
35+
def empty_row_message
36+
I18n.t :no_results_title_text
37+
end
38+
39+
def headers
40+
[
41+
['name', caption: ::Doorkeeper::Application.human_attribute_name(:name)],
42+
['owner', caption: ::Doorkeeper::Application.human_attribute_name(:owner)],
43+
['client_credentials', caption: I18n.t('oauth.client_credentials')],
44+
['redirect_uri', caption: ::Doorkeeper::Application.human_attribute_name(:redirect_uri)],
45+
['confidential', caption: ::Doorkeeper::Application.human_attribute_name(:confidential)],
46+
]
47+
end
48+
end
49+
end
50+
end

app/cells/table_cell.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ def columns
102102
end
103103

104104
def render_row(row)
105-
prefix = (self.class.namespace || "table").underscore
106-
cell("#{prefix}/row", row, table: self).call
105+
cell(self.class.row_class, row, table: self).call
107106
end
108107

109108
def initial_sort
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#-- encoding: UTF-8
2+
3+
#-- copyright
4+
# OpenProject is a project management system.
5+
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2017 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See doc/COPYRIGHT.rdoc for more details.
29+
#++
30+
31+
require 'model_contract'
32+
33+
module Oauth
34+
class ApplicationContract < ::ModelContract
35+
def self.model
36+
::Doorkeeper::Application
37+
end
38+
39+
def validate
40+
validate_client_credential_user
41+
42+
super
43+
end
44+
45+
attribute :name
46+
attribute :redirect_uri
47+
attribute :confidential
48+
attribute :owner_id
49+
attribute :owner_type
50+
attribute :scopes
51+
attribute :client_credentials_user_id
52+
53+
private
54+
55+
def validate_client_credential_user
56+
return unless model.client_credentials_user_id.present?
57+
58+
unless User.where(id: model.client_credentials_user_id).exists?
59+
errors.add :client_credentials_user_id, :invalid
60+
end
61+
end
62+
end
63+
end
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#-- encoding: UTF-8
2+
#-- copyright
3+
# OpenProject is a project management system.
4+
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License version 3.
8+
#
9+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
10+
# Copyright (C) 2006-2017 Jean-Philippe Lang
11+
# Copyright (C) 2010-2013 the ChiliProject Team
12+
#
13+
# This program is free software; you can redistribute it and/or
14+
# modify it under the terms of the GNU General Public License
15+
# as published by the Free Software Foundation; either version 2
16+
# of the License, or (at your option) any later version.
17+
#
18+
# This program is distributed in the hope that it will be useful,
19+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
# GNU General Public License for more details.
22+
#
23+
# You should have received a copy of the GNU General Public License
24+
# along with this program; if not, write to the Free Software
25+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26+
#
27+
# See docs/COPYRIGHT.rdoc for more details.
28+
#++
29+
30+
31+
module OAuth
32+
class ApplicationsController < ::ApplicationController
33+
before_action :require_admin
34+
before_action :new_app, only: %i[new create]
35+
before_action :find_app, only: %i[edit update show destroy]
36+
37+
layout 'admin'
38+
menu_item :oauth_applications
39+
40+
def index
41+
@applications = ::Doorkeeper::Application.includes(:owner).all
42+
end
43+
44+
def new; end
45+
def edit; end
46+
47+
def show
48+
@reveal_secret = flash[:reveal_secret]
49+
flash.delete :reveal_secret
50+
end
51+
52+
def create
53+
call = ::OAuth::PersistApplicationService.new(@application, user: current_user)
54+
.call(permitted_params.oauth_application)
55+
56+
if call.success?
57+
flash[:notice] = t(:notice_successful_create)
58+
flash[:_application_secret] = call.result.plaintext_secret
59+
redirect_to action: :show, id: call.result.id
60+
else
61+
@errors = call.errors
62+
flash[:error] = call.errors.full_messages.join('\n')
63+
render action: :new
64+
end
65+
end
66+
67+
def update
68+
call = ::OAuth::PersistApplicationService.new(@application, user: current_user)
69+
.call(permitted_params.oauth_application)
70+
71+
if call.success?
72+
flash[:notice] = t(:notice_successful_update)
73+
redirect_to action: :index
74+
else
75+
@errors = call.errors
76+
flash[:error] = call.errors.full_messages.join('\n')
77+
render action: :edit
78+
end
79+
end
80+
81+
def destroy
82+
if @application.destroy
83+
flash[:notice] = t(:notice_successful_delete)
84+
else
85+
flash[:error] = t(:error_can_not_delete_entry)
86+
end
87+
88+
redirect_to action: :index
89+
end
90+
91+
92+
protected
93+
94+
def default_breadcrumb
95+
if action_name == 'index'
96+
t('oauth.application.plural')
97+
else
98+
ActionController::Base.helpers.link_to(t('oauth.application.plural'), oauth_applications_path)
99+
end
100+
end
101+
102+
def show_local_breadcrumb
103+
current_user.admin?
104+
end
105+
106+
private
107+
108+
def new_app
109+
@application = ::Doorkeeper::Application.new
110+
end
111+
112+
def find_app
113+
@application = ::Doorkeeper::Application.find(params[:id])
114+
rescue ActiveRecord::RecordNotFound
115+
render_404
116+
end
117+
end
118+
end
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#-- encoding: UTF-8
2+
#-- copyright
3+
# OpenProject is a project management system.
4+
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License version 3.
8+
#
9+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
10+
# Copyright (C) 2006-2017 Jean-Philippe Lang
11+
# Copyright (C) 2010-2013 the ChiliProject Team
12+
#
13+
# This program is free software; you can redistribute it and/or
14+
# modify it under the terms of the GNU General Public License
15+
# as published by the Free Software Foundation; either version 2
16+
# of the License, or (at your option) any later version.
17+
#
18+
# This program is distributed in the hope that it will be useful,
19+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+
# GNU General Public License for more details.
22+
#
23+
# You should have received a copy of the GNU General Public License
24+
# along with this program; if not, write to the Free Software
25+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26+
#
27+
# See docs/COPYRIGHT.rdoc for more details.
28+
#++
29+
30+
31+
module OAuth
32+
##
33+
# Base controller for doorkeeper to skip the login check
34+
# because it needs to set a specific return URL
35+
# See config/initializers/doorkeeper.rb
36+
class AuthBaseController < ::ApplicationController
37+
skip_before_action :check_if_login_required
38+
layout 'only_logo'
39+
end
40+
end

0 commit comments

Comments
 (0)