Skip to content

Commit 0e8d22e

Browse files
authored
Merge pull request #226 from blackbeam/issue-225-ssl-query-params
Introduce SSL-related query params (fix #225)
2 parents 991069a + 7917e84 commit 0e8d22e

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ as well as `native-tls`-based TLS support.
8181
mysql_async = { version = "*", default-features = false, features = ["rustls-tls"] }
8282

8383
* `tracing` – enables instrumentation via `tracing` package.
84+
8485
Primary operations (`query`, `prepare`, `exec`) are instrumented at `INFO` level.
8586
Remaining operations, incl. `get_conn`, are instrumented at `DEBUG` level.
8687
Also at `DEBUG`, the SQL queries and parameters are added to the `query`, `prepare`
@@ -110,6 +111,10 @@ SSL support comes in two flavors:
110111
- it, most likely, won't work on windows, at least with default server certs,
111112
generated by the MySql installer.
112113

114+
## Connection URL parameters
115+
116+
There is a set of url-parameters supported by the driver (see documentation on [`Opts`]).
117+
113118
## Example
114119

115120
```rust

src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@
7979
//! [dependencies]
8080
//! mysql_async = { version = "*", default-features = false, features = ["rustls-tls"] }
8181
//!
82+
//! * `tracing` – enables instrumentation via `tracing` package.
83+
//!
84+
//! Primary operations (`query`, `prepare`, `exec`) are instrumented at `INFO` level.
85+
//! Remaining operations, incl. `get_conn`, are instrumented at `DEBUG` level.
86+
//! Also at `DEBUG`, the SQL queries and parameters are added to the `query`, `prepare`
87+
//! and `exec` spans.
88+
//!
89+
//! **Example:**
90+
//!
91+
//! ```toml
92+
//! [dependencies]
93+
//! mysql_async = { version = "*", features = ["tracing"] }
94+
//! ```
95+
//!
8296
//! [myslqcommonfeatures]: https://github.com/blackbeam/rust_mysql_common#crate-features
8397
//!
8498
//! # TLS/SSL Support
@@ -96,6 +110,10 @@
96110
//! - it, most likely, won't work on windows, at least with default server certs,
97111
//! generated by the MySql installer.
98112
//!
113+
//! # Connection URL parameters
114+
//!
115+
//! There is a set of url-parameters supported by the driver (see documentation on [`Opts`]).
116+
//!
99117
//! # Example
100118
//!
101119
//! ```rust

src/opts/mod.rs

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,27 @@ impl Opts {
608608
self.inner.mysql_opts.stmt_cache_size
609609
}
610610

611-
/// Driver will require SSL connection if this opts isn't `None` (default to `None`).
611+
/// Driver will require SSL connection if this opts isn't `None` (defaults to `None`).
612+
///
613+
/// # Connection URL parameters
614+
///
615+
/// Note that for securty reasons:
616+
///
617+
/// * CA and IDENTITY verifications are opt-out
618+
/// * there is no way to give an idenity or root certs via query URL
619+
///
620+
/// URL Parameters:
621+
///
622+
/// * `require_ssl: bool` (defaults to `false`) – requires SSL with default [`SslOpts`]
623+
/// * `verify_ca: bool` (defaults to `true`) – requires server Certificate Authority (CA)
624+
/// certificate validation against the configured CA certificates.
625+
/// Makes no sence if `require_ssl` equals `false`.
626+
/// * `verify_identity: bool` (defaults to `true`) – perform host name identity verification
627+
/// by checking the host name the client uses for connecting to the server against
628+
/// the identity in the certificate that the server sends to the client.
629+
/// Makes no sence if `require_ssl` equals `false`.
630+
///
631+
///
612632
pub fn ssl_opts(&self) -> Option<&SslOpts> {
613633
self.inner.mysql_opts.ssl_opts.as_ref()
614634
}
@@ -1078,6 +1098,10 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
10781098
let (mut opts, query_pairs): (MysqlOpts, _) = from_url_basic(url)?;
10791099
let mut pool_min = DEFAULT_POOL_CONSTRAINTS.min;
10801100
let mut pool_max = DEFAULT_POOL_CONSTRAINTS.max;
1101+
1102+
let mut skip_domain_validation = false;
1103+
let mut accept_invalid_certs = false;
1104+
10811105
for (key, value) in query_pairs {
10821106
if key == "pool_min" {
10831107
match usize::from_str(&*value) {
@@ -1240,6 +1264,40 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
12401264
value,
12411265
});
12421266
}
1267+
} else if key == "require_ssl" {
1268+
match bool::from_str(&*value) {
1269+
Ok(x) => opts.ssl_opts = x.then(SslOpts::default),
1270+
_ => {
1271+
return Err(UrlError::InvalidParamValue {
1272+
param: "require_ssl".into(),
1273+
value,
1274+
});
1275+
}
1276+
}
1277+
} else if key == "verify_ca" {
1278+
match bool::from_str(&*value) {
1279+
Ok(x) => {
1280+
accept_invalid_certs = !x;
1281+
}
1282+
_ => {
1283+
return Err(UrlError::InvalidParamValue {
1284+
param: "verify_ca".into(),
1285+
value,
1286+
});
1287+
}
1288+
}
1289+
} else if key == "verify_identity" {
1290+
match bool::from_str(&*value) {
1291+
Ok(x) => {
1292+
skip_domain_validation = !x;
1293+
}
1294+
_ => {
1295+
return Err(UrlError::InvalidParamValue {
1296+
param: "verify_identity".into(),
1297+
value,
1298+
});
1299+
}
1300+
}
12431301
} else {
12441302
return Err(UrlError::UnknownParameter { param: key });
12451303
}
@@ -1254,6 +1312,11 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
12541312
});
12551313
}
12561314

1315+
if let Some(ref mut ssl_opts) = opts.ssl_opts.as_mut() {
1316+
ssl_opts.accept_invalid_certs = accept_invalid_certs;
1317+
ssl_opts.skip_domain_validation = skip_domain_validation;
1318+
}
1319+
12571320
Ok(opts)
12581321
}
12591322

@@ -1276,7 +1339,7 @@ impl<'a> TryFrom<&'a str> for Opts {
12761339
#[cfg(test)]
12771340
mod test {
12781341
use super::{HostPortOrUrl, MysqlOpts, Opts, Url};
1279-
use crate::error::UrlError::InvalidParamValue;
1342+
use crate::{error::UrlError::InvalidParamValue, SslOpts};
12801343

12811344
use std::str::FromStr;
12821345

@@ -1345,6 +1408,41 @@ mod test {
13451408
assert_eq!(opts.ip_or_hostname(), "[::1]");
13461409
}
13471410

1411+
#[test]
1412+
fn should_parse_ssl_params() {
1413+
const URL1: &str = "mysql://localhost/foo?require_ssl=false";
1414+
let opts = Opts::from_url(URL1).unwrap();
1415+
assert_eq!(opts.ssl_opts(), None);
1416+
1417+
const URL2: &str = "mysql://localhost/foo?require_ssl=true";
1418+
let opts = Opts::from_url(URL2).unwrap();
1419+
assert_eq!(opts.ssl_opts(), Some(&SslOpts::default()));
1420+
1421+
const URL3: &str = "mysql://localhost/foo?require_ssl=true&verify_ca=false";
1422+
let opts = Opts::from_url(URL3).unwrap();
1423+
assert_eq!(
1424+
opts.ssl_opts(),
1425+
Some(&SslOpts::default().with_danger_accept_invalid_certs(true))
1426+
);
1427+
1428+
const URL4: &str =
1429+
"mysql://localhost/foo?require_ssl=true&verify_ca=false&verify_identity=false";
1430+
let opts = Opts::from_url(URL4).unwrap();
1431+
assert_eq!(
1432+
opts.ssl_opts(),
1433+
Some(
1434+
&SslOpts::default()
1435+
.with_danger_accept_invalid_certs(true)
1436+
.with_danger_skip_domain_validation(true)
1437+
)
1438+
);
1439+
1440+
const URL5: &str =
1441+
"mysql://localhost/foo?require_ssl=false&verify_ca=false&verify_identity=false";
1442+
let opts = Opts::from_url(URL5).unwrap();
1443+
assert_eq!(opts.ssl_opts(), None);
1444+
}
1445+
13481446
#[test]
13491447
#[should_panic]
13501448
fn should_panic_on_invalid_url() {

0 commit comments

Comments
 (0)