From b42285fa8be8cc1ffc96cbab2b629b9711f9add9 Mon Sep 17 00:00:00 2001 From: Barry Simons Date: Thu, 8 Apr 2021 17:12:12 -0400 Subject: [PATCH 01/22] use native-tls API --- .github/workflows/sqlx.yml | 87 +++++++++++++++++++++++++ sqlx-core/src/net/tls/mod.rs | 2 + sqlx-core/src/net/tls/tls_native_tls.rs | 11 +++- sqlx-core/src/net/tls/tls_rustls.rs | 31 ++++++++- sqlx-postgres/src/options/mod.rs | 38 +++++++++++ sqlx-postgres/src/options/parse.rs | 4 ++ tests/.dockerignore | 1 + tests/certs/ca.srl | 1 + tests/certs/client.crt | 57 ++++++++++++++++ tests/certs/client.csr | 60 +++++++++++++++++ tests/docker-compose.yml | 48 ++++++++++++-- tests/keys/client.key | 28 ++++++++ tests/postgres/Dockerfile | 2 + tests/postgres/pg_hba.conf | 4 ++ 14 files changed, 366 insertions(+), 8 deletions(-) create mode 100644 tests/certs/ca.srl create mode 100644 tests/certs/client.crt create mode 100644 tests/certs/client.csr create mode 100644 tests/keys/client.key create mode 100644 tests/postgres/pg_hba.conf diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 2ca687ca2b..809793cd86 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -232,6 +232,93 @@ jobs: # but `PgLTree` should just fall back to text format RUSTFLAGS: --cfg postgres_${{ matrix.postgres }} + postgres_native_cert: + name: Postgres Openssl Certificate Authentication + runs-on: ubuntu-20.04 + strategy: + matrix: + postgres: [12, 10, 9_6, 9_5] + runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls] + needs: check + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }} + + - uses: actions-rs/cargo@v1 + with: + command: build + args: > + --features postgres,openssl,all-types,runtime-${{ matrix.runtime }} + + - run: docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 postgres_${{ matrix.postgres }}_cert + - run: sleep 10 + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --no-default-features + --features any,postgres,openssl,macros,migrate,all-types,runtime-${{ matrix.runtime }} + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslcert=.%2Ftests%2Fcerts%2Fclient.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key + + + postgres_cert: + name: Postgres Rustls Certificate Authentication + runs-on: ubuntu-20.04 + strategy: + matrix: + postgres: [12, 10, 9_6, 9_5] + runtime: [async-std-rustls, tokio-rustls, actix-rustls] + needs: check + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }} + + - uses: actions-rs/cargo@v1 + with: + command: build + args: > + --features postgres,all-types,runtime-${{ matrix.runtime }} + + - run: docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 postgres_${{ matrix.postgres }}_cert + - run: sleep 10 + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --no-default-features + --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }} + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslcert=.%2Ftests%2Fcerts%2Fclient.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key + mysql: name: MySQL runs-on: ubuntu-20.04 diff --git a/sqlx-core/src/net/tls/mod.rs b/sqlx-core/src/net/tls/mod.rs index 3fae0ecaed..0b1df2b341 100644 --- a/sqlx-core/src/net/tls/mod.rs +++ b/sqlx-core/src/net/tls/mod.rs @@ -61,6 +61,8 @@ pub struct TlsConfig<'a> { pub accept_invalid_hostnames: bool, pub hostname: &'a str, pub root_cert_path: Option<&'a CertificateInput>, + pub client_cert_path: Option<&'a CertificateInput>, + pub client_key_path: Option<&'a CertificateInput>, } pub async fn handshake( diff --git a/sqlx-core/src/net/tls/tls_native_tls.rs b/sqlx-core/src/net/tls/tls_native_tls.rs index 4b0e3085d4..8c5eeb10da 100644 --- a/sqlx-core/src/net/tls/tls_native_tls.rs +++ b/sqlx-core/src/net/tls/tls_native_tls.rs @@ -6,7 +6,7 @@ use crate::net::tls::TlsConfig; use crate::net::Socket; use crate::Error; -use native_tls::HandshakeError; +use native_tls::{HandshakeError, Identity}; use std::task::{Context, Poll}; pub struct NativeTlsSocket { @@ -53,6 +53,15 @@ pub async fn handshake( builder.add_root_certificate(native_tls::Certificate::from_pem(&data).map_err(Error::tls)?); } + // authentication using user's key-file and its associated certificate + if let (Some(cert_path), Some(key_path)) = (config.client_cert_path, config.client_key_path) { + let cert_path = cert_path.data().await?; + let key_path = key_path.data().await?; + let identity = + Identity::from_pkcs8(&cert_path, &key_path).map_err(|e| Error::Tls(e.into()))?; + builder.identity(identity); + } + let connector = builder.build().map_err(Error::tls)?; let mut mid_handshake = match connector.connect(config.hostname, StdSocket::new(socket)) { diff --git a/sqlx-core/src/net/tls/tls_rustls.rs b/sqlx-core/src/net/tls/tls_rustls.rs index 230e03527f..c1c9f46ce0 100644 --- a/sqlx-core/src/net/tls/tls_rustls.rs +++ b/sqlx-core/src/net/tls/tls_rustls.rs @@ -108,12 +108,39 @@ where } } + // authentication using user's key and its associated certificate + let user_auth = match (tls_config.client_cert_path, tls_config.client_key_path) { + (Some(cert_path), Some(key_path)) => { + let cert_chain = certs_from_pem(cert_path.data().await?)?; + let key_der = private_key_from_pem(key_path.data().await?)?; + Some((cert_chain, key_der)) + } + (None, None) => None, + (_, _) => { + return Err(Error::Configuration( + "user auth key and certs must be given together".into(), + )) + } + }; + if tls_config.accept_invalid_hostnames { let verifier = WebPkiVerifier::new(cert_store, None); + if let Some(user_auth) = user_auth { + config + .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) + .with_single_cert(user_auth.0, user_auth.1) + .map_err(|err| Error::Tls(err.into()))? + } else { + config + .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) + .with_no_client_auth() + } + } else if let Some(user_auth) = user_auth { config - .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) - .with_no_client_auth() + .with_root_certificates(cert_store) + .with_single_cert(user_auth.0, user_auth.1) + .map_err(|err| Error::Tls(err.into()))? } else { config .with_root_certificates(cert_store) diff --git a/sqlx-postgres/src/options/mod.rs b/sqlx-postgres/src/options/mod.rs index 9bca6629df..5c2e47f755 100644 --- a/sqlx-postgres/src/options/mod.rs +++ b/sqlx-postgres/src/options/mod.rs @@ -87,6 +87,8 @@ pub struct PgConnectOptions { pub(crate) database: Option, pub(crate) ssl_mode: PgSslMode, pub(crate) ssl_root_cert: Option, + pub(crate) ssl_client_cert: Option, + pub(crate) ssl_client_key: Option, pub(crate) statement_cache_capacity: usize, pub(crate) application_name: Option, pub(crate) log_settings: LogSettings, @@ -112,6 +114,8 @@ impl PgConnectOptions { /// * `PGPASSWORD` /// * `PGDATABASE` /// * `PGSSLROOTCERT` + /// * `PGSSLCERT` + /// * `PGSSLKEY` /// * `PGSSLMODE` /// * `PGAPPNAME` /// @@ -145,6 +149,8 @@ impl PgConnectOptions { password: var("PGPASSWORD").ok(), database, ssl_root_cert: var("PGSSLROOTCERT").ok().map(CertificateInput::from), + ssl_client_cert: var("PGSSLCERT").ok().map(CertificateInput::from), + ssl_client_key: var("PGSSLKEY").ok().map(CertificateInput::from), ssl_mode: var("PGSSLMODE") .ok() .and_then(|v| v.parse().ok()) @@ -314,6 +320,38 @@ impl PgConnectOptions { self } + /// Sets the name of a file containing SSL client certificate. + /// + /// # Example + /// + /// ```rust + /// # use sqlx_core::postgres::{PgSslMode, PgConnectOptions}; + /// let options = PgConnectOptions::new() + /// // Providing a CA certificate with less than VerifyCa is pointless + /// .ssl_mode(PgSslMode::VerifyCa) + /// .ssl_client_cert("./client.crt"); + /// ``` + pub fn ssl_client_cert(mut self, cert: impl AsRef) -> Self { + self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf())); + self + } + + /// Sets the name of a file containing SSL client key. + /// + /// # Example + /// + /// ```rust + /// # use sqlx_core::postgres::{PgSslMode, PgConnectOptions}; + /// let options = PgConnectOptions::new() + /// // Providing a CA certificate with less than VerifyCa is pointless + /// .ssl_mode(PgSslMode::VerifyCa) + /// .ssl_client_key("./client.key"); + /// ``` + pub fn ssl_client_key(mut self, cert: impl AsRef) -> Self { + self.ssl_client_key = Some(CertificateInput::File(cert.as_ref().to_path_buf())); + self + } + /// Sets PEM encoded trusted SSL Certificate Authorities (CA). /// /// # Example diff --git a/sqlx-postgres/src/options/parse.rs b/sqlx-postgres/src/options/parse.rs index e837a95019..a0bed01cd5 100644 --- a/sqlx-postgres/src/options/parse.rs +++ b/sqlx-postgres/src/options/parse.rs @@ -53,6 +53,10 @@ impl PgConnectOptions { options = options.ssl_root_cert(&*value); } + "sslcert" => options = options.ssl_client_cert(&*value), + + "sslkey" => options = options.ssl_client_key(&*value), + "statement-cache-capacity" => { options = options.statement_cache_capacity(value.parse().map_err(Error::config)?); diff --git a/tests/.dockerignore b/tests/.dockerignore index 6c513a8a33..f1c67fa243 100644 --- a/tests/.dockerignore +++ b/tests/.dockerignore @@ -2,4 +2,5 @@ !certs/* !keys/* !mssql/*.sh +!postgres/pg_hba.conf !*/*.sql diff --git a/tests/certs/ca.srl b/tests/certs/ca.srl new file mode 100644 index 0000000000..ef2f121531 --- /dev/null +++ b/tests/certs/ca.srl @@ -0,0 +1 @@ +B6C71F4B11C0A189 diff --git a/tests/certs/client.crt b/tests/certs/client.crt new file mode 100644 index 0000000000..0edde05434 --- /dev/null +++ b/tests/certs/client.crt @@ -0,0 +1,57 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: + e0:be:1f:7a:49:1e:49:ec + Signature Algorithm: NULL + Issuer: CN = postgres + Validity + Not Before: Apr 10 20:59:23 2021 GMT + Not After : Apr 8 20:59:23 2031 GMT + Subject: CN = postgres + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:4f:18:ca:d8:ff:a3:93:aa:9a:3b:90:35:c7: + ff:82:65:d1:d0:e8:65:9d:9c:6c:cb:70:4e:31:7e: + 7e:52:ce:2d:85:7a:83:ee:b8:eb:f1:ba:37:0e:34: + 66:3d:b6:db:cb:45:6f:64:0f:5c:4d:ba:53:25:c9: + ff:e0:a1:39:9b:82:c9:c0:08:e8:17:6b:01:6a:99: + 47:05:d8:c5:2f:83:f3:33:f7:ad:bb:f3:dd:5f:6a: + 95:4f:d9:8e:1d:bc:ff:84:78:77:eb:98:40:36:2d: + 9a:a3:29:a6:ba:58:90:c1:92:88:5f:07:c3:a8:a6: + 06:f0:ca:f8:81:40:13:65:1d:08:6c:97:9f:d4:b4: + 8d:f7:77:32:f6:2c:d4:9b:07:b3:86:3a:62:7f:da: + 3d:3c:e9:96:71:cc:62:2e:ac:6d:00:ca:ac:6c:a1: + b4:68:28:67:18:be:4b:31:e7:f1:c3:1d:a4:ad:05: + 50:59:44:30:09:b1:91:e1:86:5d:ec:75:06:a9:70: + 43:6b:81:5c:ff:98:fd:22:5c:3a:0e:08:2e:e3:b3: + c4:e0:65:dd:cd:e7:f2:69:08:0a:1b:90:c4:06:c1: + 06:ee:75:ee:d3:3c:ab:a2:9c:51:00:1c:56:fe:24: + 92:36:ee:e1:f3:6f:0c:14:79:32:07:f9:12:2b:26: + 79:c1 + Exponent: 65537 (0x10001) + Signature Algorithm: NULL +-----BEGIN CERTIFICATE----- +MIIDjjCCAfYCCQC2xx9LEcChiTANBgkqhkiG9w0BAQsFADB/MR4wHAYDVQQKExVt +a2NlcnQgZGV2ZWxvcG1lbnQgQ0ExKjAoBgNVBAsMIW1laGNvZGVAR29sZW0ubG9j +YWwgKFJ5YW4gTGVja2V5KTExMC8GA1UEAwwobWtjZXJ0IG1laGNvZGVAR29sZW0u +bG9jYWwgKFJ5YW4gTGVja2V5KTAeFw0yMTA0MTAyMDU5MjNaFw0zMTA0MDgyMDU5 +MjNaMBMxETAPBgNVBAMMCHBvc3RncmVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAv08Yytj/o5OqmjuQNcf/gmXR0OhlnZxsy3BOMX5+Us4thXqD7rjr +8bo3DjRmPbbby0VvZA9cTbpTJcn/4KE5m4LJwAjoF2sBaplHBdjFL4PzM/etu/Pd +X2qVT9mOHbz/hHh365hANi2aoymmuliQwZKIXwfDqKYG8Mr4gUATZR0IbJef1LSN +93cy9izUmwezhjpif9o9POmWccxiLqxtAMqsbKG0aChnGL5LMefxwx2krQVQWUQw +CbGR4YZd7HUGqXBDa4Fc/5j9Ilw6Dggu47PE4GXdzefyaQgKG5DEBsEG7nXu0zyr +opxRABxW/iSSNu7h828MFHkyB/kSKyZ5wQIDAQABMA0GCSqGSIb3DQEBCwUAA4IB +gQBxzRXtmp1gXzNTnwQ+acdZ2mRkjoEkr00e5wQTXCcOhfsXG/udQaEU1SUhaCyV +HppmxDB4i3aHhiGKztk6JU/SE9o4B//BbdLfmv741lwrE/5Lgx2YSBnATqDWC7rI +W2Tj33Sf06y7MKgkG5TszkM2cGdYhowhsyhhpww50gKfoRBNTp935jLo3nytShiM +NeQpf7/Wjcd1yIRYbWefTDJDSwGnzBoPCNHIEhAT15RUV2jGe9ctSMU2zQWInDll +U8dkWRZp9cZpQCvx2HkMy7oqsigoHxSSnsMzc8gtJHdhovjoLAVu9y5mAtEjHnTd +2ud1woYVo5dDoQEaFMp1Ll4qotLhMRVDl3SBPJoKOrEQfS/4JwITzuS8C7RSlmxE +UR2gPw7R39ocTE/rigUnE4WHf4q18kWrkRRZoMsvitv9FSyMkN1yaL0IintkRXzg +ZkSZbzxVriE1dZ5u+Ie1zNaa5rB+yb/nzRC9HMbBtZbVgHe1ngr+pEyAMWFd4U8N +HRQ= +-----END CERTIFICATE----- diff --git a/tests/certs/client.csr b/tests/certs/client.csr new file mode 100644 index 0000000000..619f572efa --- /dev/null +++ b/tests/certs/client.csr @@ -0,0 +1,60 @@ +Certificate Request: + Data: + Version: 1 (0x0) + Subject: CN = postgres + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:4f:18:ca:d8:ff:a3:93:aa:9a:3b:90:35:c7: + ff:82:65:d1:d0:e8:65:9d:9c:6c:cb:70:4e:31:7e: + 7e:52:ce:2d:85:7a:83:ee:b8:eb:f1:ba:37:0e:34: + 66:3d:b6:db:cb:45:6f:64:0f:5c:4d:ba:53:25:c9: + ff:e0:a1:39:9b:82:c9:c0:08:e8:17:6b:01:6a:99: + 47:05:d8:c5:2f:83:f3:33:f7:ad:bb:f3:dd:5f:6a: + 95:4f:d9:8e:1d:bc:ff:84:78:77:eb:98:40:36:2d: + 9a:a3:29:a6:ba:58:90:c1:92:88:5f:07:c3:a8:a6: + 06:f0:ca:f8:81:40:13:65:1d:08:6c:97:9f:d4:b4: + 8d:f7:77:32:f6:2c:d4:9b:07:b3:86:3a:62:7f:da: + 3d:3c:e9:96:71:cc:62:2e:ac:6d:00:ca:ac:6c:a1: + b4:68:28:67:18:be:4b:31:e7:f1:c3:1d:a4:ad:05: + 50:59:44:30:09:b1:91:e1:86:5d:ec:75:06:a9:70: + 43:6b:81:5c:ff:98:fd:22:5c:3a:0e:08:2e:e3:b3: + c4:e0:65:dd:cd:e7:f2:69:08:0a:1b:90:c4:06:c1: + 06:ee:75:ee:d3:3c:ab:a2:9c:51:00:1c:56:fe:24: + 92:36:ee:e1:f3:6f:0c:14:79:32:07:f9:12:2b:26: + 79:c1 + Exponent: 65537 (0x10001) + Attributes: + a0:00 + Signature Algorithm: sha256WithRSAEncryption + b1:1f:11:89:d3:6a:a3:b3:fb:9e:9d:de:b4:cb:5c:44:0f:86: + 69:c7:c5:81:f8:cc:42:24:6d:92:1c:e8:85:bc:22:ba:49:6f: + d4:f0:89:21:6c:39:9d:29:31:a5:2a:21:81:76:58:1b:0a:1b: + fb:46:9a:59:fd:e3:c8:7b:54:25:ad:ca:86:0f:2b:e7:aa:79: + 92:d4:f5:c7:91:5d:f2:f8:ff:fe:d1:5f:0c:30:8a:1a:89:0d: + 3a:d1:1b:f2:a4:77:bd:fb:3b:5a:c9:6c:15:e5:54:f9:10:ba: + 58:6a:a2:ee:7e:32:dc:fa:ef:51:f8:52:63:67:6e:e8:fa:fc: + 21:79:46:fb:f2:6d:16:34:6c:79:96:ae:1c:8b:2c:1b:c5:ab: + b7:ac:ad:14:25:55:de:41:76:a1:47:34:0e:b4:c7:48:b1:73: + e6:74:ed:17:5f:d9:f2:d0:ec:6a:6a:97:bd:7c:81:b9:22:09: + 14:d0:e0:5e:b8:14:70:f3:3d:b1:aa:2e:43:c8:10:7d:00:85: + 90:9c:80:9f:3d:03:c3:6c:df:f3:da:50:19:e7:5e:a0:0e:17: + f9:5c:ed:83:35:38:c2:9a:5b:ea:ea:ec:8b:27:1d:51:38:8b: + 94:eb:d0:69:4a:87:dd:52:49:dc:75:86:ce:5e:ee:ec:33:ff: + 8d:0c:30:40 +-----BEGIN CERTIFICATE REQUEST----- +MIICWDCCAUACAQAwEzERMA8GA1UEAwwIcG9zdGdyZXMwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQC/TxjK2P+jk6qaO5A1x/+CZdHQ6GWdnGzLcE4xfn5S +zi2FeoPuuOvxujcONGY9ttvLRW9kD1xNulMlyf/goTmbgsnACOgXawFqmUcF2MUv +g/Mz9627891fapVP2Y4dvP+EeHfrmEA2LZqjKaa6WJDBkohfB8OopgbwyviBQBNl +HQhsl5/UtI33dzL2LNSbB7OGOmJ/2j086ZZxzGIurG0AyqxsobRoKGcYvksx5/HD +HaStBVBZRDAJsZHhhl3sdQapcENrgVz/mP0iXDoOCC7js8TgZd3N5/JpCAobkMQG +wQbude7TPKuinFEAHFb+JJI27uHzbwwUeTIH+RIrJnnBAgMBAAGgADANBgkqhkiG +9w0BAQsFAAOCAQEAsR8RidNqo7P7np3etMtcRA+GacfFgfjMQiRtkhzohbwiuklv +1PCJIWw5nSkxpSohgXZYGwob+0aaWf3jyHtUJa3Khg8r56p5ktT1x5Fd8vj//tFf +DDCKGokNOtEb8qR3vfs7WslsFeVU+RC6WGqi7n4y3PrvUfhSY2du6Pr8IXlG+/Jt +FjRseZauHIssG8Wrt6ytFCVV3kF2oUc0DrTHSLFz5nTtF1/Z8tDsamqXvXyBuSIJ +FNDgXrgUcPM9saouQ8gQfQCFkJyAnz0Dw2zf89pQGedeoA4X+VztgzU4wppb6urs +iycdUTiLlOvQaUqH3VJJ3HWGzl7u7DP/jQwwQA== +-----END CERTIFICATE REQUEST----- diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 030d1bacff..1a19a7c716 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -84,7 +84,7 @@ services: context: . dockerfile: postgres/Dockerfile args: - VERSION: 15 + VERSION: 15 ports: - 5432 environment: @@ -103,7 +103,7 @@ services: context: . dockerfile: postgres/Dockerfile args: - VERSION: 14 + VERSION: 14 ports: - 5432 environment: @@ -122,7 +122,7 @@ services: context: . dockerfile: postgres/Dockerfile args: - VERSION: 13 + VERSION: 13 ports: - 5432 environment: @@ -136,12 +136,31 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + postgres_13_cert: + build: + context: . + dockerfile: postgres/Dockerfile + args: + VERSION: 13 + ports: + - 5432 + environment: + POSTGRES_DB: sqlx + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_HOST_AUTH_METHOD: scram-sha-256 + POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 + volumes: + - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + command: > + -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf + postgres_12: build: context: . dockerfile: postgres/Dockerfile args: - VERSION: 12 + VERSION: 12 ports: - 5432 environment: @@ -155,6 +174,25 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + postgres_12_cert: + build: + context: . + dockerfile: postgres/Dockerfile + args: + VERSION: 12.3 + ports: + - 5432 + environment: + POSTGRES_DB: sqlx + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_HOST_AUTH_METHOD: scram-sha-256 + POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 + volumes: + - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + command: > + -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf + postgres_11: build: context: . @@ -162,7 +200,7 @@ services: args: VERSION: 11 ports: - - 5432 + - 5432 environment: POSTGRES_DB: sqlx POSTGRES_USER: postgres diff --git a/tests/keys/client.key b/tests/keys/client.key new file mode 100644 index 0000000000..c5a237241e --- /dev/null +++ b/tests/keys/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC/TxjK2P+jk6qa +O5A1x/+CZdHQ6GWdnGzLcE4xfn5Szi2FeoPuuOvxujcONGY9ttvLRW9kD1xNulMl +yf/goTmbgsnACOgXawFqmUcF2MUvg/Mz9627891fapVP2Y4dvP+EeHfrmEA2LZqj +Kaa6WJDBkohfB8OopgbwyviBQBNlHQhsl5/UtI33dzL2LNSbB7OGOmJ/2j086ZZx +zGIurG0AyqxsobRoKGcYvksx5/HDHaStBVBZRDAJsZHhhl3sdQapcENrgVz/mP0i +XDoOCC7js8TgZd3N5/JpCAobkMQGwQbude7TPKuinFEAHFb+JJI27uHzbwwUeTIH ++RIrJnnBAgMBAAECggEAKNCZO328XIu+lBUtGSxIKOvMLcPHGi8rTuPw6sJP9R6j +u5x91UqCnBnccR1gyr3eeqmfsDtOuA6Oertz6dq7zZ/Dp0K/MW/U54c4DdlHiHGg +S3AGEtleW2MD4/tIRLPz17FT9GGRIX3tRe428f6/M20txwiDB9IUHP9QsVKYULPX +pzX+BMMINj70U1CcwcsIkPH9znDhwdMfjphC/eJUgITDle9EynYRhBHz55ajTTeE +hPsttRPYvbXdxd1WdSnt/Xv4+N10RKcEnrPE17WrbUs9RvqOz7hW4e4QifsBf5dR +0Sw1AemmdOK5xTrA0K9D7gRv6qC8QHuTDjIntVd8gQKBgQD+PyQUNJpvUre1zK1A +HBTVbX7uIqYrX6FWXFFE55HtcnrhEWIY5QCBPfOFsVdcvBJrqclkInpELjdnVbeP +25ETIKhhiP3FnJjJlNZiFXD85NmHbRJzABvNxspb+9UOuIJfB2ixSGmnEKEQIeJf +QmUzz/PJ9+2ct8/rXobZ90Is6QKBgQDAoNe/bUGc/ZmKq132hCcBeHFcjdtW6fkE +6d8giLx90b1kQzYJaM+4jhYF4s1job32ZPlykAlGUCtWBGirhonioJVgiGy4fOc0 +SlIcKg2Gh68FDdKGHcBN5duk0nCc+uLT1fNPqo98jy1DI6VCVej0xWBrFkMFXZ3S +qJ5PWtT/GQKBgFLBkqjRBoO91PZkDPCVM2LVJT+2H4h2tDk8C2f2SFWVsdGYqumX +gLaQx7d4pgsVXJmWxmrFni6bLIWCLSGyQmKLesNkp9Wuxzy2KaH7gK+Qfg3KvvqX +ynUMg8m1CwCjpivwaW9rNpienQ53OQvwvKhExAG1pa4hVpgySIqiJPQhAoGAeFUB +8cdisZuKiyG6NQEhDL4csuC7IHRQ50zh4gUJGuAnG7cQzpf3CydXgp3ICHFFpeI2 +IebwpEf4imd+q4gEItqF9iPDJwx/sh6rZISwplWkc9fKp5V2SDNLHo+HYckoYYTJ +1f6KXBllAQgHeIUKXb3fGYZyn6t3p91F5/SqEiECgYBzjAYDWIRi7IpMkckts2ZQ +p7YXZCbUP4MALTLuWulrI5IFv7gOjW20US/CArNMc4wPv5WtY1uE59pd8Td2CW9X +BX1nQXqaVlF6xLOzgqsWPxloRk7y692J9nYMKcB6VxlkFVUQfbRZksFCsn2I4Y5Z +ZtG/bPbIR6NgZ6ntNa+KIg== +-----END PRIVATE KEY----- diff --git a/tests/postgres/Dockerfile b/tests/postgres/Dockerfile index 184f062457..026adfac77 100644 --- a/tests/postgres/Dockerfile +++ b/tests/postgres/Dockerfile @@ -3,7 +3,9 @@ FROM postgres:${VERSION}-alpine # Copy SSL certificate (and key) COPY certs/server.crt /var/lib/postgresql/server.crt +COPY certs/ca.crt /var/lib/postgresql/ca.crt COPY keys/server.key /var/lib/postgresql/server.key +COPY postgres/pg_hba.conf /var/lib/postgresql/pg_hba.conf # Fix permissions RUN chown 70:70 /var/lib/postgresql/server.crt /var/lib/postgresql/server.key diff --git a/tests/postgres/pg_hba.conf b/tests/postgres/pg_hba.conf new file mode 100644 index 0000000000..be33c4bb10 --- /dev/null +++ b/tests/postgres/pg_hba.conf @@ -0,0 +1,4 @@ +# only needed for certificate authentication tests +# omit host to prevent fallback to non certificate authentication +local all all trust +hostssl all all all cert From 8e0198fb7079dac28ba7a5796683be86179605ea Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 18 Apr 2022 17:26:28 +0200 Subject: [PATCH 02/22] Add client cert and key to MySQL connector --- sqlx-mysql/src/options/mod.rs | 34 ++++++++++++++++++++++++++++++++ sqlx-mysql/src/options/parse.rs | 4 ++++ sqlx-postgres/src/options/mod.rs | 4 ++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/sqlx-mysql/src/options/mod.rs b/sqlx-mysql/src/options/mod.rs index d0959579d1..dc06380b07 100644 --- a/sqlx-mysql/src/options/mod.rs +++ b/sqlx-mysql/src/options/mod.rs @@ -61,6 +61,8 @@ pub struct MySqlConnectOptions { pub(crate) database: Option, pub(crate) ssl_mode: MySqlSslMode, pub(crate) ssl_ca: Option, + pub(crate) ssl_client_cert: Option, + pub(crate) ssl_client_key: Option, pub(crate) statement_cache_capacity: usize, pub(crate) charset: String, pub(crate) collation: Option, @@ -88,6 +90,8 @@ impl MySqlConnectOptions { collation: None, ssl_mode: MySqlSslMode::Preferred, ssl_ca: None, + ssl_client_cert: None, + ssl_client_key: None, statement_cache_capacity: 100, log_settings: Default::default(), pipes_as_concat: true, @@ -186,6 +190,36 @@ impl MySqlConnectOptions { self } + /// Sets the name of a file containing SSL client certificate. + /// + /// # Example + /// + /// ```rust + /// # use sqlx_core::mysql::{MySqlSslMode, MySqlConnectOptions}; + /// let options = MySqlConnectOptions::new() + /// .ssl_mode(MySqlSslMode::VerifyCa) + /// .ssl_client_cert("path/to/client.crt"); + /// ``` + pub fn ssl_client_cert(mut self, cert: impl AsRef) -> Self { + self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf())); + self + } + + /// Sets the name of a file containing SSL client key. + /// + /// # Example + /// + /// ```rust + /// # use sqlx_core::mysql::{MySqlSslMode, MySqlConnectOptions}; + /// let options = MySqlConnectOptions::new() + /// .ssl_mode(MySqlSslMode::VerifyCa) + /// .ssl_client_key("path/to/client.key"); + /// ``` + pub fn ssl_client_key(mut self, key: impl AsRef) -> Self { + self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf())); + self + } + /// Sets the capacity of the connection's statement cache in a number of stored /// distinct statements. Caching is handled using LRU, meaning when the /// amount of queries hits the defined limit, the oldest statement will get diff --git a/sqlx-mysql/src/options/parse.rs b/sqlx-mysql/src/options/parse.rs index 854a95c427..0ecbba5896 100644 --- a/sqlx-mysql/src/options/parse.rs +++ b/sqlx-mysql/src/options/parse.rs @@ -59,6 +59,10 @@ impl MySqlConnectOptions { options = options.collation(&*value); } + "sslcert" => options = options.ssl_client_cert(&*value), + + "sslkey" => options = options.ssl_client_key(&*value), + "statement-cache-capacity" => { options = options.statement_cache_capacity(value.parse().map_err(Error::config)?); diff --git a/sqlx-postgres/src/options/mod.rs b/sqlx-postgres/src/options/mod.rs index 5c2e47f755..0f1972f92d 100644 --- a/sqlx-postgres/src/options/mod.rs +++ b/sqlx-postgres/src/options/mod.rs @@ -347,8 +347,8 @@ impl PgConnectOptions { /// .ssl_mode(PgSslMode::VerifyCa) /// .ssl_client_key("./client.key"); /// ``` - pub fn ssl_client_key(mut self, cert: impl AsRef) -> Self { - self.ssl_client_key = Some(CertificateInput::File(cert.as_ref().to_path_buf())); + pub fn ssl_client_key(mut self, key: impl AsRef) -> Self { + self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf())); self } From 115e7552bccf2b1f2b18ed97434fe2e274d7ade1 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 1 May 2022 10:58:48 +0200 Subject: [PATCH 03/22] Add client ssl tests for PostgreSQL --- sqlx-postgres/src/options/parse.rs | 4 +-- tests/docker-compose.yml | 50 ++++++++++++++++++++++++------ tests/docker.py | 5 ++- tests/x.py | 10 ++++++ 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/sqlx-postgres/src/options/parse.rs b/sqlx-postgres/src/options/parse.rs index a0bed01cd5..4c5cf41c3e 100644 --- a/sqlx-postgres/src/options/parse.rs +++ b/sqlx-postgres/src/options/parse.rs @@ -53,9 +53,9 @@ impl PgConnectOptions { options = options.ssl_root_cert(&*value); } - "sslcert" => options = options.ssl_client_cert(&*value), + "sslcert" | "ssl-cert" => options = options.ssl_client_cert(&*value), - "sslkey" => options = options.ssl_client_key(&*value), + "sslkey" | "ssl-key" => options = options.ssl_client_key(&*value), "statement-cache-capacity" => { options = diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 1a19a7c716..076fb64462 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -117,6 +117,23 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + postgres_14_client_ssl: + build: + context: . + dockerfile: postgres/Dockerfile + args: + VERSION: 14 + ports: + - 5432 + environment: + POSTGRES_DB: sqlx + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_INITDB_ARGS: --auth-host=trust + volumes: + - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + command: > + -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf + postgres_13: build: context: . @@ -136,7 +153,7 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key - postgres_13_cert: + postgres_13_client_ssl: build: context: . dockerfile: postgres/Dockerfile @@ -146,10 +163,8 @@ services: - 5432 environment: POSTGRES_DB: sqlx - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_HOST_AUTH_METHOD: scram-sha-256 - POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_INITDB_ARGS: --auth-host=trust volumes: - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" command: > @@ -174,7 +189,7 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key - postgres_12_cert: + postgres_12_client_ssl: build: context: . dockerfile: postgres/Dockerfile @@ -184,10 +199,8 @@ services: - 5432 environment: POSTGRES_DB: sqlx - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_HOST_AUTH_METHOD: scram-sha-256 - POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256 + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_INITDB_ARGS: --auth-host=trust volumes: - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" command: > @@ -211,3 +224,20 @@ services: - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + + postgres_11_client_ssl: + build: + context: . + dockerfile: postgres/Dockerfile + args: + VERSION: 11 + ports: + - 5432 + environment: + POSTGRES_DB: sqlx + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_INITDB_ARGS: --auth-host=trust + volumes: + - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + command: > + -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf diff --git a/tests/docker.py b/tests/docker.py index e664c38c6e..8af0342da3 100644 --- a/tests/docker.py +++ b/tests/docker.py @@ -61,7 +61,10 @@ def start_database(driver, database, cwd): return f"mysql://root:password@127.0.0.1:{port}/{database}" elif driver.startswith("postgres"): - return f"postgres://postgres:password@localhost:{port}/{database}" + if driver.endswith("client_ssl"): + return f"postgres://postgres@localhost:{port}/{database}" + else: + return f"postgres://postgres:password@localhost:{port}/{database}" elif driver.startswith("mssql"): return f"mssql://sa:Password123!@127.0.0.1:{port}/{database}" diff --git a/tests/x.py b/tests/x.py index e5cca2971f..833428a20b 100755 --- a/tests/x.py +++ b/tests/x.py @@ -187,6 +187,16 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}", ) + ## +client-ssl + for version in ["14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl", "10_client_ssl", "9_6_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-{tls}", + comment=f"test postgres {version} no-password", + database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"postgres_{version}", + tag=f"postgres_{version}_no_password" if runtime == "async-std" else f"postgres_{version}_no_password_{runtime}", + ) + # # mysql # From 33cc7b2b5616248a862f23bf14cba0718a1bea8a Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 May 2022 15:06:40 +0200 Subject: [PATCH 04/22] Add client ssl tests for MariaDB and MySQL --- sqlx-mysql/src/options/parse.rs | 8 +-- tests/.dockerignore | 1 + tests/docker-compose.yml | 87 +++++++++++++++++++++++++++++++++ tests/docker.py | 24 +++++++-- tests/mysql/Dockerfile | 15 ++++++ tests/mysql/my.cnf | 4 ++ tests/x.py | 22 ++++++++- 7 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 tests/mysql/Dockerfile create mode 100644 tests/mysql/my.cnf diff --git a/sqlx-mysql/src/options/parse.rs b/sqlx-mysql/src/options/parse.rs index 0ecbba5896..5ba5c3207a 100644 --- a/sqlx-mysql/src/options/parse.rs +++ b/sqlx-mysql/src/options/parse.rs @@ -43,11 +43,11 @@ impl MySqlConnectOptions { for (key, value) in url.query_pairs().into_iter() { match &*key { - "ssl-mode" => { + "sslmode" | "ssl-mode" => { options = options.ssl_mode(value.parse().map_err(Error::config)?); } - "ssl-ca" => { + "sslca" | "ssl-ca" => { options = options.ssl_ca(&*value); } @@ -59,9 +59,9 @@ impl MySqlConnectOptions { options = options.collation(&*value); } - "sslcert" => options = options.ssl_client_cert(&*value), + "sslcert" | "ssl-cert" => options = options.ssl_client_cert(&*value), - "sslkey" => options = options.ssl_client_key(&*value), + "sslkey" | "ssl-key" => options = options.ssl_client_key(&*value), "statement-cache-capacity" => { options = diff --git a/tests/.dockerignore b/tests/.dockerignore index f1c67fa243..ca8cb8cf84 100644 --- a/tests/.dockerignore +++ b/tests/.dockerignore @@ -1,6 +1,7 @@ * !certs/* !keys/* +!mysql/my.cnf !mssql/*.sh !postgres/pg_hba.conf !*/*.sql diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 076fb64462..7138ccf403 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -19,6 +19,21 @@ services: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + mysql_8_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mysql:8.0.27 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MYSQL_ROOT_HOST: '%' + MYSQL_DATABASE: sqlx + MYSQL_ALLOW_EMPTY_PASSWORD: 1 + mysql_5_7: image: mysql:5.7 volumes: @@ -29,6 +44,22 @@ services: MYSQL_ROOT_HOST: '%' MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + + mysql_5_7_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mysql:5.7 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MYSQL_ROOT_HOST: '%' + MYSQL_DATABASE: sqlx + MYSQL_ALLOW_EMPTY_PASSWORD: 1 + # # MariaDB 10.6, 10.5, 10.4, 10.3 # https://mariadb.org/about/#maintenance-policy @@ -44,6 +75,20 @@ services: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + mariadb_10_6_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mariadb:10.6 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MARIADB_DATABASE: sqlx + MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1 + mariadb_10_5: image: mariadb:10.5 volumes: @@ -54,6 +99,20 @@ services: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + mariadb_10_5_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mariadb:10.5 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MARIADB_DATABASE: sqlx + MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1 + mariadb_10_4: image: mariadb:10.4 volumes: @@ -64,6 +123,20 @@ services: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + mariadb_10_4_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mariadb:10.4 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MARIADB_DATABASE: sqlx + MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1 + mariadb_10_3: image: mariadb:10.3 volumes: @@ -74,6 +147,20 @@ services: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: sqlx + mariadb_10_3_client_ssl: + build: + context: . + dockerfile: mysql/Dockerfile + args: + IMAGE: mariadb:10.3 + volumes: + - "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + ports: + - 3306 + environment: + MARIADB_DATABASE: sqlx + MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1 + # # PostgreSQL 15.x, 14.x, 13.x, 12.x, 11.x # https://www.postgresql.org/support/versioning/ diff --git a/tests/docker.py b/tests/docker.py index 8af0342da3..145376d8d4 100644 --- a/tests/docker.py +++ b/tests/docker.py @@ -56,15 +56,29 @@ def start_database(driver, database, cwd): port = int(res.stdout[1:-2].decode()) + # need additional permissions to connect to MySQL when using SSL + res = subprocess.run( + ["docker", "exec", f"sqlx_{driver}_1", "mysql", "-u", "root", "-e", "GRANT ALL PRIVILEGES ON *.* TO 'root' WITH GRANT OPTION;"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=dir_tests, + ) + + if res.returncode != 0: + print(res.stderr, file=sys.stderr) + + # do not set password in URL if authenticating using SSL key file + if driver.endswith("client_ssl"): + password = "" + else: + password = ":password" + # construct appropriate database URL if driver.startswith("mysql") or driver.startswith("mariadb"): - return f"mysql://root:password@127.0.0.1:{port}/{database}" + return f"mysql://root{password}@localhost:{port}/{database}" elif driver.startswith("postgres"): - if driver.endswith("client_ssl"): - return f"postgres://postgres@localhost:{port}/{database}" - else: - return f"postgres://postgres:password@localhost:{port}/{database}" + return f"postgres://postgres{password}@localhost:{port}/{database}" elif driver.startswith("mssql"): return f"mssql://sa:Password123!@127.0.0.1:{port}/{database}" diff --git a/tests/mysql/Dockerfile b/tests/mysql/Dockerfile new file mode 100644 index 0000000000..fab69139ca --- /dev/null +++ b/tests/mysql/Dockerfile @@ -0,0 +1,15 @@ +ARG IMAGE +FROM ${IMAGE} + +# Copy SSL certificate (and key) +COPY certs/server.crt /etc/mysql/ssl/server.crt +COPY certs/ca.crt /etc/mysql/ssl/ca.crt +COPY keys/server.key /etc/mysql/ssl/server.key +COPY mysql/my.cnf /etc/mysql/my.cnf + +# Fix permissions +RUN chown mysql:mysql /etc/mysql/ssl/server.crt /etc/mysql/ssl/server.key +RUN chmod 0600 /etc/mysql/ssl/server.crt /etc/mysql/ssl/server.key + +# Create dir for secure-file-priv +RUN mkdir -p /var/lib/mysql-files diff --git a/tests/mysql/my.cnf b/tests/mysql/my.cnf new file mode 100644 index 0000000000..0e0f6c4125 --- /dev/null +++ b/tests/mysql/my.cnf @@ -0,0 +1,4 @@ +[mysqld] +ssl-ca=/etc/mysql/ssl/ca.crt +ssl-cert=/etc/mysql/ssl/server.crt +ssl-key=/etc/mysql/ssl/server.key diff --git a/tests/x.py b/tests/x.py index 833428a20b..c489a691e3 100755 --- a/tests/x.py +++ b/tests/x.py @@ -188,7 +188,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ) ## +client-ssl - for version in ["14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl", "10_client_ssl", "9_6_client_ssl"]: + for version in ["14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl", "10_client_ssl"]: run( f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-{tls}", comment=f"test postgres {version} no-password", @@ -209,6 +209,16 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}", ) + ## +client-ssl + for version in ["8_client_ssl", "5_7_client_ssl", "5_6_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", + comment=f"test mysql {version} no-password", + database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"mysql_{version}", + tag=f"mysql_{version}_no_password" if runtime == "async-std" else f"mysql_{version}_no_password_{runtime}", + ) + # # mariadb # @@ -221,5 +231,15 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}", ) + ## +client-ssl + for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl", "10_2_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", + comment=f"test mariadb {version} no-password", + database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"mariadb_{version}", + tag=f"mariadb_{version}_no_password" if runtime == "async-std" else f"mariadb_{version}_no_password_{runtime}", + ) + # TODO: Use [grcov] if available # ~/.cargo/bin/grcov tests/.cache/target/debug -s sqlx-core/ -t html --llvm --branch -o ./target/debug/coverage From 816f457547bcf8e5cb34690ee05943ac773e1850 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 6 May 2022 12:09:44 +0200 Subject: [PATCH 05/22] Adapt GA tests --- .github/workflows/sqlx.yml | 122 +++++++++++++------------------------ 1 file changed, 44 insertions(+), 78 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 809793cd86..8e82a3d133 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -232,92 +232,24 @@ jobs: # but `PgLTree` should just fall back to text format RUSTFLAGS: --cfg postgres_${{ matrix.postgres }} - postgres_native_cert: - name: Postgres Openssl Certificate Authentication - runs-on: ubuntu-20.04 - strategy: - matrix: - postgres: [12, 10, 9_6, 9_5] - runtime: [async-std-native-tls, tokio-native-tls, actix-native-tls] - needs: check - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }} - - - uses: actions-rs/cargo@v1 - with: - command: build - args: > - --features postgres,openssl,all-types,runtime-${{ matrix.runtime }} + # client SSL authentication - - run: docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 postgres_${{ matrix.postgres }}_cert - - run: sleep 10 - - - uses: actions-rs/cargo@v1 - with: - command: test - args: > - --no-default-features - --features any,postgres,openssl,macros,migrate,all-types,runtime-${{ matrix.runtime }} - env: - DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslcert=.%2Ftests%2Fcerts%2Fclient.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key - - - postgres_cert: - name: Postgres Rustls Certificate Authentication - runs-on: ubuntu-20.04 - strategy: - matrix: - postgres: [12, 10, 9_6, 9_5] - runtime: [async-std-rustls, tokio-rustls, actix-rustls] - needs: check - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ hashFiles('**/Cargo.lock') }} - - - uses: actions-rs/cargo@v1 - with: - command: build - args: > - --features postgres,all-types,runtime-${{ matrix.runtime }} - - - run: docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 postgres_${{ matrix.postgres }}_cert - - run: sleep 10 + - run: | + docker-compose -f tests/docker-compose.yml stop postgres_${{ matrix.postgres }} + docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }}_client_ssl postgres_${{ matrix.postgres }}_client_ssl + docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c "until pg_isready; do sleep 1; done" - uses: actions-rs/cargo@v1 with: command: test args: > --no-default-features - --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }} + --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} env: - DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslcert=.%2Ftests%2Fcerts%2Fclient.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key + DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt + # FIXME: needed to disable `ltree` tests in Postgres 9.6 + # but `PgLTree` should just fall back to text format + RUSTFLAGS: --cfg postgres_${{ matrix.postgres }}_client_ssl mysql: name: MySQL @@ -372,6 +304,23 @@ jobs: DATABASE_URL: mysql://root:password@localhost:3306/sqlx RUSTFLAGS: --cfg mysql_${{ matrix.mysql }} + # client SSL authentication + + - run: | + docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} + docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl + sleep 60 + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --no-default-features + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + env: + DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt + RUSTFLAGS: --cfg mysql_${{ matrix.mysql }} + mariadb: name: MariaDB runs-on: ubuntu-20.04 @@ -412,3 +361,20 @@ jobs: env: DATABASE_URL: mysql://root:password@localhost:3306/sqlx RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }} + + # client SSL authentication + + - run: | + docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} + docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl + sleep 60 + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --no-default-features + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + env: + DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt + RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }} From f31554f408949f3b5daaea8d1149a3cf74b4e794 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 19 Jul 2022 08:18:23 +0200 Subject: [PATCH 06/22] Fix RUSTFLAGS to run all tests --- .github/workflows/sqlx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 8e82a3d133..2afd1a0ca0 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -249,7 +249,7 @@ jobs: DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt # FIXME: needed to disable `ltree` tests in Postgres 9.6 # but `PgLTree` should just fall back to text format - RUSTFLAGS: --cfg postgres_${{ matrix.postgres }}_client_ssl + RUSTFLAGS: --cfg postgres_${{ matrix.postgres }} mysql: name: MySQL From 227515237270a8aa34cd306f8ea0950be0a9b2fa Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 19 Jul 2022 10:00:06 +0200 Subject: [PATCH 07/22] Remove containers to free the DB port before running SSL auth tests --- .github/workflows/sqlx.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 2afd1a0ca0..703317ba53 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -236,6 +236,7 @@ jobs: - run: | docker-compose -f tests/docker-compose.yml stop postgres_${{ matrix.postgres }} + docker-compose -f tests/docker-compose.yml rm postgres_${{ matrix.postgres }} docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }}_client_ssl postgres_${{ matrix.postgres }}_client_ssl docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c "until pg_isready; do sleep 1; done" @@ -308,6 +309,7 @@ jobs: - run: | docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} + docker-compose -f tests/docker-compose.yml rm mysql_${{ matrix.mysql }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl sleep 60 @@ -366,6 +368,7 @@ jobs: - run: | docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} + docker-compose -f tests/docker-compose.yml rm mysql_${{ matrix.mysql }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl sleep 60 From d93faf307c4178ef84965f5860f31fb03a121a85 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 23 Jul 2022 18:59:41 +0200 Subject: [PATCH 08/22] Fix CI bad naming --- .github/workflows/sqlx.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 703317ba53..fb83c9a609 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -367,9 +367,9 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} - docker-compose -f tests/docker-compose.yml rm mysql_${{ matrix.mysql }} - docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl + docker-compose -f tests/docker-compose.yml stop mariadb_${{ matrix.mariadb }} + docker-compose -f tests/docker-compose.yml rm mariadb_${{ matrix.mariadb }} + docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }}_client_ssl sleep 60 - uses: actions-rs/cargo@v1 From 63c1ac0a9b7535ef992598adc700278b2f9d9d61 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 20 Aug 2022 17:47:58 +0200 Subject: [PATCH 09/22] Use docker-compose down to remove also the network --- .github/workflows/sqlx.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index fb83c9a609..78e18e3129 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -235,8 +235,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml stop postgres_${{ matrix.postgres }} - docker-compose -f tests/docker-compose.yml rm postgres_${{ matrix.postgres }} + docker-compose -f tests/docker-compose.yml down postgres_${{ matrix.postgres }} docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }}_client_ssl postgres_${{ matrix.postgres }}_client_ssl docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c "until pg_isready; do sleep 1; done" @@ -308,8 +307,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml stop mysql_${{ matrix.mysql }} - docker-compose -f tests/docker-compose.yml rm mysql_${{ matrix.mysql }} + docker-compose -f tests/docker-compose.yml down mysql_${{ matrix.mysql }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl sleep 60 @@ -367,8 +365,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml stop mariadb_${{ matrix.mariadb }} - docker-compose -f tests/docker-compose.yml rm mariadb_${{ matrix.mariadb }} + docker-compose -f tests/docker-compose.yml down mariadb_${{ matrix.mariadb }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }}_client_ssl sleep 60 From d24ee0b8b10b8bb9fe3be9865a2c2415cd53631c Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 20 Aug 2022 18:13:03 +0200 Subject: [PATCH 10/22] Fix main rebase --- tests/x.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/x.py b/tests/x.py index c489a691e3..e92c109109 100755 --- a/tests/x.py +++ b/tests/x.py @@ -210,7 +210,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ) ## +client-ssl - for version in ["8_client_ssl", "5_7_client_ssl", "5_6_client_ssl"]: + for version in ["8_client_ssl", "5_7_client_ssl"]: run( f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", comment=f"test mysql {version} no-password", @@ -223,7 +223,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data # mariadb # - for version in ["10_6", "10_5", "10_4", "10_3", "10_2"]: + for version in ["10_6", "10_5", "10_4", "10_3"]: run( f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", comment=f"test mariadb {version}", @@ -232,7 +232,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ) ## +client-ssl - for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl", "10_2_client_ssl"]: + for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl"]: run( f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", comment=f"test mariadb {version} no-password", From 993248a4dc9613075553ae2e61532b277ea5578a Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 23 Aug 2022 10:03:37 +0200 Subject: [PATCH 11/22] Stop trying to stop service using docker-compose, simply use docker cmd --- .github/workflows/sqlx.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 78e18e3129..f0342a6573 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -235,7 +235,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml down postgres_${{ matrix.postgres }} + docker stop postgres_${{ matrix.postgres }} docker-compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }}_client_ssl postgres_${{ matrix.postgres }}_client_ssl docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c "until pg_isready; do sleep 1; done" @@ -307,7 +307,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml down mysql_${{ matrix.mysql }} + docker stop mysql_${{ matrix.mysql }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl sleep 60 @@ -365,7 +365,7 @@ jobs: # client SSL authentication - run: | - docker-compose -f tests/docker-compose.yml down mariadb_${{ matrix.mariadb }} + docker stop mariadb_${{ matrix.mariadb }} docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }}_client_ssl sleep 60 From 68b96ae3dd63e559b08827d1541bdd3729a7a30b Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 13 Sep 2022 18:42:59 +0200 Subject: [PATCH 12/22] Fix RUSTFLAGS for Postgres --- .github/workflows/sqlx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index f0342a6573..9469629b85 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -249,7 +249,7 @@ jobs: DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt # FIXME: needed to disable `ltree` tests in Postgres 9.6 # but `PgLTree` should just fall back to text format - RUSTFLAGS: --cfg postgres_${{ matrix.postgres }} + RUSTFLAGS: --cfg postgres_${{ matrix.postgres }}_client_ssl mysql: name: MySQL From d23e2f3ebf05d23565e6a88ea5d9a626f197d312 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Wed, 14 Sep 2022 09:20:38 +0200 Subject: [PATCH 13/22] Name the Docker images for MariaDB and MySQL so we can stop them using their name --- .github/workflows/sqlx.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 9469629b85..1ae3694982 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -279,7 +279,7 @@ jobs: args: > --features mysql,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} - - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }} + - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mysql_${{ matrix.mysql }} mysql_${{ matrix.mysql }} - run: sleep 60 - uses: actions-rs/cargo@v1 @@ -308,7 +308,7 @@ jobs: - run: | docker stop mysql_${{ matrix.mysql }} - docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mysql_${{ matrix.mysql }}_client_ssl + docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mysql_${{ matrix.mysql }}_client_ssl mysql_${{ matrix.mysql }}_client_ssl sleep 60 - uses: actions-rs/cargo@v1 @@ -349,7 +349,7 @@ jobs: args: > --features mysql,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} - - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }} + - run: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mariadb_${{ matrix.mariadb }} mariadb_${{ matrix.mariadb }} - run: sleep 30 - uses: actions-rs/cargo@v1 @@ -366,7 +366,7 @@ jobs: - run: | docker stop mariadb_${{ matrix.mariadb }} - docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 mariadb_${{ matrix.mariadb }}_client_ssl + docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mariadb_${{ matrix.mariadb }}_client_ssl mariadb_${{ matrix.mariadb }}_client_ssl sleep 60 - uses: actions-rs/cargo@v1 From 2e6656a6b96874acc8609ac04994dc5d9596f8a5 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 15 Sep 2022 08:51:56 +0200 Subject: [PATCH 14/22] Add the exception for mysql 5.7 not supporting compatible TLS version with RusTLS --- .github/workflows/sqlx.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 1ae3694982..375d140106 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -311,7 +311,9 @@ jobs: docker-compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mysql_${{ matrix.mysql }}_client_ssl mysql_${{ matrix.mysql }}_client_ssl sleep 60 + # MySQL 5.7 supports TLS but not TLSv1.3 as required by RusTLS. - uses: actions-rs/cargo@v1 + if: ${{ !(matrix.mysql == '5_7' && matrix.tls == 'rustls') }} with: command: test args: > From 363a72f52354ce768d93ecd3cbe4cf1e1e3c9418 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 4 Feb 2023 17:12:13 +0100 Subject: [PATCH 15/22] Rebase fixes --- sqlx-core/src/net/tls/tls_native_tls.rs | 3 +- sqlx-core/src/net/tls/tls_rustls.rs | 79 +++++++++++++++++-------- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/sqlx-core/src/net/tls/tls_native_tls.rs b/sqlx-core/src/net/tls/tls_native_tls.rs index 8c5eeb10da..1c40b4b01f 100644 --- a/sqlx-core/src/net/tls/tls_native_tls.rs +++ b/sqlx-core/src/net/tls/tls_native_tls.rs @@ -57,8 +57,7 @@ pub async fn handshake( if let (Some(cert_path), Some(key_path)) = (config.client_cert_path, config.client_key_path) { let cert_path = cert_path.data().await?; let key_path = key_path.data().await?; - let identity = - Identity::from_pkcs8(&cert_path, &key_path).map_err(|e| Error::Tls(e.into()))?; + let identity = Identity::from_pkcs8(&cert_path, &key_path).map_err(Error::tls)?; builder.identity(identity); } diff --git a/sqlx-core/src/net/tls/tls_rustls.rs b/sqlx-core/src/net/tls/tls_rustls.rs index c1c9f46ce0..8b98559055 100644 --- a/sqlx-core/src/net/tls/tls_rustls.rs +++ b/sqlx-core/src/net/tls/tls_rustls.rs @@ -1,6 +1,5 @@ use futures_util::future; -use std::io; -use std::io::{Cursor, Read, Write}; +use std::io::{self, BufReader, Cursor, Read, Write}; use std::sync::Arc; use std::task::{Context, Poll}; use std::time::SystemTime; @@ -48,7 +47,7 @@ impl Socket for RustlsSocket { match self.state.writer().write(buf) { // Returns a zero-length write when the buffer is full. Ok(0) => Err(io::ErrorKind::WouldBlock.into()), - other => return other, + other => other, } } @@ -81,10 +80,32 @@ where { let config = ClientConfig::builder().with_safe_defaults(); + // authentication using user's key and its associated certificate + let user_auth = match (tls_config.client_cert_path, tls_config.client_key_path) { + (Some(cert_path), Some(key_path)) => { + let cert_chain = certs_from_pem(cert_path.data().await?)?; + let key_der = private_key_from_pem(key_path.data().await?)?; + Some((cert_chain, key_der)) + } + (None, None) => None, + (_, _) => { + return Err(Error::Configuration( + "user auth key and certs must be given together".into(), + )) + } + }; + let config = if tls_config.accept_invalid_certs { - config - .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier)) - .with_no_client_auth() + if let Some(user_auth) = user_auth { + config + .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier)) + .with_single_cert(user_auth.0, user_auth.1) + .map_err(Error::tls)? + } else { + config + .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier)) + .with_no_client_auth() + } } else { let mut cert_store = RootCertStore::empty(); cert_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { @@ -100,7 +121,7 @@ where let mut cursor = Cursor::new(data); for cert in rustls_pemfile::certs(&mut cursor) - .map_err(|_| Error::Tls(format!("Invalid certificate {}", ca).into()))? + .map_err(|_| Error::Tls(format!("Invalid certificate {ca}").into()))? { cert_store .add(&rustls::Certificate(cert)) @@ -108,21 +129,6 @@ where } } - // authentication using user's key and its associated certificate - let user_auth = match (tls_config.client_cert_path, tls_config.client_key_path) { - (Some(cert_path), Some(key_path)) => { - let cert_chain = certs_from_pem(cert_path.data().await?)?; - let key_der = private_key_from_pem(key_path.data().await?)?; - Some((cert_chain, key_der)) - } - (None, None) => None, - (_, _) => { - return Err(Error::Configuration( - "user auth key and certs must be given together".into(), - )) - } - }; - if tls_config.accept_invalid_hostnames { let verifier = WebPkiVerifier::new(cert_store, None); @@ -130,7 +136,7 @@ where config .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) .with_single_cert(user_auth.0, user_auth.1) - .map_err(|err| Error::Tls(err.into()))? + .map_err(Error::tls)? } else { config .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) @@ -140,7 +146,7 @@ where config .with_root_certificates(cert_store) .with_single_cert(user_auth.0, user_auth.1) - .map_err(|err| Error::Tls(err.into()))? + .map_err(Error::tls)? } else { config .with_root_certificates(cert_store) @@ -162,6 +168,31 @@ where Ok(socket) } +fn certs_from_pem(pem: Vec) -> Result, Error> { + let cur = Cursor::new(pem); + let mut reader = BufReader::new(cur); + rustls_pemfile::certs(&mut reader)? + .into_iter() + .map(|v| Ok(rustls::Certificate(v))) + .collect() +} + +fn private_key_from_pem(pem: Vec) -> Result { + let cur = Cursor::new(pem); + let mut reader = BufReader::new(cur); + + loop { + match rustls_pemfile::read_one(&mut reader)? { + Some(rustls_pemfile::Item::RSAKey(key)) => return Ok(rustls::PrivateKey(key)), + Some(rustls_pemfile::Item::PKCS8Key(key)) => return Ok(rustls::PrivateKey(key)), + None => break, + _ => {} + } + } + + Err(Error::Configuration("no keys found pem file".into())) +} + struct DummyTlsVerifier; impl ServerCertVerifier for DummyTlsVerifier { From 4b7c54a477455108cff43047a774aee5f4988a45 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 4 Feb 2023 22:43:43 +0100 Subject: [PATCH 16/22] Set correctly tls struct (fix merge) --- sqlx-mysql/src/connection/tls.rs | 2 ++ sqlx-postgres/src/connection/tls.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sqlx-mysql/src/connection/tls.rs b/sqlx-mysql/src/connection/tls.rs index b8cb05c9d3..f98c5c532f 100644 --- a/sqlx-mysql/src/connection/tls.rs +++ b/sqlx-mysql/src/connection/tls.rs @@ -64,6 +64,8 @@ pub(super) async fn maybe_upgrade( accept_invalid_hostnames: !matches!(options.ssl_mode, MySqlSslMode::VerifyIdentity), hostname: &options.host, root_cert_path: options.ssl_ca.as_ref(), + client_cert_path: options.ssl_client_cert.as_ref(), + client_key_path: options.ssl_client_key.as_ref(), }; // Request TLS upgrade diff --git a/sqlx-postgres/src/connection/tls.rs b/sqlx-postgres/src/connection/tls.rs index b9e40d90dc..04bab793a7 100644 --- a/sqlx-postgres/src/connection/tls.rs +++ b/sqlx-postgres/src/connection/tls.rs @@ -58,6 +58,8 @@ async fn maybe_upgrade( accept_invalid_hostnames, hostname: &options.host, root_cert_path: options.ssl_root_cert.as_ref(), + client_cert_path: options.ssl_client_cert.as_ref(), + client_key_path: options.ssl_client_key.as_ref(), }; tls::handshake(socket, config, SocketIntoBox).await From 1a77523c6c04b2e8f4fe18c969be03274836b473 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 6 Feb 2023 11:04:47 +0100 Subject: [PATCH 17/22] Handle Elliptic Curve variant for private key --- sqlx-core/src/net/tls/tls_rustls.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sqlx-core/src/net/tls/tls_rustls.rs b/sqlx-core/src/net/tls/tls_rustls.rs index 8b98559055..ab0f721f79 100644 --- a/sqlx-core/src/net/tls/tls_rustls.rs +++ b/sqlx-core/src/net/tls/tls_rustls.rs @@ -1,4 +1,5 @@ use futures_util::future; +use rustls::{Certificate, PrivateKey}; use std::io::{self, BufReader, Cursor, Read, Write}; use std::sync::Arc; use std::task::{Context, Poll}; @@ -12,7 +13,7 @@ use rustls::{ use crate::error::Error; use crate::io::ReadBuf; use crate::net::tls::util::StdSocket; -use crate::net::tls::TlsConfig; +use crate::net::tls::{CertificateInput, TlsConfig}; use crate::net::Socket; pub struct RustlsSocket { @@ -183,8 +184,11 @@ fn private_key_from_pem(pem: Vec) -> Result { loop { match rustls_pemfile::read_one(&mut reader)? { - Some(rustls_pemfile::Item::RSAKey(key)) => return Ok(rustls::PrivateKey(key)), - Some(rustls_pemfile::Item::PKCS8Key(key)) => return Ok(rustls::PrivateKey(key)), + Some( + rustls_pemfile::Item::RSAKey(key) + | rustls_pemfile::Item::PKCS8Key(key) + | rustls_pemfile::Item::ECKey(key), + ) => return Ok(rustls::PrivateKey(key)), None => break, _ => {} } From 1862c923bfb56dff75397d88b7f6a10b58d5e11f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 7 Feb 2023 10:57:30 +0100 Subject: [PATCH 18/22] Fix tests suite --- .github/workflows/sqlx.yml | 6 +-- tests/x.py | 81 ++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 375d140106..6ccc8704bf 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -244,7 +244,7 @@ jobs: command: test args: > --no-default-features - --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt # FIXME: needed to disable `ltree` tests in Postgres 9.6 @@ -318,7 +318,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt RUSTFLAGS: --cfg mysql_${{ matrix.mysql }} @@ -376,7 +376,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }}-${{ matrix.tls }} + --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }} diff --git a/tests/x.py b/tests/x.py index e92c109109..455b89944b 100755 --- a/tests/x.py +++ b/tests/x.py @@ -142,7 +142,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for runtime in ["async-std", "tokio"]: for tls in ["native-tls", "rustls", "none"]: run( - f"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features json,offline,migrate,_rt-{runtime},_tls-{tls}", + f"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features json,_rt-{runtime},_tls-{tls}", comment="unit test core", tag=f"unit_{runtime}_{tls}" ) @@ -171,31 +171,32 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for version in ["15", "14", "13", "12", "11"]: run( - f"cargo test --no-default-features --features macros,any,unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", comment=f"test postgres {version}", service=f"postgres_{version}", tag=f"postgres_{version}" if runtime == "async-std" else f"postgres_{version}_{runtime}", ) - ## +ssl - for version in ["15", "14", "13", "12", "11"]: - run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", - comment=f"test postgres {version} ssl", - database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt", - service=f"postgres_{version}", - tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}", - ) - - ## +client-ssl - for version in ["14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl", "10_client_ssl"]: - run( - f"cargo test --no-default-features --features macros,offline,any,all-types,postgres,runtime-{runtime}-{tls}", - comment=f"test postgres {version} no-password", - database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"postgres_{version}", - tag=f"postgres_{version}_no_password" if runtime == "async-std" else f"postgres_{version}_no_password_{runtime}", - ) + if tls != "none": + ## +ssl + for version in ["15", "14", "13", "12", "11"]: + run( + f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + comment=f"test postgres {version} ssl", + database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt", + service=f"postgres_{version}", + tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}", + ) + + ## +client-ssl + for version in ["15_client_ssl", "14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + comment=f"test postgres {version} no-password", + database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"postgres_{version}", + tag=f"postgres_{version}_no_password" if runtime == "async-std" else f"postgres_{version}_no_password_{runtime}", + ) # # mysql @@ -209,15 +210,16 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}", ) - ## +client-ssl - for version in ["8_client_ssl", "5_7_client_ssl"]: - run( - f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", - comment=f"test mysql {version} no-password", - database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"mysql_{version}", - tag=f"mysql_{version}_no_password" if runtime == "async-std" else f"mysql_{version}_no_password_{runtime}", - ) + if tls != "none": + ## +client-ssl + for version in ["8_client_ssl", "5_7_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + comment=f"test mysql {version} no-password", + database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"mysql_{version}", + tag=f"mysql_{version}_no_password" if runtime == "async-std" else f"mysql_{version}_no_password_{runtime}", + ) # # mariadb @@ -231,15 +233,16 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}", ) - ## +client-ssl - for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl"]: - run( - f"cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-{runtime}-{tls}", - comment=f"test mariadb {version} no-password", - database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"mariadb_{version}", - tag=f"mariadb_{version}_no_password" if runtime == "async-std" else f"mariadb_{version}_no_password_{runtime}", - ) + if tls != "none": + ## +client-ssl + for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl"]: + run( + f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + comment=f"test mariadb {version} no-password", + database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", + service=f"mariadb_{version}", + tag=f"mariadb_{version}_no_password" if runtime == "async-std" else f"mariadb_{version}_no_password_{runtime}", + ) # TODO: Use [grcov] if available # ~/.cargo/bin/grcov tests/.cache/target/debug -s sqlx-core/ -t html --llvm --branch -o ./target/debug/coverage From bd821b2cef02748b2d1f63206b1b680143a1ca63 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 10 Feb 2023 15:31:42 +0100 Subject: [PATCH 19/22] Fix features in CI --- .github/workflows/sqlx.yml | 6 +++--- tests/sqlite/sqlite.db | Bin 36864 -> 36864 bytes tests/x.py | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 6ccc8704bf..51f24ad0d5 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -244,7 +244,7 @@ jobs: command: test args: > --no-default-features - --features any,postgres,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} + --features any,postgres,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt # FIXME: needed to disable `ltree` tests in Postgres 9.6 @@ -318,7 +318,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} + --features any,mysql,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt RUSTFLAGS: --cfg mysql_${{ matrix.mysql }} @@ -376,7 +376,7 @@ jobs: command: test args: > --no-default-features - --features any,mysql,macros,migrate,all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} + --features any,mysql,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }} env: DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }} diff --git a/tests/sqlite/sqlite.db b/tests/sqlite/sqlite.db index 6832b724b7b03810228bad606fbefb35dcc4e6dc..e357615025e1e8b905d823110804fa9a422a92c9 100644 GIT binary patch delta 127 zcmZozz|^pSX@WE(-$WT_M!t;+OY-?x`4=+qzvaKhf1G~{|H93J0{#4If~?F8nk5;T z#R@=_s8EtxTq4MVAvF1Ty)97t3kLo_{NMRM0S$SvSy15`zXVVzBP)nt0TIj~f{B@# GffE3Z9U+?l delta 70 zcmZozz|^pSX@WE(&qNt#MxKocOY*sx`HwU3zvaKhe|)o`z)t?j$Lno@VxJiJ|L}k3 Y|Fl_9;R!z<3o`>FGl*bfW@g|703tpUmjD0& diff --git a/tests/x.py b/tests/x.py index 455b89944b..3e2b1ec4d1 100755 --- a/tests/x.py +++ b/tests/x.py @@ -142,7 +142,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for runtime in ["async-std", "tokio"]: for tls in ["native-tls", "rustls", "none"]: run( - f"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features json,_rt-{runtime},_tls-{tls}", + f"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features json,offline,migrate,_rt-{runtime},_tls-{tls}", comment="unit test core", tag=f"unit_{runtime}_{tls}" ) @@ -159,7 +159,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data # run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,sqlite,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,sqlite,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test sqlite", service="sqlite", tag=f"sqlite" if runtime == "async-std" else f"sqlite_{runtime}", @@ -171,7 +171,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for version in ["15", "14", "13", "12", "11"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test postgres {version}", service=f"postgres_{version}", tag=f"postgres_{version}" if runtime == "async-std" else f"postgres_{version}_{runtime}", @@ -181,7 +181,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ## +ssl for version in ["15", "14", "13", "12", "11"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test postgres {version} ssl", database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt", service=f"postgres_{version}", @@ -191,7 +191,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ## +client-ssl for version in ["15_client_ssl", "14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,postgres,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test postgres {version} no-password", database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt", service=f"postgres_{version}", @@ -204,7 +204,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for version in ["8", "5_7"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test mysql {version}", service=f"mysql_{version}", tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}", @@ -214,7 +214,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ## +client-ssl for version in ["8_client_ssl", "5_7_client_ssl"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test mysql {version} no-password", database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", service=f"mysql_{version}", @@ -227,7 +227,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data for version in ["10_6", "10_5", "10_4", "10_3"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test mariadb {version}", service=f"mariadb_{version}", tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}", @@ -237,7 +237,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ## +client-ssl for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl"]: run( - f"cargo test --no-default-features --features macros,any,_unstable-all-types,mysql,runtime-{runtime},tls-{tls}", + f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test mariadb {version} no-password", database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", service=f"mariadb_{version}", From 60c5cfa90070148a6e68d5174913f8bccc5c7ced Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 12 Feb 2023 10:19:35 +0100 Subject: [PATCH 20/22] Add tests for Postgres 15 + rebase --- tests/docker-compose.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index 7138ccf403..f521efb3a4 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -185,6 +185,23 @@ services: command: > -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + postgres_15_client_ssl: + build: + context: . + dockerfile: postgres/Dockerfile + args: + VERSION: 15 + ports: + - 5432 + environment: + POSTGRES_DB: sqlx + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_INITDB_ARGS: --auth-host=trust + volumes: + - "./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql" + command: > + -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf + postgres_14: build: context: . From d32139bfa1a5244c7d1a61e316f9752b743cb20f Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 12 Feb 2023 10:49:20 +0100 Subject: [PATCH 21/22] Python tests: fix exception for MySQL 5.7 + remove unneeded for loops --- tests/x.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/x.py b/tests/x.py index 3e2b1ec4d1..34360de9f0 100755 --- a/tests/x.py +++ b/tests/x.py @@ -177,9 +177,8 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"postgres_{version}" if runtime == "async-std" else f"postgres_{version}_{runtime}", ) - if tls != "none": - ## +ssl - for version in ["15", "14", "13", "12", "11"]: + if tls != "none": + ## +ssl run( f"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test postgres {version} ssl", @@ -188,14 +187,13 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"postgres_{version}_ssl" if runtime == "async-std" else f"postgres_{version}_ssl_{runtime}", ) - ## +client-ssl - for version in ["15_client_ssl", "14_client_ssl", "13_client_ssl", "12_client_ssl", "11_client_ssl"]: + ## +client-ssl run( f"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", - comment=f"test postgres {version} no-password", + comment=f"test postgres {version}_client_ssl no-password", database_url_args="sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"postgres_{version}", - tag=f"postgres_{version}_no_password" if runtime == "async-std" else f"postgres_{version}_no_password_{runtime}", + service=f"postgres_{version}_client_ssl", + tag=f"postgres_{version}_client_ssl_no_password" if runtime == "async-std" else f"postgres_{version}_client_ssl_no_password_{runtime}", ) # @@ -210,15 +208,14 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mysql_{version}" if runtime == "async-std" else f"mysql_{version}_{runtime}", ) - if tls != "none": ## +client-ssl - for version in ["8_client_ssl", "5_7_client_ssl"]: + if version != "5_7" or tls == "native-tls": run( f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", - comment=f"test mysql {version} no-password", + comment=f"test mysql {version}_client_ssl no-password", database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"mysql_{version}", - tag=f"mysql_{version}_no_password" if runtime == "async-std" else f"mysql_{version}_no_password_{runtime}", + service=f"mysql_{version}_client_ssl", + tag=f"mysql_{version}_client_ssl_no_password" if runtime == "async-std" else f"mysql_{version}_client_ssl_no_password_{runtime}", ) # @@ -233,15 +230,14 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data tag=f"mariadb_{version}" if runtime == "async-std" else f"mariadb_{version}_{runtime}", ) - if tls != "none": ## +client-ssl - for version in ["10_6_client_ssl", "10_5_client_ssl", "10_4_client_ssl", "10_3_client_ssl"]: + if tls != "none": run( f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", - comment=f"test mariadb {version} no-password", + comment=f"test mariadb {version}_client_ssl no-password", database_url_args="sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt", - service=f"mariadb_{version}", - tag=f"mariadb_{version}_no_password" if runtime == "async-std" else f"mariadb_{version}_no_password_{runtime}", + service=f"mariadb_{version}_client_ssl", + tag=f"mariadb_{version}_client_ssl_no_password" if runtime == "async-std" else f"mariadb_{version}_client_ssl_no_password_{runtime}", ) # TODO: Use [grcov] if available From 5d44ae1a7fba0fb7688f529cc9001daa92d06665 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 12 Feb 2023 14:35:34 +0100 Subject: [PATCH 22/22] CI: run SSL tests only when building with TLS support --- .github/workflows/sqlx.yml | 4 +++- tests/docker.py | 6 ------ tests/x.py | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sqlx.yml b/.github/workflows/sqlx.yml index 51f24ad0d5..3e71536a96 100644 --- a/.github/workflows/sqlx.yml +++ b/.github/workflows/sqlx.yml @@ -240,6 +240,7 @@ jobs: docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c "until pg_isready; do sleep 1; done" - uses: actions-rs/cargo@v1 + if: matrix.tls != 'none' with: command: test args: > @@ -313,7 +314,7 @@ jobs: # MySQL 5.7 supports TLS but not TLSv1.3 as required by RusTLS. - uses: actions-rs/cargo@v1 - if: ${{ !(matrix.mysql == '5_7' && matrix.tls == 'rustls') }} + if: ${{ !(matrix.mysql == '5_7' && matrix.tls == 'rustls') && matrix.tls != 'none' }} with: command: test args: > @@ -372,6 +373,7 @@ jobs: sleep 60 - uses: actions-rs/cargo@v1 + if: matrix.tls != 'none' with: command: test args: > diff --git a/tests/docker.py b/tests/docker.py index 145376d8d4..427ed98a44 100644 --- a/tests/docker.py +++ b/tests/docker.py @@ -36,9 +36,6 @@ def start_database(driver, database, cwd): elif driver.startswith("postgres"): port = 5432 - elif driver.startswith("mssql"): - port = 1433 - else: raise NotImplementedError @@ -80,8 +77,5 @@ def start_database(driver, database, cwd): elif driver.startswith("postgres"): return f"postgres://postgres{password}@localhost:{port}/{database}" - elif driver.startswith("mssql"): - return f"mssql://sa:Password123!@127.0.0.1:{port}/{database}" - else: raise NotImplementedError diff --git a/tests/x.py b/tests/x.py index 34360de9f0..a487d3986a 100755 --- a/tests/x.py +++ b/tests/x.py @@ -209,7 +209,7 @@ def run(command, comment=None, env=None, service=None, tag=None, args=None, data ) ## +client-ssl - if version != "5_7" or tls == "native-tls": + if tls != "none" and not(version == "5_7" and tls == "rustls"): run( f"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}", comment=f"test mysql {version}_client_ssl no-password",