Drop support for OAuth 1
This commit is contained in:
parent
cee9818dfc
commit
17bc0853a0
48 changed files with 52 additions and 2395 deletions
|
@ -1,57 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# type :string(20)
|
||||
# client_application_id :integer
|
||||
# token :string(50)
|
||||
# secret :string(50)
|
||||
# authorized_at :datetime
|
||||
# invalidated_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# callback_url :string
|
||||
# verifier :string(20)
|
||||
# scope :string
|
||||
# valid_to :datetime
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_tokens_on_token (token) UNIQUE
|
||||
# index_oauth_tokens_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# oauth_tokens_client_application_id_fkey (client_application_id => client_applications.id)
|
||||
# oauth_tokens_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class AccessToken < OauthToken
|
||||
belongs_to :user, :optional => true
|
||||
belongs_to :client_application, :optional => true
|
||||
|
||||
scope :valid, -> { where(:invalidated_at => nil) }
|
||||
|
||||
validates :user, :secret, :presence => true
|
||||
|
||||
before_create :set_authorized_at
|
||||
|
||||
def includes_scope?(scope)
|
||||
self[:"allow_#{scope}"]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_authorized_at
|
||||
self.authorized_at = Time.now.utc
|
||||
end
|
||||
end
|
|
@ -1,109 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: client_applications
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string
|
||||
# url :string
|
||||
# support_url :string
|
||||
# callback_url :string
|
||||
# key :string(50)
|
||||
# secret :string(50)
|
||||
# user_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_client_applications_on_key (key) UNIQUE
|
||||
# index_client_applications_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# client_applications_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class ClientApplication < ApplicationRecord
|
||||
belongs_to :user, :optional => true
|
||||
has_many :tokens, :class_name => "OauthToken", :dependent => :delete_all
|
||||
has_many :access_tokens
|
||||
has_many :oauth2_verifiers
|
||||
has_many :oauth_tokens
|
||||
|
||||
validates :key, :presence => true, :uniqueness => true
|
||||
validates :name, :url, :secret, :presence => true
|
||||
validates :url, :format => /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
|
||||
validates :support_url, :allow_blank => true, :format => /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/
|
||||
validates :callback_url, :allow_blank => true, :format => /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
|
||||
|
||||
before_validation :generate_keys, :on => :create
|
||||
|
||||
attr_accessor :token_callback_url
|
||||
|
||||
def self.find_token(token_key)
|
||||
token = OauthToken.includes(:client_application).find_by(:token => token_key)
|
||||
token if token&.authorized?
|
||||
end
|
||||
|
||||
def self.verify_request(request, options = {}, &block)
|
||||
signature = OAuth::Signature.build(request, options, &block)
|
||||
return false unless OauthNonce.remember(signature.request.nonce, signature.request.timestamp)
|
||||
|
||||
signature.verify
|
||||
rescue OAuth::Signature::UnknownSignatureMethod
|
||||
false
|
||||
end
|
||||
|
||||
def self.all_permissions
|
||||
Oauth.scopes.collect { |s| :"allow_#{s.name}" }
|
||||
end
|
||||
|
||||
def oauth_server
|
||||
@oauth_server ||= OAuth::Server.new("https://#{Settings.server_url}")
|
||||
end
|
||||
|
||||
def credentials
|
||||
@credentials ||= OAuth::Consumer.new(key, secret)
|
||||
end
|
||||
|
||||
def create_request_token(_params = {})
|
||||
params = { :client_application => self, :callback_url => token_callback_url }
|
||||
permissions.each do |p|
|
||||
params[p] = true
|
||||
end
|
||||
RequestToken.create(params)
|
||||
end
|
||||
|
||||
def access_token_for_user(user)
|
||||
unless token = access_tokens.valid.find_by(:user_id => user)
|
||||
params = { :user => user }
|
||||
|
||||
permissions.each do |p|
|
||||
params[p] = true
|
||||
end
|
||||
|
||||
token = access_tokens.create(params)
|
||||
end
|
||||
|
||||
token
|
||||
end
|
||||
|
||||
# the permissions that this client would like from the user
|
||||
def permissions
|
||||
ClientApplication.all_permissions.select { |p| self[p] }
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def generate_keys
|
||||
self.key = OAuth::Helper.generate_key(40)[0, 40]
|
||||
self.secret = OAuth::Helper.generate_key(40)[0, 40]
|
||||
end
|
||||
end
|
|
@ -1,58 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# type :string(20)
|
||||
# client_application_id :integer
|
||||
# token :string(50)
|
||||
# secret :string(50)
|
||||
# authorized_at :datetime
|
||||
# invalidated_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# callback_url :string
|
||||
# verifier :string(20)
|
||||
# scope :string
|
||||
# valid_to :datetime
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_tokens_on_token (token) UNIQUE
|
||||
# index_oauth_tokens_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# oauth_tokens_client_application_id_fkey (client_application_id => client_applications.id)
|
||||
# oauth_tokens_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class Oauth2Token < AccessToken
|
||||
attr_accessor :state
|
||||
|
||||
def as_json(_options = {})
|
||||
d = { :access_token => token, :token_type => "bearer" }
|
||||
d[:expires_in] = expires_in if expires_at
|
||||
d
|
||||
end
|
||||
|
||||
def to_query
|
||||
q = "access_token=#{token}&token_type=bearer"
|
||||
q << "&state=#{CGI.escape(state)}" if @state
|
||||
q << "&expires_in=#{expires_in}" if expires_at
|
||||
q << "&scope=#{CGI.escape(scope)}" if scope
|
||||
q
|
||||
end
|
||||
|
||||
def expires_in
|
||||
expires_at.to_i - Time.now.to_i
|
||||
end
|
||||
end
|
|
@ -1,72 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# type :string(20)
|
||||
# client_application_id :integer
|
||||
# token :string(50)
|
||||
# secret :string(50)
|
||||
# authorized_at :datetime
|
||||
# invalidated_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# callback_url :string
|
||||
# verifier :string(20)
|
||||
# scope :string
|
||||
# valid_to :datetime
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_tokens_on_token (token) UNIQUE
|
||||
# index_oauth_tokens_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# oauth_tokens_client_application_id_fkey (client_application_id => client_applications.id)
|
||||
# oauth_tokens_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class Oauth2Verifier < OauthToken
|
||||
validates :user, :presence => true, :associated => true
|
||||
|
||||
attr_accessor :state
|
||||
|
||||
def exchange!(_params = {})
|
||||
OauthToken.transaction do
|
||||
token = Oauth2Token.create! :user => user, :client_application => client_application, :scope => scope
|
||||
invalidate!
|
||||
token
|
||||
end
|
||||
end
|
||||
|
||||
def code
|
||||
token
|
||||
end
|
||||
|
||||
def redirect_url
|
||||
callback_url
|
||||
end
|
||||
|
||||
def to_query
|
||||
q = "code=#{token}"
|
||||
q << "&state=#{CGI.escape(state)}" if @state
|
||||
q
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def generate_keys
|
||||
self.token = OAuth::Helper.generate_key(20)[0, 20]
|
||||
self.expires_at = 10.minutes.from_now
|
||||
self.authorized_at = Time.now.utc
|
||||
end
|
||||
end
|
|
@ -1,31 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_nonces
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# nonce :string
|
||||
# timestamp :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_nonces_on_nonce_and_timestamp (nonce,timestamp) UNIQUE
|
||||
#
|
||||
|
||||
# Simple store of nonces. The OAuth Spec requires that any given pair of nonce and timestamps are unique.
|
||||
# Thus you can use the same nonce with a different timestamp and viceversa.
|
||||
class OauthNonce < ApplicationRecord
|
||||
validates :timestamp, :presence => true
|
||||
validates :nonce, :presence => true, :uniqueness => { :scope => :timestamp }
|
||||
|
||||
# Remembers a nonce and it's associated timestamp. It returns false if it has already been used
|
||||
def self.remember(nonce, timestamp)
|
||||
return false if Time.now.to_i - timestamp.to_i > 86400
|
||||
|
||||
oauth_nonce = OauthNonce.create(:nonce => nonce, :timestamp => timestamp.to_i)
|
||||
return false if oauth_nonce.new_record?
|
||||
|
||||
oauth_nonce
|
||||
end
|
||||
end
|
|
@ -1,72 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# type :string(20)
|
||||
# client_application_id :integer
|
||||
# token :string(50)
|
||||
# secret :string(50)
|
||||
# authorized_at :datetime
|
||||
# invalidated_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# callback_url :string
|
||||
# verifier :string(20)
|
||||
# scope :string
|
||||
# valid_to :datetime
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_tokens_on_token (token) UNIQUE
|
||||
# index_oauth_tokens_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# oauth_tokens_client_application_id_fkey (client_application_id => client_applications.id)
|
||||
# oauth_tokens_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class OauthToken < ApplicationRecord
|
||||
belongs_to :client_application, :optional => true
|
||||
belongs_to :user, :optional => true
|
||||
|
||||
scope :authorized, -> { where("authorized_at IS NOT NULL and invalidated_at IS NULL") }
|
||||
|
||||
validates :token, :presence => true, :uniqueness => true
|
||||
validates :user, :associated => true
|
||||
validates :client_application, :presence => true
|
||||
|
||||
before_validation :generate_keys, :on => :create
|
||||
|
||||
def invalidated?
|
||||
invalidated_at != nil
|
||||
end
|
||||
|
||||
def invalidate!
|
||||
update(:invalidated_at => Time.now.utc)
|
||||
end
|
||||
|
||||
def authorized?
|
||||
!authorized_at.nil? && !invalidated?
|
||||
end
|
||||
|
||||
def to_query
|
||||
"oauth_token=#{token}&oauth_token_secret=#{secret}"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def generate_keys
|
||||
self.token = OAuth::Helper.generate_key(40)[0, 40]
|
||||
self.secret = OAuth::Helper.generate_key(40)[0, 40]
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: oauth_tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# type :string(20)
|
||||
# client_application_id :integer
|
||||
# token :string(50)
|
||||
# secret :string(50)
|
||||
# authorized_at :datetime
|
||||
# invalidated_at :datetime
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# allow_read_prefs :boolean default(FALSE), not null
|
||||
# allow_write_prefs :boolean default(FALSE), not null
|
||||
# allow_write_diary :boolean default(FALSE), not null
|
||||
# allow_write_api :boolean default(FALSE), not null
|
||||
# allow_read_gpx :boolean default(FALSE), not null
|
||||
# allow_write_gpx :boolean default(FALSE), not null
|
||||
# callback_url :string
|
||||
# verifier :string(20)
|
||||
# scope :string
|
||||
# valid_to :datetime
|
||||
# allow_write_notes :boolean default(FALSE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_oauth_tokens_on_token (token) UNIQUE
|
||||
# index_oauth_tokens_on_user_id (user_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# oauth_tokens_client_application_id_fkey (client_application_id => client_applications.id)
|
||||
# oauth_tokens_user_id_fkey (user_id => users.id)
|
||||
#
|
||||
|
||||
class RequestToken < OauthToken
|
||||
attr_accessor :provided_oauth_verifier
|
||||
|
||||
def authorize!(user)
|
||||
return false if authorized?
|
||||
|
||||
self.user = user
|
||||
self.authorized_at = Time.now.utc
|
||||
self.verifier = OAuth::Helper.generate_key(20)[0, 20] unless oauth10?
|
||||
save
|
||||
end
|
||||
|
||||
def exchange!
|
||||
return false unless authorized?
|
||||
return false unless oauth10? || verifier == provided_oauth_verifier
|
||||
|
||||
RequestToken.transaction do
|
||||
params = { :user => user, :client_application => client_application }
|
||||
# copy the permissions from the authorised request token to the access token
|
||||
client_application.permissions.each do |p|
|
||||
params[p] = self[p]
|
||||
end
|
||||
|
||||
access_token = AccessToken.create(params)
|
||||
invalidate!
|
||||
access_token
|
||||
end
|
||||
end
|
||||
|
||||
def to_query
|
||||
if oauth10?
|
||||
super
|
||||
else
|
||||
"#{super}&oauth_callback_confirmed=true"
|
||||
end
|
||||
end
|
||||
|
||||
def oob?
|
||||
callback_url.nil? || callback_url.casecmp?("oob")
|
||||
end
|
||||
|
||||
def oauth10?
|
||||
Settings.key?(:oauth_10_support) && Settings.oauth_10_support && callback_url.blank?
|
||||
end
|
||||
end
|
|
@ -66,9 +66,6 @@ class User < ApplicationRecord
|
|||
has_many :note_comments, :foreign_key => :author_id, :inverse_of => :author
|
||||
has_many :notes, :through => :note_comments
|
||||
|
||||
has_many :client_applications
|
||||
has_many :oauth_tokens, -> { order(:authorized_at => :desc).preload(:client_application) }, :class_name => "OauthToken", :inverse_of => :user
|
||||
|
||||
has_many :oauth2_applications, :class_name => Doorkeeper.config.application_model.name, :as => :owner
|
||||
has_many :access_grants, :class_name => Doorkeeper.config.access_grant_model.name, :foreign_key => :resource_owner_id
|
||||
has_many :access_tokens, :class_name => Doorkeeper.config.access_token_model.name, :foreign_key => :resource_owner_id
|
||||
|
@ -332,7 +329,6 @@ class User < ApplicationRecord
|
|||
##
|
||||
# revoke any authentication tokens
|
||||
def revoke_authentication_tokens
|
||||
oauth_tokens.authorized.each(&:invalidate!)
|
||||
access_tokens.not_expired.each(&:revoke)
|
||||
end
|
||||
|
||||
|
@ -377,12 +373,6 @@ class User < ApplicationRecord
|
|||
suspend! if may_suspend? && spam_score > Settings.spam_threshold
|
||||
end
|
||||
|
||||
##
|
||||
# return an oauth 1 access token for a specified application
|
||||
def access_token(application_key)
|
||||
ClientApplication.find_by(:key => application_key).access_token_for_user(self)
|
||||
end
|
||||
|
||||
##
|
||||
# return an oauth 2 access token for a specified application
|
||||
def oauth_token(application_id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue