Class: OmniauthOpenidFederation::FederationController
- Inherits:
-
ApplicationController
- Object
- ApplicationController
- OmniauthOpenidFederation::FederationController
- Defined in:
- app/controllers/omniauth_openid_federation/federation_controller.rb
Instance Method Summary collapse
-
#fetch ⇒ Object
Serve fetch endpoint (for Subordinate Statements).
-
#jwks ⇒ Object
Serve standard JWKS.
-
#show ⇒ Object
Serve the entity statement.
-
#signed_jwks ⇒ Object
Serve signed JWKS.
Instance Method Details
#fetch ⇒ Object
Serve fetch endpoint (for Subordinate Statements)
GET /.well-known/openid-federation/fetch?sub=<subject_entity_id>
Returns a Subordinate Statement JWT for the specified subject entity. Per OpenID Federation 1.0 Section 6.1.
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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'app/controllers/omniauth_openid_federation/federation_controller.rb', line 44 def fetch # Extract 'sub' query parameter (required per spec) subject_entity_id = params[:sub] unless subject_entity_id render json: {error: "invalid_request", error_description: "Missing required parameter: sub"}, status: :bad_request return end # Security: Validate entity identifier per OpenID Federation 1.0 spec # Entity identifiers must be valid HTTP/HTTPS URIs begin # Validate and get trimmed value subject_entity_id = OmniauthOpenidFederation::Validators.validate_entity_identifier!(subject_entity_id, max_length: 2048) rescue SecurityError => e render json: {error: "invalid_request", error_description: "Invalid subject entity ID: #{e.message}"}, status: :bad_request return rescue => e render json: {error: "invalid_request", error_description: "Subject entity ID validation failed: #{e.message}"}, status: :bad_request return end # Validate that subject is not the issuer (invalid request per spec) config = OmniauthOpenidFederation::FederationEndpoint.configuration if subject_entity_id == config.issuer render json: {error: "invalid_request", error_description: "Subject cannot be the issuer"}, status: :bad_request return end # Get Subordinate Statement subordinate_statement = OmniauthOpenidFederation::FederationEndpoint.get_subordinate_statement(subject_entity_id) unless subordinate_statement render json: {error: "not_found", error_description: "Subordinate Statement not found for subject: #{subject_entity_id}"}, status: :not_found return end # Set appropriate headers per spec (application/entity-statement+jwt) response.headers["Content-Type"] = "application/entity-statement+jwt" response.headers["Cache-Control"] = "public, max-age=3600" # Cache for 1 hour render plain: subordinate_statement rescue OmniauthOpenidFederation::ConfigurationError => e OmniauthOpenidFederation::Logger.error("[FederationController] Configuration error: #{e.message}") render json: {error: "Federation endpoint not configured"}, status: :service_unavailable rescue => e OmniauthOpenidFederation::Logger.error("[FederationController] Error fetching subordinate statement: #{e.class} - #{e.message}") render json: {error: "Internal server error"}, status: :internal_server_error end |
#jwks ⇒ Object
Serve standard JWKS
GET /.well-known/jwks.json
Returns the current JWKS in JSON format. Uses config.current_jwks or config.current_jwks_proc if configured, otherwise falls back to entity statement JWKS.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'app/controllers/omniauth_openid_federation/federation_controller.rb', line 101 def jwks config = OmniauthOpenidFederation::FederationEndpoint.configuration # Get current JWKS (may differ from entity statement JWKS) jwks_to_serve = OmniauthOpenidFederation::FederationEndpoint.current_jwks # Apply server-side caching if available cache_key = "federation:jwks:#{Digest::SHA256.hexdigest(jwks_to_serve.to_json)}" cache_ttl = config.jwks_cache_ttl || 3600 jwks_json = if OmniauthOpenidFederation::CacheAdapter.available? OmniauthOpenidFederation::CacheAdapter.fetch(cache_key, expires_in: cache_ttl) do jwks_to_serve.to_json end else jwks_to_serve.to_json end response.headers["Content-Type"] = "application/json" response.headers["Cache-Control"] = "public, max-age=3600" # Client-side cache for 1 hour render json: JSON.parse(jwks_json) rescue OmniauthOpenidFederation::ConfigurationError => e OmniauthOpenidFederation::Logger.error("[FederationController] Configuration error: #{e.message}") render json: {error: "Federation endpoint not configured"}, status: :service_unavailable rescue => e OmniauthOpenidFederation::Logger.error("[FederationController] Error serving JWKS: #{e.class} - #{e.message}") render json: {error: "Internal server error"}, status: :internal_server_error end |
#show ⇒ Object
Serve the entity statement
GET /.well-known/openid-federation
Returns the entity statement JWT as plain text with appropriate content type.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'app/controllers/omniauth_openid_federation/federation_controller.rb', line 21 def show entity_statement = OmniauthOpenidFederation::FederationEndpoint.generate_entity_statement # Set appropriate headers for entity statement # Per OpenID Federation 1.0 Section 9.2, MUST use application/entity-statement+jwt response.headers["Content-Type"] = "application/entity-statement+jwt" response.headers["Cache-Control"] = "public, max-age=3600" # Cache for 1 hour render plain: entity_statement rescue OmniauthOpenidFederation::ConfigurationError => e OmniauthOpenidFederation::Logger.error("[FederationController] Configuration error: #{e.message}") render plain: "Federation endpoint not configured", status: :service_unavailable rescue => e OmniauthOpenidFederation::Logger.error("[FederationController] Error generating entity statement: #{e.class} - #{e.message}") render plain: "Internal server error", status: :internal_server_error end |
#signed_jwks ⇒ Object
Serve signed JWKS
GET /.well-known/signed-jwks.json
Returns the current JWKS wrapped in a JWT, signed with entity statement key. Note: Despite the .json extension (per OpenID Federation spec), this endpoint returns application/jwt (a JWT), not plain JSON. The Content-Type header correctly indicates application/jwt. Uses config.signed_jwks_payload or config.signed_jwks_payload_proc if configured, otherwise falls back to entity statement JWKS.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'app/controllers/omniauth_openid_federation/federation_controller.rb', line 140 def signed_jwks config = OmniauthOpenidFederation::FederationEndpoint.configuration # Generate signed JWKS JWT signed_jwks_jwt = OmniauthOpenidFederation::FederationEndpoint.generate_signed_jwks # Apply server-side caching if available cache_key = "federation:signed_jwks:#{Digest::SHA256.hexdigest(signed_jwks_jwt)}" cache_ttl = config.jwks_cache_ttl || 3600 cached_jwt = if OmniauthOpenidFederation::CacheAdapter.available? OmniauthOpenidFederation::CacheAdapter.fetch(cache_key, expires_in: cache_ttl) do signed_jwks_jwt end else signed_jwks_jwt end response.headers["Content-Type"] = "application/jwt" response.headers["Cache-Control"] = "public, max-age=3600" # Client-side cache for 1 hour render plain: cached_jwt rescue OmniauthOpenidFederation::ConfigurationError => e OmniauthOpenidFederation::Logger.error("[FederationController] Configuration error: #{e.message}") render plain: "Federation endpoint not configured", status: :service_unavailable rescue OmniauthOpenidFederation::SignatureError => e OmniauthOpenidFederation::Logger.error("[FederationController] Signature error: #{e.message}") render plain: "Internal server error", status: :internal_server_error rescue => e OmniauthOpenidFederation::Logger.error("[FederationController] Error generating signed JWKS: #{e.class} - #{e.message}") render plain: "Internal server error", status: :internal_server_error end |