app/models/setup/oauth2_authorization.rb
module Setup
class Oauth2Authorization < Setup::BaseOauthAuthorization
include CenitScoped
build_in_data_type.referenced_by(:namespace, :name)
has_and_belongs_to_many :scopes, class_name: Setup::Oauth2Scope.to_s, inverse_of: nil
field :token_type, type: String
field :refresh_token, type: String
field :id_token, type: String
auth_template_parameters access_token: ->(oauth2_auth) { oauth2_auth.fresh_access_token }
def check
if super
errors.add(:client, 'provider is not OAuth 2.0 compatible') unless provider.is_a?(Setup::Oauth2Provider)
scopes.each do |scope|
next if scope.provider == provider
errors.add(:scopes, "contains not compatible scope #{scope.name} of #{scope.provider.custom_title}")
end
end
errors.blank?
end
def cancel
self.id_token = nil
super
end
def ready_to_save?
client.present?
end
def build_auth_header(template_parameters)
((token_type.to_s.capitalize || 'OAuth').to_s + ' ' + fresh_access_token.to_s).strip #TODO For Facebook that do not use token type
end
def callback_key
:redirect_uri
end
def create_http_client(options = {})
http_client = HttpClient.new(client.get_identifier, client.get_secret, options)
if (http_proxy = Cenit.http_proxy)
http_client.connection.proxy(http_proxy)
end
http_client
end
def authorize_url(params)
if (cenit_token = params.delete(:cenit_token)) && !params.has_key?(:state)
params[:state] = cenit_token.token
end
create_http_client(authorize_url: authorization_endpoint).auth_code.authorize_url(authorize_params(params))
end
def authorize_params(params, template_parameters = {})
scope_sep = provider.scope_separator.blank? ? ' ' : provider.scope_separator
params[:scope] ||= conformed_scopes(template_parameters).values.to_a.join(scope_sep)
super(params, template_parameters)
end
def request_token(params)
http_client = create_http_client(token_url: token_endpoint, token_method: token_method.to_s.downcase.to_sym)
token = http_client.get_token_with(:auth_code, params[:code]) do |parameters, headers|
parameters.merge!(token_params(parameters, params)) if parameters
headers.merge!(token_headers(headers, params)) if headers
end
self.token_type = token.params['token_type']
self.authorized_at =
if (time = token.params['created_at'])
time.is_a?(String) ? Time.parse(time) : Time.at(time.to_i)
else
Time.now
end
self.access_token = token.token
self.token_span = token.expires_in || token.params['token_span']
self.refresh_token = token.refresh_token if token.refresh_token
self.id_token = token.params['id_token']
end
def accept_callback?(params)
params[:code].present?
end
class HttpClient < OAuth2::Client
def thread_id(suffix)
"#{self.class}##{object_id}:#{suffix}"
end
def get_token_with(*args, &block)
if block
Thread.current[thread_id(:get_token_proc)] = block
end
strategy = args.shift
token = send(strategy).get_token(*args)
Thread.current[thread_id(:get_token_proc)] = nil
token
end
def get_token(params, access_token_opts = {}, access_token_class = OAuth2::AccessToken)
if (proc = Thread.current[thread_id(:get_token_proc)])
proc.call(params, headers = params[:headers])
params[:headers] = headers if headers
end
super
end
end
end
end