require 'active_support/concern' require 'oauth2' module ShopliftClient extend ActiveSupport::Concern included do attr_reader :authentication attr_reader :api_key attr_reader :current_user attr_reader :current_company attr_reader :do_hide_search_for_this_action helper_method :company_logo_path_defined end class_methods do attr_reader :search_path attr_reader :required_scopes attr_reader :do_hide_search_for_this_controller def set_search_path(value) @search_path = value return if @search_path == :current_path @search_path = "/#{@search_path}" unless @search_path[0] == '/' @search_path = "#{@search_path}/" unless @search_path[-1] == '/' end def hide_search_for_this_controller @do_hide_search_for_this_controller = true end def require_scopes(scopes) @required_scopes ||= [] scopes = [scopes] unless scopes.is_a? Array @required_scopes.concat scopes.map(&:to_s) @required_scopes.uniq! end end def hide_search_for_this_action @do_hide_search_for_this_action = true end def session_cookie session["authlift_session_id"] end def session_cookie=(new_value) session["authlift_session_id"] = new_value end def local_authlift_redirect_uri if respond_to? :app_authlift_redirect_uri app_authlift_redirect_uri else Rails.configuration.settings['authlift_redirect_uri'] end end def redirect_unauthorized return if performed? session.clear session[:previous_url] = request.fullpath redirect_to client.auth_code.authorize_url( redirect_uri: local_authlift_redirect_uri, scope: scope) end def scope [Rails.configuration.settings['authlift_default_scope'], 'public'].compact.join ' ' end def find_company_by_code(code) begin @current_company ||= Company.find_or_create_by! code: code rescue ActiveRecord::StatementInvalid if $!.cause.is_a? PG::UndefinedTable fail <<-ERROR.strip_heredoc You have not defined a company, and that is compulsory even if you are not planning to add any additional fields. You do not need to seed it, so following is enough forever: rails g model company code:string; rake db:migrate ERROR end end end def authenticate_user if session_cookie.present? @token = OAuth2::AccessToken.new client, session_cookie, scope: scope begin x = srv.get '/api/users/profile' @current_user = JSON.parse x.response.body user_scopes = JSON.parse @current_user['scopes'] unless user_scopes.include? 'admin' (self.class.required_scopes || []).each do |required_scope| unless user_scopes.include? required_scope render(file: 'shopapp/403.html', status: 403, layout: false, locals: { missing_scope: required_scope }) return false end end end find_company_by_code current_user['company']['code'] rescue OAuth2::Error return false end else return false end true end def authenticate_user! redirect_unauthorized unless authenticate_user end def authenticate_user_or_api! unless authenticate_company!(true) redirect_unauthorized end end def authenticate_company!(soft = false) return true if authenticate_user @api_key = if params['key'].present? params['key'].match(/[0-9a-f]+/).to_s elsif request.headers['AUTHORIZATION'].present? && !request.headers['AUTHORIZATION'].include?('Basic') request.headers['AUTHORIZATION'].gsub(/^Bearer ?/, '') else Rails.configuration.settings['authlift_default_app_key'] end if @api_key.blank? return false if soft fail ActionController::RoutingError, 'Authentication token missing' end response = srv.post 'auth/api_key', body: { api_key: api_key, requested_action: "#{self.controller_name}##{self.action_name}" } if response.blank? return false if soft fail ActionController::RoutingError, 'Request not authorized' end @authentication = JSON.parse response.body find_company_by_code authentication['company'] true end def current_user return @current_user if @current_user.present? @current_user end def current_company end def user_signed_in? !current_user.nil? end # To create/update a model, params must be of form { model_name: { attr1: value1, attr2: value2 } } # and attr1, attr2 must be in the list of allowed params the Rails way. def post(url, params) puts 'co_cli: post' puts "url: #{url}" puts "params: #{params}" response = srv.request(:post, url, body: params) JSON.parse(response.body) rescue OAuth2::Error raise "Server fault, could not perform post to #{srv.client.site}#{url}" rescue raise "Unknown error, could not perform post to #{srv.client.site}#{url}" end def get(url, params = {}) puts 'co_cli: get' puts "url: #{url}" puts "params: #{params}" response = srv.request(:get, url, body: params) JSON.parse(response.body) rescue OAuth2::Error raise "Server fault, could not perform post to #{srv.client.site}#{url}" rescue raise "Unknown error, could not perform post to #{srv.client.site}#{url}" end def srv @token ||= client.client_credentials.get_token scope: scope end def client @oauth ||= OAuth2::Client.new Rails.configuration.settings['authlift_app_id'], Rails.configuration.settings['authlift_app_secret'], site: Rails.configuration.settings['authlift_url'] end def company_logo_path_defined if defined? self.company_logo_path company_logo_path else "https://media.shoplift.fi/company_logos/#{@current_company.code}_company_logo_24.png" end end end