Class: Hooks::Plugins::Auth::SharedSecret

Inherits:
Base
  • Object
show all
Defined in:
lib/hooks/plugins/auth/shared_secret.rb

Overview

Note:

This validator performs direct string comparison of the shared secret. While simpler than HMAC, it provides less security since the secret is transmitted directly in the request header.

Generic shared secret validator for webhooks

This validator provides simple shared secret authentication for webhook requests. It compares a secret value sent in a configurable HTTP header against the expected secret value. This is a common (though less secure than HMAC) authentication pattern used by various webhook providers.

Examples:

Basic configuration

auth:
  type: shared_secret
  secret_env_key: WEBHOOK_SECRET
  header: Authorization

Custom header configuration

auth:
  type: shared_secret
  secret_env_key: SOME_OTHER_WEBHOOK_SECRET
  header: X-API-Key

Constant Summary collapse

DEFAULT_CONFIG =

Default configuration values for shared secret validation

Returns:

  • (Hash<Symbol, String>)

    Default configuration settings

{
  header: "Authorization"
}.freeze

Constants inherited from Base

Base::MAX_HEADER_VALUE_LENGTH, Base::MAX_PAYLOAD_SIZE

Class Method Summary collapse

Methods inherited from Base

fetch_secret, find_header_value, timestamp_validator, valid_header_value?, valid_headers?, valid_payload_size?

Methods included from Core::ComponentAccess

#failbot, #log, #method_missing, #respond_to_missing?, #stats

Class Method Details

.valid?(payload:, headers:, config:) ⇒ Boolean

Note:

This method is designed to be safe and will never raise exceptions

Note:

Uses Rack::Utils.secure_compare to prevent timing attacks

Validate shared secret from webhook requests

Performs secure comparison of the shared secret value from the configured header against the expected secret. Uses secure comparison to prevent timing attacks.

Examples:

Basic validation

SharedSecret.valid?(
  payload: request_body,
  headers: request.headers,
  config: { auth: { header: 'Authorization' } }
)

Parameters:

  • payload (String)

    Raw request body (unused but required by interface)

  • headers (Hash<String, String>)

    HTTP headers from the request

  • config (Hash)

    Endpoint configuration containing validator settings

Options Hash (config:):

  • :auth (Hash)

    Validator-specific configuration

  • :header (String) — default: 'Authorization'

    Header containing the secret

Returns:

  • (Boolean)

    true if secret is valid, false otherwise

Raises:

  • (StandardError)

    Rescued internally, returns false on any error



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/hooks/plugins/auth/shared_secret.rb', line 59

def self.valid?(payload:, headers:, config:)
  secret = fetch_secret(config)

  validator_config = build_config(config)

  # Security: Check raw headers and payload BEFORE processing
  return false unless valid_headers?(headers)
  return false unless valid_payload_size?(payload)

  secret_header = validator_config[:header]

  # Find the secret header with case-insensitive matching
  provided_secret = find_header_value(headers, secret_header)

  if provided_secret.nil? || provided_secret.empty?
    log.warn("Auth::SharedSecret validation failed: Missing or empty secret header '#{secret_header}'")
    return false
  end

  # Validate secret format using shared validation
  unless valid_header_value?(provided_secret, "Secret")
    log.warn("Auth::SharedSecret validation failed: Invalid secret format")
    return false
  end

  # Use secure comparison to prevent timing attacks
  result = Rack::Utils.secure_compare(secret, provided_secret)
  if result
    log.debug("Auth::SharedSecret validation successful for header '#{secret_header}'")
  else
    log.warn("Auth::SharedSecret validation failed: Signature mismatch")
  end
  result
rescue StandardError => e
  log.error("Auth::SharedSecret validation failed: #{e.message}")
  false
end