mirror of
https://github.com/we-promise/sure.git
synced 2026-08-04 08:02:15 +00:00
* fix(oidc): honor http issuer scheme during OIDC discovery Self-hosted IdPs served over plain HTTP (no SSL) failed OIDC login with "Failed to open TCP connection to <issuer>:443 (Connection refused)". The openid_connect/swd gems hardcode discovery to HTTPS: SWD.url_builder defaults to URI::HTTPS, and OpenIDConnect::Discovery::Provider::Config::Resource drops the issuer's scheme, rebuilding the .well-known URL from host/port only. So an http:// issuer is upgraded to https:443 and never connects. (This is why the in-app "Test connection" passes -- it uses Faraday against the raw issuer URL and never goes through the gem.) Patch Config::Resource to remember the issuer's scheme and build the discovery endpoint with URI::HTTP or URI::HTTPS accordingly. Per-request, no global mutable state, so mixed http/https providers coexist. Only discovery needs patching: the endpoints it returns are absolute and rack-oauth2 preserves an existing scheme, so the token/userinfo/jwks calls follow over http automatically. Verified against openid_connect 2.3.1 / swd 2.0.3. Fixes #2844 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(oidc): scheme-aware port and discovery cache key Address automated review feedback on the OIDC http-discovery patch: - Preserve explicitly configured non-default ports (http on 443, https on 80) by omitting only the scheme's own default port instead of both 80 and 443. - Override the discovery cache_key to include scheme/port/path (the gem keyed on host alone), so an http:// issuer can't reuse an https:// issuer's cached metadata on the same host. Latent today (default SWD cache is a no-op) but removed to keep the override self-consistent. Adds regression tests for both cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(oidc): cover port and path as cache-key components Extend the discovery cache-key test to assert scheme, port, and path each produce a distinct key on the same host, per review feedback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
2.1 KiB
Ruby
54 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Patch: honor the issuer's scheme during OIDC discovery.
|
|
#
|
|
# The openid_connect/swd gems hardcode discovery to HTTPS (SWD.url_builder defaults to
|
|
# URI::HTTPS, and Config::Resource drops the issuer's scheme), so an http:// issuer -
|
|
# a self-hosted IdP without SSL - is upgraded to https:443 and fails to connect.
|
|
#
|
|
# Only the discovery request is affected: the endpoints it returns are absolute, and
|
|
# rack-oauth2 keeps a scheme that is already present, so the rest of the flow follows.
|
|
# The port and cache-key handling below are also made scheme-aware so an http:// issuer
|
|
# never drops an explicit port or reuses an https:// issuer's cached metadata.
|
|
#
|
|
# Verified against openid_connect 2.3.1 / swd 2.0.3 - revisit if those are upgraded.
|
|
# See https://github.com/we-promise/sure/issues/2844.
|
|
require "openid_connect"
|
|
|
|
module OpenIDConnect
|
|
module Discovery
|
|
module Provider
|
|
class Config
|
|
class Resource
|
|
def initialize(uri)
|
|
@scheme = uri.scheme
|
|
@host = uri.host
|
|
# Only omit the scheme's own default port, so an explicitly configured
|
|
# non-default port (e.g. http on 443, https on 80) is preserved.
|
|
@port = uri.port unless uri.port == uri.default_port
|
|
@path = File.join uri.path, ".well-known/openid-configuration"
|
|
attr_missing!
|
|
end
|
|
|
|
def endpoint
|
|
url_builder = @scheme == "http" ? URI::HTTP : URI::HTTPS
|
|
url_builder.build [ nil, host, port, path, nil, nil ]
|
|
rescue URI::Error => e
|
|
raise SWD::Exception.new(e.message)
|
|
end
|
|
|
|
private
|
|
|
|
# The gem keys the discovery cache on host alone. Now that a single host
|
|
# can be reached over more than one scheme/port/path, include those so an
|
|
# http:// issuer never reuses an https:// issuer's cached metadata.
|
|
def cache_key
|
|
digest = OpenSSL::Digest::SHA256.hexdigest [ @scheme, host, port, path ].join(" ")
|
|
"swd:resource:opneid-conf:#{digest}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|