Skip to content

Commit

Permalink
Switch authentication to new rails 8.0 base
Browse files Browse the repository at this point in the history
  • Loading branch information
renatolond committed Nov 8, 2024
1 parent 498c090 commit 112f044
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 27 deletions.
10 changes: 3 additions & 7 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
# frozen_string_literal: true

class ApplicationController < ActionController::Base
include Authentication
before_action :basic_profile_info

# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern

protected

# @return [String,nil] The value of the authorization cookie
def authorization_header
cookies["Authorization"]
end

# Gets base information about a profile, things that are needed to show the profile info a of a logged-in user
# @return [BasicProfileInfo] if the user is logged in
# @return [nil] if the user is not logged in
def basic_profile_info
@basic_profile_info ||= retro_meet_client.basic_profile_info
rescue RetroMeetClient::UnauthorizedError
flash.now[:warn] = t("forced_log_out")
cookies.delete("Authorization")
terminate_session
redirect_to :root
end

def retro_meet_client = @retro_meet_client ||= RetroMeetClient.new(authorization_header)
def retro_meet_client = @retro_meet_client ||= RetroMeetClient.new(Current.session)
end
71 changes: 71 additions & 0 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

# This module can be included in controllers to enable authentication and related methods.
# It will automatically require authentication for all methods on that controller and any children controllers
module Authentication
extend ActiveSupport::Concern

included do
before_action :require_authentication
helper_method :authenticated?
end

class_methods do
# Method that allows some method in a controller to be unauthenticated. Should really only be used for root and sign_in/register actions
def allow_unauthenticated_access(**options)
skip_before_action :require_authentication, **options
end
end

private

# Check if there's a current session
def authenticated?
resume_session
end

# Makes sure that if there's no session, it will require auth
def require_authentication
resume_session || request_authentication
end

# Sets the current session from the cookie
def resume_session
Current.session ||= find_session_by_cookie
end

# (renatolond, 2024-11-08) should it be returning something more than the authorization cookie?
#
# @return [String]
def find_session_by_cookie
cookies.signed[:authorization]
end

# Sets the return url and redirects to login page
# @return [void]
def request_authentication
session[:return_to_after_authenticating] = request.url
redirect_to new_session_path
end

# Will either return the url the user was at before, or the root
#
# @return [String] The url to go after the login
def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
end

# Sets the cookie for the new session
# @return [void]
def start_new_session_for(authorization_token)
# TODO: check expiration time
cookies.signed[:authorization] = { value: authorization_token, httponly: true, same_site: :strict }
end

# Logs out from retro meet core and removes the session cookie
# @return [void]
def terminate_session
retro_meet_client.sign_out
cookies.delete(:authorization)
end
end
28 changes: 16 additions & 12 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

class SessionsController < ApplicationController
layout "no_columns"
allow_unauthenticated_access only: %i[new create new_account create_account]
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }

def new
redirect_to :root unless basic_profile_info.nil?
redirect_to :root if Current.session
end

def create
authorization_token = RetroMeetClient.login(login: params.dig(:sessions, :email),
password: params.dig(:sessions, :password))

cookies[:Authorization] = authorization_token
redirect_to :root
authorization_token = RetroMeetClient.login(login: params[:email],
password: params[:password])
# user_agent: request.user_agent,
# ip_address: request.remote_ip)
start_new_session_for authorization_token
redirect_to after_authentication_url
rescue RetroMeetClient::BadPasswordError
flash.now[:error] = t(".bad_password")
render "new", status: :unauthorized
Expand All @@ -21,15 +24,17 @@ def create
render "new", status: :unauthorized
end

def new_account; end
def new_account
redirect_to :root if Current.session
end

def create_account
@email = params[:email]

if params[:password] == params[:password_confirmation]
authorization_token = RetroMeetClient.create_account(login: params[:email], password: params[:password])
cookies[:Authorization] = authorization_token
redirect_to :root
start_new_session_for authorization_token
redirect_to after_authentication_url
else
flash.now[:error] = t(".passwords_do_not_match")
render "new_account", status: :bad_request
Expand All @@ -40,8 +45,7 @@ def create_account
end

def destroy
retro_meet_client.sign_out
cookies.delete(:Authorization)
redirect_to :root
terminate_session
redirect_to new_session_path
end
end
6 changes: 6 additions & 0 deletions app/models/current.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

# This class keeps the current session that's used for authentication
class Current < ActiveSupport::CurrentAttributes
attribute :session
end
12 changes: 4 additions & 8 deletions app/views/sessions/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
%h3.title.has-text-grey= t('.sign_in')
%p.subtitle.has-text-grey= t('.login_to_proceed')
.box
= form_for(:sessions, url: session_path()) do |f|
= form_with url: session_path do |form|
.field
.control
= f.email_field :email, autofocus: true, autocomplete: 'email', placeholder: 'email@example.com', class: 'input is-large'
= form.email_field :email, autofocus: true, autocomplete: 'email', placeholder: 'email@example.com', class: 'input is-large'
.field
.control
= f.password_field :password, autocomplete: "current-password", placeholder: 'password', class: 'input is-large'
.field
= f.label :remember_me, class: 'checkbox' do
= f.check_box :remember_me
= t(".remember_me")
= f.submit t(".sign_in"), class: 'button is-block is-info is-large is-fullwidth'
= form.password_field :password, autocomplete: "current-password", placeholder: 'password', class: 'input is-large'
= form.submit t(".sign_in"), class: 'button is-block is-info is-large is-fullwidth'
= render "sessions/shared/links"
1 change: 1 addition & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Application < Rails::Application
# Common ones are `templates`, `generators`, or `middleware`, for example.
config.autoload_lib(ignore: %w[assets tasks])

config.active_support.isolation_level = :fiber
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
Expand Down

0 comments on commit 112f044

Please sign in to comment.