Drop support for OAuth 1

This commit is contained in:
Tom Hughes 2024-07-24 19:12:14 +01:00 committed by Anton Khorev
parent cee9818dfc
commit 17bc0853a0
48 changed files with 52 additions and 2395 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)