Hi!! After some discussion about PGOAUTHCAFILE[1] variable, the need of having the TLS support for the tests added in a different patch[2].
I'm attaching a patch that add this TLS support making use of the already certs system in the `src/test/ssl/` directory and just making the `oauth_server.py` script able to support TLS only, this removes the plain HTTP support from the server. My Python skills are old, but I tried to keep the modifications as simple as possible, even that there's an easy way to have the context in Python 3.14, I decided to just have a context because the function HTTPSServer() is only available from Python 3.14 and above, which is not so widely used yet, in the future for sure will be more simple to use that function. [1] https://www.postgresql.org/message-id/flat/16a91d02795cb991963326a902afa764e4d721db.camel%40gmail.com [2] https://www.postgresql.org/message-id/flat/9850AB21-78A7-43CD-94C6-FA8E3BC9F1B3%40yesql.se#11e8d9febb3c3b428caa383f0c3f6acf -- Jonathan Gonzalez V. <[email protected]>
From 3c1eddf0734c6c6ce7e0f91a5e991a95692f5f20 Mon Sep 17 00:00:00 2001 From: "Jonathan Gonzalez V." <[email protected]> Date: Fri, 27 Feb 2026 17:19:42 +0100 Subject: [PATCH v1 1/1] Add TLS support for the OAuth tests To be able to properly test some options related to certificates we require to be able to run the test over TLS, this patch provides the required infrastructure for this. The certificates are generated in `src/tests/ssl/` directory since all the configurations related to generate certificates and CA are present in that directory. Signed-off-by: Jonathan Gonzalez V. <[email protected]> --- .../modules/oauth_validator/t/001_server.pl | 17 +++++------ .../modules/oauth_validator/t/OAuth/Server.pm | 7 ++--- .../modules/oauth_validator/t/oauth_server.py | 11 +++++++- src/test/ssl/conf/server-ip-localhost.config | 18 ++++++++++++ src/test/ssl/ssl/server-ip-localhost.crt | 20 +++++++++++++ src/test/ssl/ssl/server-ip-localhost.key | 28 +++++++++++++++++++ src/test/ssl/sslfiles.mk | 1 + 7 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 src/test/ssl/conf/server-ip-localhost.config create mode 100644 src/test/ssl/ssl/server-ip-localhost.crt create mode 100644 src/test/ssl/ssl/server-ip-localhost.key diff --git a/src/test/modules/oauth_validator/t/001_server.pl b/src/test/modules/oauth_validator/t/001_server.pl index 6b649c0b06f..12da59109bf 100644 --- a/src/test/modules/oauth_validator/t/001_server.pl +++ b/src/test/modules/oauth_validator/t/001_server.pl @@ -14,6 +14,7 @@ use MIME::Base64 qw(encode_base64); use PostgreSQL::Test::Cluster; use PostgreSQL::Test::Utils; use Test::More; +use File::Basename; use FindBin; use lib $FindBin::RealBin; @@ -72,7 +73,7 @@ END } my $port = $webserver->port(); -my $issuer = "http://127.0.0.1:$port"; +my $issuer = "https://localhost:$port"; unlink($node->data_dir . '/pg_hba.conf'); $node->append_conf( @@ -96,17 +97,13 @@ is( $contents, 3|oauth|\{issuer=$issuer/param,"scope=openid postgres",validator=validator\}}, "pg_hba_file_rules recreates OAuth HBA settings"); -# To test against HTTP rather than HTTPS, we need to enable PGOAUTHDEBUG. But -# first, check to make sure the client refuses such connections by default. -$node->connect_fails( - "user=test dbname=postgres oauth_issuer=$issuer oauth_client_id=f02c6361-0635", - "HTTPS is required without debug mode", - expected_stderr => - qr@OAuth discovery URI "\Q$issuer\E/.well-known/openid-configuration" must use HTTPS@ -); - +# To test against HTTPS, we need to enable PGOAUTHDEBUG and provide the right +# CA to be able to verify the server certificate $ENV{PGOAUTHDEBUG} = "UNSAFE"; +my $certdir = dirname(__FILE__) . "/../../../ssl/ssl"; +$ENV{PGOAUTHCAFILE} = "$certdir/root+server_ca.crt"; + my $user = "test"; $node->connect_ok( "user=$user dbname=postgres oauth_issuer=$issuer oauth_client_id=f02c6361-0635", diff --git a/src/test/modules/oauth_validator/t/OAuth/Server.pm b/src/test/modules/oauth_validator/t/OAuth/Server.pm index 89ea7ab4a4c..84c62f38c6b 100644 --- a/src/test/modules/oauth_validator/t/OAuth/Server.pm +++ b/src/test/modules/oauth_validator/t/OAuth/Server.pm @@ -15,7 +15,7 @@ OAuth::Server - runs a mock OAuth authorization server for testing $server->run; my $port = $server->port; - my $issuer = "http://127.0.0.1:$port"; + my $issuer = "https://localhost:$port"; # test against $issuer... @@ -27,9 +27,8 @@ This is glue API between the Perl tests and the Python authorization server daemon implemented in t/oauth_server.py. (Python has a fairly usable HTTP server in its standard library, so the implementation was ported from Perl.) -This authorization server does not use TLS (it implements a nonstandard, unsafe -issuer at "http://127.0.0.1:<port>"), so libpq in particular will need to set -PGOAUTHDEBUG=UNSAFE to be able to talk to it. +This authorization server runs over TLS, so libpq will need to set +PGOAUTHDEBUG=UNSAFE and PGOAUTHCAFILE with the right CA. =cut diff --git a/src/test/modules/oauth_validator/t/oauth_server.py b/src/test/modules/oauth_validator/t/oauth_server.py index c70783ecbe4..d7de984535b 100755 --- a/src/test/modules/oauth_validator/t/oauth_server.py +++ b/src/test/modules/oauth_validator/t/oauth_server.py @@ -11,12 +11,17 @@ import functools import http.server import json import os +import ssl import sys import time import urllib.parse from collections import defaultdict from typing import Dict +oauth_server_dir = os.path.dirname(os.path.realpath(__file__)) +ssl_dir = os.path.join(oauth_server_dir, "../../../ssl/ssl") +ssl_cert = ssl_dir + "/server-ip-localhost.crt" +ssl_key = ssl_dir + "/server-ip-localhost.key" class OAuthHandler(http.server.BaseHTTPRequestHandler): """ @@ -295,7 +300,7 @@ class OAuthHandler(http.server.BaseHTTPRequestHandler): def config(self) -> JsonObject: port = self.server.socket.getsockname()[1] - issuer = f"http://127.0.0.1:{port}" + issuer = f"https://localhost:{port}" if self._alt_issuer: issuer += "/alternate" elif self._parameterized: @@ -408,8 +413,12 @@ def main(): Starts the authorization server on localhost. The ephemeral port in use will be printed to stdout. """ + # To be able to listen over SSL we create the context and load the certificates + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(ssl_cert, ssl_key) s = http.server.HTTPServer(("127.0.0.1", 0), OAuthHandler) + s.socket = ssl_context.wrap_socket(s.socket, server_side=True) # Attach a "cache" dictionary to the server to allow the OAuthHandlers to # track state across token requests. The use of defaultdict ensures that new diff --git a/src/test/ssl/conf/server-ip-localhost.config b/src/test/ssl/conf/server-ip-localhost.config new file mode 100644 index 00000000000..61f10af0619 --- /dev/null +++ b/src/test/ssl/conf/server-ip-localhost.config @@ -0,0 +1,18 @@ +# An OpenSSL format CSR config file for creating a server certificate. +# + +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] +CN = localhost +OU = PostgreSQL test suite + +# For Subject Alternative Names +[ v3_req ] +subjectAltName = @alt_names + +[ alt_names ] +IP.1 = 127.0.0.1 +IP.2 = ::1 diff --git a/src/test/ssl/ssl/server-ip-localhost.crt b/src/test/ssl/ssl/server-ip-localhost.crt new file mode 100644 index 00000000000..c6e4dadcef8 --- /dev/null +++ b/src/test/ssl/ssl/server-ip-localhost.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIIICYCJxcTNAAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE +Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl +cnZlciBjZXJ0czAgFw0yNjAyMjcxNjEzMzRaGA8yMDUzMDcxNTE2MTMzNFowNDEe +MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAlsb2NhbGhv +c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC3bW97F0OjQR1E+CW +TLqPsBngwy02IBbcPZNr19HYodby82mKavwvU7IDkTCCNTU89zlHbzlF4NsnWuvA +zQlPk/kfg9OeDj2G3PKYvHe2G9xkuBEgusKsq+FkQcx3o4S93fAZKyCztgBVptfm +/q8CeJ4nsNlQI7uAYZ9s3R36PrX92qS50NvOOIm5zxRtCXX51gMVqWS7t/iyvXU2 +EVGyXLRyOArCoVkfY9AbBAJJzftzEQjqUVS7W2INUr8KLkRRJOKrzkBLg8T2+YmR +PNKdqhVMhn5uozjTgA0viQN1rVJZvxahR8zAhhqChO7+84xWEcZTl9Lc5uWDV+O4 +w4bPAgMBAAGjQjBAMB0GA1UdDgQWBBQWXk4bIK8qHwQpAQTmvNX4B/h5ozAfBgNV +HSMEGDAWgBTyjzpmQFBkSCLXLoL/Vp7Cs+50CjANBgkqhkiG9w0BAQsFAAOCAQEA +Kh0pDHJfQ/5daLpmLiOwZD3KqN8FQd5QNVJjlGD3Qh3QblVRGNl1csLSWb4BnENO +3Kq6zKkNBSoAA6bFqVhXcdL1utrnGk2fLpInGMA5B+r+BpZkUVSKu6BPn/HNnImt +PCZ3sjQyTZ1QXjDjxiOynGkDl9G+3RKDsDhdOHxoqCKUDlHkC9oi3FxkNgvvwpVu +ybio+haTmoRbOr7U5MFNbtQOglgjV4/QeFjzSm3mrSuCEJVTI4/CovbboM5xZ144 +FNunyccqdaFA9O3lKsmj03zEIkI9kNRL8IRNVf/xoVRdivNMdHhG+KrO9pqIYuYM +3Vsjv+Men06w2B0StaazZg== +-----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/server-ip-localhost.key b/src/test/ssl/ssl/server-ip-localhost.key new file mode 100644 index 00000000000..748cf7a59b4 --- /dev/null +++ b/src/test/ssl/ssl/server-ip-localhost.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDC3bW97F0OjQR1 +E+CWTLqPsBngwy02IBbcPZNr19HYodby82mKavwvU7IDkTCCNTU89zlHbzlF4Nsn +WuvAzQlPk/kfg9OeDj2G3PKYvHe2G9xkuBEgusKsq+FkQcx3o4S93fAZKyCztgBV +ptfm/q8CeJ4nsNlQI7uAYZ9s3R36PrX92qS50NvOOIm5zxRtCXX51gMVqWS7t/iy +vXU2EVGyXLRyOArCoVkfY9AbBAJJzftzEQjqUVS7W2INUr8KLkRRJOKrzkBLg8T2 ++YmRPNKdqhVMhn5uozjTgA0viQN1rVJZvxahR8zAhhqChO7+84xWEcZTl9Lc5uWD +V+O4w4bPAgMBAAECggEAAnJfIopWH08bU/A54+4bAzuZgPlu7UPFqpR/FvbYfPh9 +Ka+9TsuPZ3WBz+ZksPJfhUzRd7ayOBO5rtBHEyPzaSFdXXyRR/xRvs0slz3jnZvp +Hxz6upkx5t/2Z00wz9BdsccjpS5M3OIFV1vkchCRmGCAFAzaOHckewW7/tV7Ugfa +pNuYz0WjJT7N2sU362QINABgWtD1a3vPOyspsrSb8Gox1fzeGAgCZi8oKiI3QYuk +ooyqwbs/lkXKHRZXmLc7lXMr1wWLLnMUUUGXZ/eC4vpPJ9rH33ymxShAfrUGWvXQ +fXnuabLyMT0a/uhaJZh0/jAk1BOnUnjHCHuBpyHGrQKBgQD5mpYbpAChs9vN6yFP +RPjc2q9xuJbLzsi9vTgTxRiYVUcYWJ2Lcz2wSg9nyBsHBZVFqH9uVGTCImOIDbba +8lIZmvC4nNiMxhsD1jQZQBCOU03t0Ga5ImxUYexxq/lP809qJcGKdgVSGA93ufkC +7FXJH6iWnwTk/jiM/YyaJhX/QwKBgQDH3Ap4aGf7CmkULvKei9435lt1a3YkmXmt +NOBBimLUyXJtq1m//Thx/Gp9CVa38M3fd0NH6ZZvRJBPwO+43A3EqXv/qXn9dNcA +xY2bYtRrm3LGilNuG2C/8T+cZ+T9hX4dSIwefJMYGPDkZNwgwl/tjRjbZZE+KWv8 +VGQ87HVjhQKBgQCMZW5vh7UvP1qwncQzsUkF+R/cKIbxhpOVXhxvylpGPRlrUVT0 +flLBmTbHGmBRd8t5zgg3h9LQ+8TeX1BuIQUbD/K89MQ9kqTZaKAPX+CwHZ1k2ecd +1YX3hMkZOzFVzjbqLuiJOE9P2ObCYmH1SfgK0/rhFfsLzw8CBxASGMAgvwKBgBr6 +wlMUzQyfkCXQXKI4gWwMZcZJFm7EZR+Tpr5SPxs4goD5g6keNtN0Xq+4ZgN4t2H2 +SJfZmZw1pkGN6w6KbjVhJ8MQjs4/SpLpGD+krMZF+s2AeNjBS2M93vdvMwNiVO8B +DyFCcdzr6QD7+JdXhfmcdYGQiXXZw6ERh2KODR69AoGBAPQ4IRTIh3jfBj2xZenI +MDegCiOIAO516GTX0C1aB3jFhH4pcdbiN2R/2dffdvZvuQmJ4kCmyggvyx9QjUHL +/Kxk0jacA14LFOmrnlihwET4gfeL8S3vzhJcNcv0GXOgWe4hP9LH+eaidICx/JlD +hYX8HYSKQxIFmt5IUAxlUvoj +-----END PRIVATE KEY----- diff --git a/src/test/ssl/sslfiles.mk b/src/test/ssl/sslfiles.mk index ecb40588c87..68fc0366df3 100644 --- a/src/test/ssl/sslfiles.mk +++ b/src/test/ssl/sslfiles.mk @@ -29,6 +29,7 @@ SERVERS := server-cn-and-alt-names \ server-ip-cn-and-alt-names \ server-ip-cn-and-dns-alt-names \ server-ip-in-dnsname \ + server-ip-localhost \ server-single-alt-name \ server-multiple-alt-names \ server-no-names \ -- 2.51.0
signature.asc
Description: This is a digitally signed message part
