0006-Use-Redmine-s-permissions-as-OAuth2-scopes.patch

Jan from Planio www.plan.io, 2017-01-18 17:46

Download (7.87 KB)

View differences:

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'}
252
-