Introduce privileged scopes that only an administrator can enable

This commit is contained in:
Tom Hughes 2021-07-30 22:24:51 +01:00
parent 6a9ab7cb2d
commit 6c6e8883f7
7 changed files with 38 additions and 20 deletions

View file

@ -20,8 +20,8 @@ class Oauth2ApplicationsController < Doorkeeper::ApplicationsController
end
def application_params
params[:doorkeeper_application][:scopes]&.delete("")
params.require(:doorkeeper_application)
params[:oauth2_application][:scopes]&.delete("")
params.require(:oauth2_application)
.permit(:name, :redirect_uri, :confidential, :scopes => [])
.merge(:owner => current_resource_owner)
end

View file

@ -0,0 +1,13 @@
class Oauth2Application < Doorkeeper::Application
belongs_to :owner, :polymorphic => true
validate :allowed_scopes
private
def allowed_scopes
return if owner.administrator?
errors.add(:scopes) if scopes.any? { |scope| Oauth::PRIVILEGED_SCOPES.include?(scope) }
end
end

View file

@ -3,5 +3,5 @@
<%= f.form_group :confidential do %>
<%= f.check_box :confidential %>
<% end %>
<%= f.collection_check_boxes :scopes, Oauth.scopes, :name, :description %>
<%= f.collection_check_boxes :scopes, Oauth.scopes(:privileged => current_user.administrator?), :name, :description %>
<%= f.primary %>

View file

@ -48,6 +48,8 @@ Doorkeeper.configure do
# end
# end
application_class "Oauth2Application"
# Enables polymorphic Resource Owner association for Access Tokens and Access Grants.
# By default this option is disabled.
#
@ -221,7 +223,7 @@ Doorkeeper.configure do
# https://doorkeeper.gitbook.io/guides/ruby-on-rails/scopes
# default_scopes :public
optional_scopes(*Oauth::SCOPES)
optional_scopes(*Oauth::SCOPES, *Oauth::PRIVILEGED_SCOPES)
# Allows to restrict only certain scopes for grant_type.
# By default, all the scopes will be available for all the grant types.

View file

@ -1,5 +1,6 @@
module Oauth
SCOPES = %w[read_prefs write_prefs write_diary write_api read_gpx write_gpx write_notes].freeze
PRIVILEGED_SCOPES = %w[].freeze
class Scope
attr_reader :name
@ -13,7 +14,9 @@ module Oauth
end
end
def self.scopes
SCOPES.collect { |s| Scope.new(s) }
def self.scopes(privileged: false)
scopes = SCOPES
scopes += PRIVILEGED_SCOPES if privileged
scopes.collect { |s| Scope.new(s) }
end
end

View file

@ -67,11 +67,11 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_response :success
assert_template "oauth2_applications/new"
assert_select "form", 1 do
assert_select "input#doorkeeper_application_name", 1
assert_select "textarea#doorkeeper_application_redirect_uri", 1
assert_select "input#doorkeeper_application_confidential", 1
assert_select "input#oauth2_application_name", 1
assert_select "textarea#oauth2_application_redirect_uri", 1
assert_select "input#oauth2_application_confidential", 1
Oauth.scopes.each do |scope|
assert_select "input#doorkeeper_application_scopes_#{scope.name}", 1
assert_select "input#oauth2_application_scopes_#{scope.name}", 1
end
end
end
@ -87,7 +87,7 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
session_for(user)
assert_difference "Doorkeeper::Application.count", 0 do
post oauth_applications_path(:doorkeeper_application => {
post oauth_applications_path(:oauth2_application => {
:name => "Test Application"
})
end
@ -95,7 +95,7 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_template "oauth2_applications/new"
assert_difference "Doorkeeper::Application.count", 0 do
post oauth_applications_path(:doorkeeper_application => {
post oauth_applications_path(:oauth2_application => {
:name => "Test Application",
:redirect_uri => "https://test.example.com/",
:scopes => ["bad_scope"]
@ -105,7 +105,7 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_template "oauth2_applications/new"
assert_difference "Doorkeeper::Application.count", 1 do
post oauth_applications_path(:doorkeeper_application => {
post oauth_applications_path(:oauth2_application => {
:name => "Test Application",
:redirect_uri => "https://test.example.com/",
:scopes => ["read_prefs"]
@ -154,11 +154,11 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_response :success
assert_template "oauth2_applications/edit"
assert_select "form", 1 do
assert_select "input#doorkeeper_application_name", 1
assert_select "textarea#doorkeeper_application_redirect_uri", 1
assert_select "input#doorkeeper_application_confidential", 1
assert_select "input#oauth2_application_name", 1
assert_select "textarea#oauth2_application_redirect_uri", 1
assert_select "input#oauth2_application_confidential", 1
Oauth.scopes.each do |scope|
assert_select "input#doorkeeper_application_scopes_#{scope.name}", 1
assert_select "input#oauth2_application_scopes_#{scope.name}", 1
end
end
end
@ -178,7 +178,7 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_template "oauth2_applications/not_found"
put oauth_application_path(:id => client,
:doorkeeper_application => {
:oauth2_application => {
:name => "New Name",
:redirect_uri => nil
})
@ -186,7 +186,7 @@ class Oauth2ApplicationsControllerTest < ActionDispatch::IntegrationTest
assert_template "oauth2_applications/edit"
put oauth_application_path(:id => client,
:doorkeeper_application => {
:oauth2_application => {
:name => "New Name",
:redirect_uri => "https://new.example.com/url"
})

View file

@ -1,5 +1,5 @@
FactoryBot.define do
factory :oauth_application, :class => "Doorkeeper::Application" do
factory :oauth_application, :class => "Oauth2Application" do
sequence(:name) { |n| "OAuth application #{n}" }
sequence(:redirect_uri) { |n| "https://example.com/app/#{n}" }