DEV: Add support for allowed parameters in user api key scopes

Initially, this feature is only intended for use in core/plugins, so there is no API for requesting a parameter-scoped key. That may change in future.
This commit is contained in:
David Taylor 2020-10-08 17:38:54 +01:00
parent 1cec333f48
commit 23e5c605f6
5 changed files with 53 additions and 7 deletions

View File

@ -12,7 +12,8 @@ class UserApiKeyScope < ActiveRecord::Base
RouteMatcher.new(methods: :get, actions: 'notifications#index'), RouteMatcher.new(methods: :get, actions: 'notifications#index'),
RouteMatcher.new(methods: :put, actions: 'notifications#mark_read') RouteMatcher.new(methods: :put, actions: 'notifications#mark_read')
], ],
session_info: [ RouteMatcher.new(methods: :get, actions: 'session#current') ] session_info: [ RouteMatcher.new(methods: :get, actions: 'session#current') ],
bookmarks_calendar: [ RouteMatcher.new(methods: :get, actions: 'users#bookmarks', formats: :ics, params: %i[username]) ]
} }
def self.all_scopes def self.all_scopes
@ -20,7 +21,7 @@ class UserApiKeyScope < ActiveRecord::Base
end end
def permits?(env) def permits?(env)
matchers.any? { |m| m.match?(env: env) } matchers.any? { |m| m.with_allowed_param_values(allowed_parameters).match?(env: env) }
end end
private private
@ -35,11 +36,12 @@ end
# #
# Table name: user_api_key_scopes # Table name: user_api_key_scopes
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# user_api_key_id :integer not null # user_api_key_id :integer not null
# name :string not null # name :string not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# allowed_parameters :jsonb
# #
# Indexes # Indexes
# #

View File

@ -1049,6 +1049,7 @@ en:
read: "Read all" read: "Read all"
write: "Write all" write: "Write all"
one_time_password: "Create a one-time login token" one_time_password: "Create a one-time login token"
bookmarks_calendar: "Read bookmark reminders"
invalid_public_key: "Sorry, the public key is invalid." invalid_public_key: "Sorry, the public key is invalid."
invalid_auth_redirect: "Sorry, this auth_redirect host is not allowed." invalid_auth_redirect: "Sorry, this auth_redirect host is not allowed."
invalid_token: "Missing, invalid or expired token." invalid_token: "Missing, invalid or expired token."

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddAllowedParametersToUserApiKeyScope < ActiveRecord::Migration[6.0]
def change
add_column :user_api_key_scopes, :allowed_parameters, :jsonb
end
end

View File

@ -8,3 +8,10 @@ Fabricator(:readonly_user_api_key, from: :user_api_key) do
client_id { SecureRandom.hex } client_id { SecureRandom.hex }
application_name 'some app' application_name 'some app'
end end
Fabricator(:bookmarks_calendar_user_api_key, from: :user_api_key) do
user
scopes { [Fabricate.build(:user_api_key_scope, name: 'bookmarks_calendar')] }
client_id { SecureRandom.hex }
application_name 'some app'
end

View File

@ -99,4 +99,33 @@ describe 'user api keys' do
expect(response.status).to eq(302) expect(response.status).to eq(302)
end end
it "can restrict scopes by parameters" do
admin = Fabricate(:admin)
calendar_key = Fabricate(:bookmarks_calendar_user_api_key, user: admin)
get "/u/#{user.username}/bookmarks.json", headers: {
HTTP_USER_API_KEY: calendar_key.key,
}
expect(response.status).to eq(403) # Does not allow json
get "/u/#{user.username}/bookmarks.ics", headers: {
HTTP_USER_API_KEY: calendar_key.key,
}
expect(response.status).to eq(200) # Allows ICS
# Now restrict the key
calendar_key.scopes.first.update(allowed_parameters: { username: admin.username })
get "/u/#{user.username}/bookmarks.ics", headers: {
HTTP_USER_API_KEY: calendar_key.key,
}
expect(response.status).to eq(403) # Cannot access another users calendar
get "/u/#{admin.username}/bookmarks.ics", headers: {
HTTP_USER_API_KEY: calendar_key.key,
}
expect(response.status).to eq(200) # Can access own calendar
end
end end