Module: Verikloak::BFF::ForwardedToken
- Defined in:
- lib/verikloak/bff/forwarded_token.rb
Overview
Helpers to extract and normalize forwarded/access token headers.
Constant Summary collapse
- FORWARDED_HEADER =
Verikloak::HeaderSources::DEFAULT_FORWARDED_HEADER
- AUTH_HEADER =
Verikloak::HeaderSources::AUTHORIZATION_HEADER
Class Method Summary collapse
-
.ensure_bearer(token) ⇒ String
Normalize to a proper 'Bearer
' header value. -
.extract(env, forwarded_header_name = FORWARDED_HEADER, auth_header_name = AUTH_HEADER) ⇒ Array(String, String)
Extract normalized tokens from the Rack env.
-
.normalize_auth(raw) ⇒ String?
Only accept Bearer scheme for Authorization header.
-
.normalize_forwarded(raw) ⇒ String?
Accept either bare token or Bearer for forwarded header.
-
.sanitize(token) ⇒ String
Remove CRLF and other control characters to prevent header injection.
-
.set_authorization!(env, token) ⇒ void
Set Authorization header to a normalized Bearer value.
-
.strip_suspicious!(env, headers = nil) ⇒ void
Remove potentially forged X-Auth-Request-* headers before passing downstream when not emitted by a trusted proxy.
Class Method Details
.ensure_bearer(token) ⇒ String
Normalize to a proper 'Bearer
- Detects scheme case-insensitively
- Inserts a missing space (e.g., 'BearerXYZ' => 'Bearer XYZ')
- Collapses multiple spaces/tabs after the scheme to a single space
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 68 def ensure_bearer(token) s = sanitize(token) # Case-insensitive 'Bearer' with spaces/tabs after if s =~ /\ABearer[ \t]+/i rest = s.sub(/\ABearer[ \t]+/i, '') return "Bearer #{rest}" end # Case-insensitive 'Bearer' with no separator (e.g., 'BearerXYZ') if s =~ /\ABearer(?![ \t])/i rest = s[6..] || '' return "Bearer #{rest}" end # No scheme present; add it "Bearer #{s}" end |
.extract(env, forwarded_header_name = FORWARDED_HEADER, auth_header_name = AUTH_HEADER) ⇒ Array(String, String)
Extract normalized tokens from the Rack env.
25 26 27 28 29 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 25 def extract(env, forwarded_header_name = FORWARDED_HEADER, auth_header_name = AUTH_HEADER) fwd_raw = env[forwarded_header_name] auth_raw = env[auth_header_name] [normalize_auth(auth_raw), normalize_forwarded(fwd_raw)] end |
.normalize_auth(raw) ⇒ String?
Only accept Bearer scheme for Authorization header. A scheme without a token (e.g. "Bearer" or "Bearer ") is treated as absent so that an empty Authorization header never shadows a valid forwarded token.
The pattern is anchored with \A/\z (not ^/$) so a multi-line value
cannot smuggle a "Bearer
42 43 44 45 46 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 42 def normalize_auth(raw) return nil unless raw raw.to_s.strip[/\ABearer[ \t]*(.+)\z/i, 1] end |
.normalize_forwarded(raw) ⇒ String?
Accept either bare token or Bearer for forwarded header.
52 53 54 55 56 57 58 59 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 52 def normalize_forwarded(raw) return nil unless raw token = raw.to_s.strip token = token.sub(/^Bearer\s+/i, '') if token =~ /^Bearer\s+/i token.empty? ? nil : token end |
.sanitize(token) ⇒ String
Remove CRLF and other control characters to prevent header injection.
101 102 103 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 101 def sanitize(token) token.to_s.gsub(/[[:cntrl:]]/, '').strip end |
.set_authorization!(env, token) ⇒ void
This method returns an undefined value.
Set Authorization header to a normalized Bearer value. Always overwrites the existing Authorization header to ensure the chosen token and Authorization are synchronized.
93 94 95 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 93 def (env, token) env[AUTH_HEADER] = ensure_bearer(token) end |
.strip_suspicious!(env, headers = nil) ⇒ void
This method returns an undefined value.
Remove potentially forged X-Auth-Request-* headers before passing downstream when not emitted by a trusted proxy.
111 112 113 114 |
# File 'lib/verikloak/bff/forwarded_token.rb', line 111 def strip_suspicious!(env, headers = nil) headers = Constants::DEFAULT_AUTH_REQUEST_HEADERS unless headers.is_a?(Hash) headers.each_value { |h| env.delete(h) } end |