Feature #24808 » 0006-Use-Redmine-s-permissions-as-OAuth2-scopes.patch
app/controllers/application_controller.rb | ||
---|---|---|
115 | 115 |
elsif access_token = Doorkeeper.authenticate(request) |
116 | 116 |
if access_token.accessible? |
117 | 117 |
user = User.active.find_by_id(access_token.resource_owner_id) |
118 |
user.oauth_scope = access_token.scopes.all.map(&:to_sym) |
|
118 | 119 |
else |
119 | 120 |
doorkeeper_render_error |
120 | 121 |
end |
app/controllers/oauth2_applications_controller.rb | ||
---|---|---|
1 |
class Oauth2ApplicationsController < Doorkeeper::ApplicationsController |
|
2 | ||
3 |
private |
|
4 | ||
5 |
def application_params |
|
6 |
params[:doorkeeper_application] ||= {} |
|
7 |
params[:doorkeeper_application][:scopes] ||= [] |
|
8 | ||
9 |
scopes = Redmine::AccessControl.public_permissions.map{|p| p.name.to_s} |
|
10 | ||
11 |
if params[:doorkeeper_application][:scopes].is_a?(Array) |
|
12 |
scopes |= params[:doorkeeper_application][:scopes] |
|
13 |
else |
|
14 |
scopes |= params[:doorkeeper_application][:scopes].split(/\s+/) |
|
15 |
end |
|
16 |
params[:doorkeeper_application][:scopes] = scopes.join(' ') |
|
17 |
super |
|
18 |
end |
|
19 |
end |
app/models/user.rb | ||
---|---|---|
98 | 98 |
attr_accessor :password, :password_confirmation, :generate_password |
99 | 99 |
attr_accessor :last_before_login_on |
100 | 100 |
attr_accessor :remote_ip |
101 |
attr_writer :oauth_scope |
|
101 | 102 | |
102 | 103 |
# Prevents unauthorized assignments |
103 | 104 |
attr_protected :password, :password_confirmation, :hashed_password |
... | ... | |
654 | 655 |
def allowed_to?(action, context, options={}, &block) |
655 | 656 |
if context && context.is_a?(Project) |
656 | 657 |
return false unless context.allows_to?(action) |
657 |
# Admin users are authorized for anything else |
|
658 |
return true if admin? |
|
658 |
# Admin users are authorized for anything or what their oauth scope prescribes |
|
659 |
if admin? && @oauth_scope.present? |
|
660 |
Role.new(permissions: @oauth_scope).allowed_to?(action, @oauth_scope) |
|
661 |
elsif admin? |
|
662 |
return true |
|
663 |
end |
|
659 | 664 | |
660 | 665 |
roles = roles_for_project(context) |
661 | 666 |
return false unless roles |
662 | 667 |
roles.any? {|role| |
663 | 668 |
(context.is_public? || role.member?) && |
664 |
role.allowed_to?(action) && |
|
669 |
role.allowed_to?(action, @oauth_scope) &&
|
|
665 | 670 |
(block_given? ? yield(role, self) : true) |
666 | 671 |
} |
667 | 672 |
elsif context && context.is_a?(Array) |
... | ... | |
674 | 679 |
elsif context |
675 | 680 |
raise ArgumentError.new("#allowed_to? context argument must be a Project, an Array of projects or nil") |
676 | 681 |
elsif options[:global] |
677 |
# Admin users are always authorized |
|
678 |
return true if admin? |
|
682 |
# Admin users are always authorized, only limited by their oauth scope |
|
683 |
if admin? && @oauth_scope.present? |
|
684 |
Role.new(permissions: @oauth_scope).allowed_to?(action, @oauth_scope) |
|
685 |
elsif admin? |
|
686 |
return true |
|
687 |
end |
|
679 | 688 | |
680 | 689 |
# authorize if user has at least one role that has this permission |
681 | 690 |
roles = self.roles.to_a | [builtin_role] |
682 | 691 |
roles.any? {|role| |
683 |
role.allowed_to?(action) && |
|
692 |
role.allowed_to?(action, @oauth_scope) &&
|
|
684 | 693 |
(block_given? ? yield(role, self) : true) |
685 | 694 |
} |
686 | 695 |
else |
app/views/doorkeeper/applications/_form.html.erb | ||
---|---|---|
12 | 12 |
<% end %> |
13 | 13 |
</em> |
14 | 14 |
</p> |
15 |
</div> |
|
15 | 16 | |
16 |
<p> |
|
17 |
<%= f.text_field :scopes, :size => 60, :label => :'activerecord.attributes.doorkeeper/application.scopes' %> |
|
18 |
<em class="info"> |
|
19 |
<%= t('doorkeeper.applications.help.scopes') %> |
|
20 |
</em> |
|
21 |
</p> |
|
22 | ||
23 | ||
24 | ||
17 |
<h3><%= l(:'activerecord.attributes.doorkeeper/application.scopes') %></h3> |
|
18 |
<div class="box tabular" id="scopes"> |
|
19 |
<% perms_by_module = Redmine::AccessControl.permissions.group_by {|p| p.project_module.to_s} %> |
|
20 |
<% perms_by_module.keys.sort.each do |mod| %> |
|
21 |
<fieldset><legend><%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %></legend> |
|
22 |
<% perms_by_module[mod].each do |permission| %> |
|
23 |
<label class="floating"> |
|
24 |
<%= check_box_tag 'doorkeeper_application[scopes][]', permission.name.to_s, (permission.public? || @application.scopes.include?( permission.name.to_s)), |
|
25 |
:id => "doorkeeper_application_scopes_#{permission.name}", |
|
26 |
:data => {:shows => ".#{permission.name}_shown"}, |
|
27 |
:disabled => permission.public? %> |
|
28 |
<%= l_or_humanize(permission.name, :prefix => 'permission_') %> |
|
29 |
</label> |
|
30 |
<% end %> |
|
31 |
</fieldset> |
|
32 |
<% end %> |
|
33 |
<br /><%= check_all_links 'scopes' %> |
|
34 |
<%= hidden_field_tag 'doorkeeper_application[scopes][]', '' %> |
|
25 | 35 |
</div> |
config/initializers/doorkeeper.rb | ||
---|---|---|
3 | 3 |
reuse_access_token |
4 | 4 |
realm Redmine::Info.app_name |
5 | 5 |
base_controller 'ApplicationController' |
6 |
default_scopes :public |
|
6 |
default_scopes *Redmine::AccessControl.public_permissions.map(&:name) |
|
7 |
optional_scopes *Redmine::AccessControl.permissions.map(&:name) |
|
7 | 8 | |
8 | 9 |
resource_owner_authenticator do |
9 | 10 |
if require_login |
config/routes.rb | ||
---|---|---|
17 | 17 | |
18 | 18 |
Rails.application.routes.draw do |
19 | 19 | |
20 |
use_doorkeeper |
|
20 |
use_doorkeeper do |
|
21 |
controllers :applications => 'oauth2_applications' |
|
22 |
end |
|
21 | 23 | |
22 | 24 |
root :to => 'welcome#index' |
23 | 25 |
root :to => 'welcome#index', :as => 'home' |
lib/redmine.rb | ||
---|---|---|
245 | 245 |
:html => {:class => 'icon icon-server-authentication'} |
246 | 246 |
menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true, |
247 | 247 |
:html => {:class => 'icon icon-plugins'} |
248 |
menu.push :applications, {:controller => 'doorkeeper/applications', :action => 'index'}, :last => true,
|
|
248 |
menu.push :applications, {:controller => 'oauth2_applications', :action => 'index'}, :last => true,
|
|
249 | 249 |
:if => Proc.new { Setting.rest_api_enabled? }, |
250 | 250 |
:caption => :'doorkeeper.layouts.admin.nav.applications', |
251 | 251 |
:html => {:class => 'icon icon-applications'} |