diff --git a/src/http_client.cpp b/src/http_client.cpp index b5d22ad..72a9e6e 100644 --- a/src/http_client.cpp +++ b/src/http_client.cpp @@ -15,6 +15,8 @@ extern "C" { #include #include +extern bool pg_oidc_validator_insecure_skip_tls_verify; + http_client::http_client() : curl(curl_easy_init()), last_max_age_(std::nullopt) { if (curl == nullptr) { throw std::runtime_error("Failed to initialize libcurl"); @@ -96,6 +98,11 @@ picojson::value http_client::get_json(const std::string& url) { curl_easy_setopt(curl, CURLOPT_HEADERDATA, this); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); + if (pg_oidc_validator_insecure_skip_tls_verify) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { diff --git a/src/pg_oidc_validator.cpp b/src/pg_oidc_validator.cpp index e56fec0..207cec7 100644 --- a/src/pg_oidc_validator.cpp +++ b/src/pg_oidc_validator.cpp @@ -30,10 +30,26 @@ const OAuthValidatorCallbacks* _PG_oauth_validator_module_init(void) { return &v static char* authn_field = nullptr; +// When non-empty, the validator uses this URL (instead of pg_hba's `issuer=`) +static char* discovery_url_override = nullptr; + +// Off by default; only meant for local development against self-signed Keycloak/IdP certs. +bool pg_oidc_validator_insecure_skip_tls_verify = false; + extern "C" void _PG_init() { DefineCustomStringVariable("pg_oidc_validator.authn_field", gettext_noop("OAuth field used for matching PostgreSQL users"), nullptr, &authn_field, "sub", PGC_SIGHUP, 0, nullptr, nullptr, nullptr); + DefineCustomStringVariable( + "pg_oidc_validator.discovery_url_override", + gettext_noop("If set, fetch OIDC discovery and JWKS from this URL instead of the pg_hba issuer."), + gettext_noop("The JWT `iss` claim is still validated against the pg_hba issuer."), + &discovery_url_override, "", PGC_SIGHUP, 0, nullptr, nullptr, nullptr); + DefineCustomBoolVariable( + "pg_oidc_validator.insecure_skip_tls_verify", + gettext_noop("Disable TLS certificate verification for OIDC discovery and JWKS fetches."), + gettext_noop("UNSAFE. Only intended for local development against self-signed certs."), + &pg_oidc_validator_insecure_skip_tls_verify, false, PGC_SIGHUP, 0, nullptr, nullptr, nullptr); } bool validate_token(const ValidatorModuleState* state, const char* token, const char* role, @@ -53,9 +69,11 @@ bool validate_token(const ValidatorModuleState* state, const char* token, const const scopes_t required_scopes(required_scopes_range.begin(), required_scopes_range.end()); const std::string issuer = MyProcPort->hba->oauth_issuer; + const std::string discovery_url = + (discovery_url_override != nullptr && *discovery_url_override != '\0') ? discovery_url_override : issuer; http_client http; - const auto issuer_info = http.get_json(issuer_info_url(issuer)); + const auto issuer_info = http.get_json(issuer_info_url(discovery_url)); if (!issuer_info.is()) { elog(WARNING, "OpenID configuration from issuer is not a JSON object");