Skip to content

Commit

Permalink
Merge pull request #117 from internetee/encrypt-aith-info
Browse files Browse the repository at this point in the history
Encrypted auth info cache
  • Loading branch information
vohmar authored Jan 26, 2024
2 parents ae7c71e + 069b30b commit 1fac697
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 97 deletions.
101 changes: 8 additions & 93 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
class ApplicationController < ActionController::Base # rubocop:disable Metrics/ClassLength
class ApplicationController < ActionController::Base
include Pagy::Backend

helper_method :current_user, :logged_in?, :can?
before_action :set_locale

def current_user
@current_user ||= OpenStruct.new(auth_info) if auth_info
end

def can?(action, subject)
return false if current_user.abilities[:can].blank?
return false if current_user.abilities[:can][action].blank?

current_user.abilities[:can][action].keys.include? subject
end

def authorize!(action, subject)
return if can? action, subject

respond_to do |format|
format.html { redirect_to dashboard_url, alert: 'Authorization error' }
end
end

def logged_in?
current_user != nil
end

def sign_out
session[:uuid] = nil
Rails.cache.instance_variable_get(:@data)&.each_key do |key|
Rails.cache.delete(key) unless key.match?(/distribution_data|growth_rate_data/)
end
end

def sign_in(uuid)
session[:uuid] = uuid
cookies.delete(:request_ip)
end
include Authentication
include Authorization
include Localization

def reset_bulk_change_cache
@attrs&.slice!(:type, :form_steps)
Expand Down Expand Up @@ -75,19 +40,6 @@ def respond(msg, dialog: false)
end
end

def store_auth_info(token:, request_ip:, data:)
uuid = SecureRandom.uuid
Rails.cache.write(uuid, { username: data[:username],
registrar_name: data[:registrar_name],
role: data[:roles].first,
legaldoc_mandatory: data[:legaldoc_mandatory],
address_processing: data[:address_processing],
token: token,
request_ip: request_ip,
abilities: data[:abilities] }, expires_in: 18.hours)
uuid
end

private

def handle_successful_response(res)
Expand Down Expand Up @@ -129,48 +81,11 @@ def respond_turbo_stream(msg, dialog)
flash.now[:alert] = msg

turbo_stream_render = if dialog
turbo_stream.update_all('.dialog_flash', partial: 'common/dialog_flash')
else
turbo_stream.update('flash', partial: 'common/flash')
end
turbo_stream.update_all('.dialog_flash', partial: 'common/dialog_flash')
else
turbo_stream.update('flash', partial: 'common/flash')
end

render turbo_stream: turbo_stream_render
end

def auth_info
Rails.cache.fetch(session[:uuid])&.symbolize_keys
end

def default_url_options
{ locale: I18n.locale }
end

def set_locale
I18n.locale = extract_locale || I18n.default_locale
@pagy_locale = I18n.locale.to_s
end

def extract_locale
set_locale_cookie_if_present
locale = cookies[:locale]

return locale.to_sym if valid_locale?(locale)

log_invalid_locale(locale)
nil
end

def set_locale_cookie_if_present
cookies.permanent[:locale] = params[:locale] if params[:locale].present?
end

def valid_locale?(locale)
I18n.available_locales.map(&:to_s).include?(locale)
end

def log_invalid_locale(locale)
notice = "#{locale} #{t(:no_translation)}"
# flash.now[:notice] = notice
logger.error notice
end
end
67 changes: 67 additions & 0 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# app/controllers/concerns/authentication.rb
module Authentication
extend ActiveSupport::Concern

included do
helper_method :current_user, :logged_in?
end

def current_user
@current_user ||= OpenStruct.new(auth_info) if auth_info
end

def logged_in?
current_user != nil
end

def sign_out
session[:uuid] = nil
clear_cache
end

def sign_in(uuid)
session[:uuid] = uuid
cookies.delete(:request_ip)
end

def store_auth_info(token:, request_ip:, data:)
uuid = SecureRandom.uuid
data = construct_auth_info(token, request_ip, data)
encrypted_data = Encryptor.encrypt(data.to_json)
Rails.cache.write(uuid, encrypted_data, expires_in: 18.hours)

uuid
end

private

def auth_info
cached_data = Rails.cache.fetch(session[:uuid]) || ''
decrypted_data = Encryptor.decrypt(cached_data)
return unless decrypted_data

JSON.parse(decrypted_data).symbolize_keys
rescue JSON::ParserError => e
logger.info(e)
nil
end

def construct_auth_info(token, request_ip, data)
{
username: data[:username],
registrar_name: data[:registrar_name],
role: data[:roles].first,
legaldoc_mandatory: data[:legaldoc_mandatory],
address_processing: data[:address_processing],
token: token,
request_ip: request_ip,
abilities: data[:abilities]
}
end

def clear_cache
Rails.cache.instance_variable_get(:@data)&.each_key do |key|
Rails.cache.delete(key) unless key.match?(/distribution_data|growth_rate_data/)
end
end
end
24 changes: 24 additions & 0 deletions app/controllers/concerns/authorization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# app/controllers/concerns/authorization.rb
module Authorization
extend ActiveSupport::Concern

included do
helper_method :can?
end

def can?(action, subject)
abilities = current_user.abilities.with_indifferent_access
return false if abilities[:can].blank?
return false if abilities[:can][action].blank?

abilities[:can][action].keys.include? subject
end

def authorize!(action, subject)
return if can? action, subject

respond_to do |format|
format.html { redirect_to dashboard_url, alert: 'Authorization error' }
end
end
end
43 changes: 43 additions & 0 deletions app/controllers/concerns/localization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# app/controllers/concerns/localization.rb
module Localization
extend ActiveSupport::Concern

included do
before_action :switch_locale
end

private

def switch_locale
I18n.locale = extract_locale || I18n.default_locale
@pagy_locale = I18n.locale.to_s
end

def extract_locale
set_locale_cookie_if_present
locale = cookies[:locale]

return locale.to_sym if valid_locale?(locale)

log_invalid_locale(locale)
nil
end

def set_locale_cookie_if_present
cookies.permanent[:locale] = params[:locale] if params[:locale].present?
end

def valid_locale?(locale)
I18n.available_locales.map(&:to_s).include?(locale)
end

def log_invalid_locale(locale)
notice = "#{locale} #{t(:no_translation)}"
# flash.now[:notice] = notice
logger.error notice
end

def default_url_options
{ locale: I18n.locale }
end
end
24 changes: 24 additions & 0 deletions lib/encryptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# lib/encryptor.rb
class Encryptor
class << self
def encrypt(value)
encryptor.encrypt_and_sign(value)
end

def decrypt(value)
encryptor.decrypt_and_verify(value)
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
nil
end

private

def encryptor
@encryptor ||= begin
secret_key_base = Rails.application.secret_key_base
key = ActiveSupport::KeyGenerator.new(secret_key_base).generate_key('', 32)
ActiveSupport::MessageEncryptor.new(key)
end
end
end
end
5 changes: 3 additions & 2 deletions spec/controllers/auth/tara_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@

it 'does not receive callback if user already logged in' do
session[:uuid] = uuid
Rails.cache.write(uuid, auth_data_legal)
encrypted_data = Encryptor.encrypt(auth_data_legal.to_json)
Rails.cache.write(uuid, encrypted_data)
VCR.use_cassette("#{cassette_path}/#{option[:method]}", match_requests_on: %i[path method]) do
send(option[:http_method], option[:method], params: option[:params])
end
Expand All @@ -48,4 +49,4 @@

expect(response).to redirect_to(login_url)
end
end
end
6 changes: 4 additions & 2 deletions spec/support/base_controller_shared_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
options.each do |option|
it 'successfully checks for auth info in session' do
session[:uuid] = uuid
Rails.cache.write(uuid, auth_data_legal)
encrypted_data = Encryptor.encrypt(auth_data_legal.to_json)
Rails.cache.write(uuid, encrypted_data)
VCR.use_cassette("#{cassette_path}/#{option[:method]}", match_requests_on: %i[path method]) do
# p VCR.current_cassette.file
send(option[:http_method], option[:method],
Expand Down Expand Up @@ -47,7 +48,8 @@

it 'redirects to auth controller if failed auth' do
session[:uuid] = uuid
Rails.cache.write(uuid, auth_data_fail)
encrypted_data = Encryptor.encrypt(auth_data_fail.to_json)
Rails.cache.write(uuid, encrypted_data)
VCR.use_cassette("#{cassette_path}/#{option[:method]}-auth-fail", match_requests_on: %i[path method]) do
# p VCR.current_cassette.file
send(option[:http_method], option[:method], params: option[:params])
Expand Down

0 comments on commit 1fac697

Please sign in to comment.