Module: Clavis::Controllers::Concerns::Authentication

Extended by:
ActiveSupport::Concern
Included in:
AuthController
Defined in:
lib/clavis/controllers/concerns/authentication.rb

Instance Method Summary collapse

Instance Method Details

#oauth_authorizeObject



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/clavis/controllers/concerns/authentication.rb', line 11

def oauth_authorize
  provider_name = params[:provider]

  # Check if provider is specified
  if provider_name.blank?
    error_message = "No provider specified for OAuth authentication"
    Clavis::Logging.log_error(error_message)

    # Return a meaningful error to the user
    flash[:alert] = "Authentication provider not specified. Please try again or contact support."
    redirect_to main_app.respond_to?(:root_path) ? main_app.root_path : "/"
    return
  end

  begin
    # Explicitly validate provider - this will raise Clavis::ProviderNotConfigured if not configured
    Clavis.configuration.validate_provider!(provider_name)

    # Initialize the provider - if it fails, let the exception bubble up
    provider = Clavis.provider(provider_name)

    # Validate and store redirect URI if provided
    if params[:redirect_uri].present?
      Clavis::Security::SessionManager.store_redirect_uri(session, params[:redirect_uri])
    end

    # Generate and store state and nonce in session
    state = Clavis::Security::SessionManager.generate_and_store_state(session)
    nonce = Clavis::Security::SessionManager.generate_and_store_nonce(session)

    # Log parameters safely
    Clavis::Security::ParameterFilter.log_parameters(
      { provider: provider_name, scope: params[:scope] },
      level: :info,
      message: "Starting OAuth flow"
    )

    # Validate inputs
    scope = params[:scope] || Clavis.configuration.default_scopes
    Clavis::Security::InputValidator.sanitize(scope)

    # Generate the authorization URL and redirect
    auth_url = provider.authorize_url(
      state: state,
      nonce: nonce,
      scope: scope
    )

    redirect_to auth_url, allow_other_host: true
  rescue StandardError => e
    # Only rescue non-configuration errors
    raise if e.is_a?(Clavis::ProviderNotConfigured) || e.is_a?(Clavis::ConfigurationError)

    # Re-raise configuration errors to make them visible

    Clavis::Logging.log_error("OAuth flow error: #{e.class.name} - #{e.message}")
    Clavis::Logging.log_error(e.backtrace.join("\n"))

    flash[:alert] = "An error occurred while setting up authentication. Please try again or contact support."
    redirect_to main_app.respond_to?(:root_path) ? main_app.root_path : "/"
  end
end

#oauth_callbackObject



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/clavis/controllers/concerns/authentication.rb', line 74

def oauth_callback
  provider_name = params[:provider].to_sym
  Clavis::Logging.debug("oauth_callback - Starting for provider: #{provider_name}")

  # Debug log of all params
  oauth_params = request.env["action_dispatch.request.parameters"] || params.to_unsafe_h

  # Check if the OAuth provider returned an error
  return handle_oauth_error(oauth_params["error"]) if oauth_params["error"]

  # Verify state to prevent CSRF
  validate_state(oauth_params["state"])

  # Validate the code parameter
  validate_code(oauth_params["code"])

  # Create provider instance
  provider = Clavis.provider(provider_name)
  Clavis::Logging.debug("oauth_callback - Provider created: #{provider.class.name}")

  # Debug logging for token verification status
  log_token_verification_status(provider)

  # Process the OAuth callback
  auth_hash = process_provider_callback(provider, oauth_params)

  # Find or create user if configured
  user = find_or_create_user(auth_hash)

  # Security measures and session management
  handle_session_security(auth_hash)

  # Process ID token claims if OpenID Connect provider
  process_claims_if_needed(auth_hash)

  # Yield to a block if given - for custom logic
  yield(auth_hash, user) if block_given?

  Clavis::Logging.debug("oauth_callback - Completed successfully")
  auth_hash
rescue StandardError => e
  Clavis::Logging.debug("oauth_callback - Error: #{e.class.name}: #{e.message}")
  Clavis::Logging.debug("oauth_callback - Backtrace: #{e.backtrace.join("\n")}")
  handle_auth_error(e)
end