Pass the redirect url through the forms
This commit is contained in:
@@ -1,15 +1,15 @@
|
|||||||
module Api
|
module Api
|
||||||
class ForwardAuthController < ApplicationController
|
class ForwardAuthController < ApplicationController
|
||||||
# ForwardAuth endpoints don't use sessions or CSRF
|
# ForwardAuth endpoints need session storage for return URL
|
||||||
allow_unauthenticated_access
|
allow_unauthenticated_access
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
|
skip_before_action :verify_request_origin
|
||||||
|
|
||||||
# GET /api/verify
|
# GET /api/verify
|
||||||
# This endpoint is called by reverse proxies (Traefik, Caddy, nginx)
|
# This endpoint is called by reverse proxies (Traefik, Caddy, nginx)
|
||||||
# to verify if a user is authenticated and authorized to access an application
|
# to verify if a user is authenticated and authorized to access a domain
|
||||||
def verify
|
def verify
|
||||||
# Get the application slug from query params or X-Forwarded-Host header
|
# Note: app_slug parameter is no longer used - we match domains directly with ForwardAuthRule
|
||||||
app_slug = params[:app] || extract_app_from_headers
|
|
||||||
|
|
||||||
# Get the session from cookie
|
# Get the session from cookie
|
||||||
session_id = extract_session_id
|
session_id = extract_session_id
|
||||||
@@ -40,24 +40,28 @@ module Api
|
|||||||
return render_unauthorized("User account is not active")
|
return render_unauthorized("User account is not active")
|
||||||
end
|
end
|
||||||
|
|
||||||
# If an application is specified, check authorization
|
# Check for forward auth rule authorization
|
||||||
if app_slug.present?
|
# Get the forwarded host for domain matching
|
||||||
application = Application.find_by(slug: app_slug, app_type: "trusted_header", active: true)
|
forwarded_host = request.headers["X-Forwarded-Host"] || request.headers["Host"]
|
||||||
|
|
||||||
unless application
|
if forwarded_host.present?
|
||||||
Rails.logger.warn "ForwardAuth: Application not found or not configured for trusted_header: #{app_slug}"
|
# Find matching forward auth rule for this domain
|
||||||
return render_forbidden("Application not found or not configured")
|
rule = ForwardAuthRule.active.find { |r| r.matches_domain?(forwarded_host) }
|
||||||
|
|
||||||
|
unless rule
|
||||||
|
Rails.logger.warn "ForwardAuth: No rule found for domain: #{forwarded_host}"
|
||||||
|
return render_forbidden("No authentication rule configured for this domain")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check if user is allowed to access this application
|
# Check if user is allowed by this rule
|
||||||
unless application.user_allowed?(user)
|
unless rule.user_allowed?(user)
|
||||||
Rails.logger.info "ForwardAuth: User #{user.email_address} denied access to #{app_slug}"
|
Rails.logger.info "ForwardAuth: User #{user.email_address} denied access to #{forwarded_host} by rule #{rule.domain_pattern}"
|
||||||
return render_forbidden("You do not have permission to access this application")
|
return render_forbidden("You do not have permission to access this domain")
|
||||||
end
|
end
|
||||||
|
|
||||||
Rails.logger.info "ForwardAuth: User #{user.email_address} granted access to #{app_slug}"
|
Rails.logger.info "ForwardAuth: User #{user.email_address} granted access to #{forwarded_host} by rule #{rule.domain_pattern} (policy: #{rule.policy_for_user(user)})"
|
||||||
else
|
else
|
||||||
Rails.logger.info "ForwardAuth: User #{user.email_address} authenticated (no app specified)"
|
Rails.logger.info "ForwardAuth: User #{user.email_address} authenticated (no domain specified)"
|
||||||
end
|
end
|
||||||
|
|
||||||
# User is authenticated and authorized
|
# User is authenticated and authorized
|
||||||
@@ -87,22 +91,8 @@ module Api
|
|||||||
end
|
end
|
||||||
|
|
||||||
def extract_app_from_headers
|
def extract_app_from_headers
|
||||||
# Try to extract application slug from forwarded headers
|
# This method is deprecated since we now use ForwardAuthRule domain matching
|
||||||
# This is useful when the proxy doesn't pass ?app= param
|
# Keeping it for backward compatibility but it's no longer used
|
||||||
|
|
||||||
# X-Forwarded-Host might contain the hostname
|
|
||||||
host = request.headers["X-Forwarded-Host"] || request.headers["Host"]
|
|
||||||
|
|
||||||
# Try to match hostname to application
|
|
||||||
# Format: app-slug.domain.com -> app-slug
|
|
||||||
if host.present?
|
|
||||||
# Extract subdomain as potential app slug
|
|
||||||
parts = host.split(".")
|
|
||||||
if parts.length >= 2
|
|
||||||
return parts.first if parts.first != "www"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ class SessionsController < ApplicationController
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Store the redirect URL from forward auth if present
|
||||||
|
if params[:rd].present?
|
||||||
|
session[:return_to_after_authenticating] = params[:rd]
|
||||||
|
end
|
||||||
|
|
||||||
# Check if user is active
|
# Check if user is active
|
||||||
unless user.active?
|
unless user.active?
|
||||||
redirect_to signin_path, alert: "Your account is not active. Please contact an administrator."
|
redirect_to signin_path, alert: "Your account is not active. Please contact an administrator."
|
||||||
@@ -26,7 +31,11 @@ class SessionsController < ApplicationController
|
|||||||
if user.totp_enabled?
|
if user.totp_enabled?
|
||||||
# Store user ID in session temporarily for TOTP verification
|
# Store user ID in session temporarily for TOTP verification
|
||||||
session[:pending_totp_user_id] = user.id
|
session[:pending_totp_user_id] = user.id
|
||||||
redirect_to totp_verification_path
|
# Preserve the redirect URL through TOTP verification
|
||||||
|
if params[:rd].present?
|
||||||
|
session[:totp_redirect_url] = params[:rd]
|
||||||
|
end
|
||||||
|
redirect_to totp_verification_path(rd: params[:rd])
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -57,6 +66,10 @@ class SessionsController < ApplicationController
|
|||||||
# Try TOTP verification first
|
# Try TOTP verification first
|
||||||
if user.verify_totp(code)
|
if user.verify_totp(code)
|
||||||
session.delete(:pending_totp_user_id)
|
session.delete(:pending_totp_user_id)
|
||||||
|
# Restore redirect URL if it was preserved
|
||||||
|
if session[:totp_redirect_url].present?
|
||||||
|
session[:return_to_after_authenticating] = session.delete(:totp_redirect_url)
|
||||||
|
end
|
||||||
start_new_session_for user
|
start_new_session_for user
|
||||||
redirect_to after_authentication_url, notice: "Signed in successfully."
|
redirect_to after_authentication_url, notice: "Signed in successfully."
|
||||||
return
|
return
|
||||||
@@ -65,6 +78,10 @@ class SessionsController < ApplicationController
|
|||||||
# Try backup code verification
|
# Try backup code verification
|
||||||
if user.verify_backup_code(code)
|
if user.verify_backup_code(code)
|
||||||
session.delete(:pending_totp_user_id)
|
session.delete(:pending_totp_user_id)
|
||||||
|
# Restore redirect URL if it was preserved
|
||||||
|
if session[:totp_redirect_url].present?
|
||||||
|
session[:return_to_after_authenticating] = session.delete(:totp_redirect_url)
|
||||||
|
end
|
||||||
start_new_session_for user
|
start_new_session_for user
|
||||||
redirect_to after_authentication_url, notice: "Signed in successfully using backup code."
|
redirect_to after_authentication_url, notice: "Signed in successfully using backup code."
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= form_with url: signin_path, class: "contents" do |form| %>
|
<%= form_with url: signin_path, class: "contents" do |form| %>
|
||||||
|
<%= hidden_field_tag :rd, params[:rd] if params[:rd].present? %>
|
||||||
<div class="my-5">
|
<div class="my-5">
|
||||||
<%= form.label :email_address, "Email Address", class: "block font-medium text-sm text-gray-700" %>
|
<%= form.label :email_address, "Email Address", class: "block font-medium text-sm text-gray-700" %>
|
||||||
<%= form.email_field :email_address,
|
<%= form.email_field :email_address,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= form_with url: totp_verification_path, method: :post, class: "space-y-6" do |form| %>
|
<%= form_with url: totp_verification_path, method: :post, class: "space-y-6" do |form| %>
|
||||||
|
<%= hidden_field_tag :rd, params[:rd] if params[:rd].present? %>
|
||||||
<div>
|
<div>
|
||||||
<%= label_tag :code, "Verification Code", class: "block text-sm font-medium text-gray-700" %>
|
<%= label_tag :code, "Verification Code", class: "block text-sm font-medium text-gray-700" %>
|
||||||
<%= text_field_tag :code,
|
<%= text_field_tag :code,
|
||||||
|
|||||||
Reference in New Issue
Block a user