FEATURE: user API now contains scopes so permission is granular

previously we supported blanket read and write for user API, this
change amends it so we can define more limited scopes. A scope only
covers a few routes. You can not grant access to part of the site and
leave a large amount of the information hidden to API consumer.
This commit is contained in:
Sam
2016-10-14 16:05:27 +11:00
parent becff2de4d
commit f4f5524190
16 changed files with 164 additions and 75 deletions

View File

@@ -1,10 +1,63 @@
class UserApiKey < ActiveRecord::Base
SCOPES = {
read: [:get],
write: [:get, :post, :patch],
message_bus: [[:post, 'message_bus']],
push: nil,
notifications: [[:post, 'message_bus'], [:get, 'notifications#index'], [:put, 'notifications#mark_read']],
session_info: [[:get, 'session#current'], [:get, 'users#topic_tracking_state']]
}
belongs_to :user
def access
has_push = push && push_url.present? && SiteSetting.allowed_user_api_push_urls.include?(push_url)
"#{read ? "r" : ""}#{write ? "w" : ""}#{has_push ? "p" : ""}"
def self.allowed_scopes
Set.new(SiteSetting.allow_user_api_key_scopes.split("|"))
end
def self.available_scopes
@available_scopes ||= Set.new(SCOPES.keys.map(&:to_s))
end
def self.allow_permission?(permission, env)
verb, action = permission
actual_verb = env["REQUEST_METHOD"] || ""
# safe in Ruby 2.3 which is only one supported
return false unless actual_verb.downcase == verb.to_s
return true unless action
# not a rails route, special handling
return true if action == "message_bus" && env["PATH_INFO"] =~ /^\/message-bus\/.*\/poll/
params = env['action_dispatch.request.path_parameters']
return false unless params
actual_action = "#{params[:controller]}##{params[:action]}"
actual_action == action
end
def self.allow_scope?(name, env)
if allowed = SCOPES[name.to_sym]
good = allowed.any? do |permission|
allow_permission?(permission, env)
end
good || allow_permission?([:post, 'user_api_keys#revoke'], env)
end
end
def has_push?
(scopes.include?("push") || scopes.include?("notifications")) && push_url.present? && SiteSetting.allowed_user_api_push_urls.include?(push_url)
end
def allow?(env)
scopes.any? do |name|
UserApiKey.allow_scope?(name, env)
end
end
end
# == Schema Information