Skip to content

Commit

Permalink
Merge pull request blackbeam#226 from blackbeam/issue-225-ssl-query-p…
Browse files Browse the repository at this point in the history
…arams

Introduce SSL-related query params (fix blackbeam#225)
  • Loading branch information
blackbeam authored Feb 2, 2023
2 parents 991069a + 7917e84 commit 0e8d22e
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 2 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ as well as `native-tls`-based TLS support.
mysql_async = { version = "*", default-features = false, features = ["rustls-tls"] }

* `tracing` – enables instrumentation via `tracing` package.

Primary operations (`query`, `prepare`, `exec`) are instrumented at `INFO` level.
Remaining operations, incl. `get_conn`, are instrumented at `DEBUG` level.
Also at `DEBUG`, the SQL queries and parameters are added to the `query`, `prepare`
Expand Down Expand Up @@ -110,6 +111,10 @@ SSL support comes in two flavors:
- it, most likely, won't work on windows, at least with default server certs,
generated by the MySql installer.

## Connection URL parameters

There is a set of url-parameters supported by the driver (see documentation on [`Opts`]).

## Example

```rust
Expand Down
18 changes: 18 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@
//! [dependencies]
//! mysql_async = { version = "*", default-features = false, features = ["rustls-tls"] }
//!
//! * `tracing` – enables instrumentation via `tracing` package.
//!
//! Primary operations (`query`, `prepare`, `exec`) are instrumented at `INFO` level.
//! Remaining operations, incl. `get_conn`, are instrumented at `DEBUG` level.
//! Also at `DEBUG`, the SQL queries and parameters are added to the `query`, `prepare`
//! and `exec` spans.
//!
//! **Example:**
//!
//! ```toml
//! [dependencies]
//! mysql_async = { version = "*", features = ["tracing"] }
//! ```
//!
//! [myslqcommonfeatures]: https://github.com/blackbeam/rust_mysql_common#crate-features
//!
//! # TLS/SSL Support
Expand All @@ -96,6 +110,10 @@
//! - it, most likely, won't work on windows, at least with default server certs,
//! generated by the MySql installer.
//!
//! # Connection URL parameters
//!
//! There is a set of url-parameters supported by the driver (see documentation on [`Opts`]).
//!
//! # Example
//!
//! ```rust
Expand Down
102 changes: 100 additions & 2 deletions src/opts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,27 @@ impl Opts {
self.inner.mysql_opts.stmt_cache_size
}

/// Driver will require SSL connection if this opts isn't `None` (default to `None`).
/// Driver will require SSL connection if this opts isn't `None` (defaults to `None`).
///
/// # Connection URL parameters
///
/// Note that for securty reasons:
///
/// * CA and IDENTITY verifications are opt-out
/// * there is no way to give an idenity or root certs via query URL
///
/// URL Parameters:
///
/// * `require_ssl: bool` (defaults to `false`) – requires SSL with default [`SslOpts`]
/// * `verify_ca: bool` (defaults to `true`) – requires server Certificate Authority (CA)
/// certificate validation against the configured CA certificates.
/// Makes no sence if `require_ssl` equals `false`.
/// * `verify_identity: bool` (defaults to `true`) – perform host name identity verification
/// by checking the host name the client uses for connecting to the server against
/// the identity in the certificate that the server sends to the client.
/// Makes no sence if `require_ssl` equals `false`.
///
///
pub fn ssl_opts(&self) -> Option<&SslOpts> {
self.inner.mysql_opts.ssl_opts.as_ref()
}
Expand Down Expand Up @@ -1078,6 +1098,10 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
let (mut opts, query_pairs): (MysqlOpts, _) = from_url_basic(url)?;
let mut pool_min = DEFAULT_POOL_CONSTRAINTS.min;
let mut pool_max = DEFAULT_POOL_CONSTRAINTS.max;

let mut skip_domain_validation = false;
let mut accept_invalid_certs = false;

for (key, value) in query_pairs {
if key == "pool_min" {
match usize::from_str(&*value) {
Expand Down Expand Up @@ -1240,6 +1264,40 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
value,
});
}
} else if key == "require_ssl" {
match bool::from_str(&*value) {
Ok(x) => opts.ssl_opts = x.then(SslOpts::default),
_ => {
return Err(UrlError::InvalidParamValue {
param: "require_ssl".into(),
value,
});
}
}
} else if key == "verify_ca" {
match bool::from_str(&*value) {
Ok(x) => {
accept_invalid_certs = !x;
}
_ => {
return Err(UrlError::InvalidParamValue {
param: "verify_ca".into(),
value,
});
}
}
} else if key == "verify_identity" {
match bool::from_str(&*value) {
Ok(x) => {
skip_domain_validation = !x;
}
_ => {
return Err(UrlError::InvalidParamValue {
param: "verify_identity".into(),
value,
});
}
}
} else {
return Err(UrlError::UnknownParameter { param: key });
}
Expand All @@ -1254,6 +1312,11 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
});
}

if let Some(ref mut ssl_opts) = opts.ssl_opts.as_mut() {
ssl_opts.accept_invalid_certs = accept_invalid_certs;
ssl_opts.skip_domain_validation = skip_domain_validation;
}

Ok(opts)
}

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

use std::str::FromStr;

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

#[test]
fn should_parse_ssl_params() {
const URL1: &str = "mysql://localhost/foo?require_ssl=false";
let opts = Opts::from_url(URL1).unwrap();
assert_eq!(opts.ssl_opts(), None);

const URL2: &str = "mysql://localhost/foo?require_ssl=true";
let opts = Opts::from_url(URL2).unwrap();
assert_eq!(opts.ssl_opts(), Some(&SslOpts::default()));

const URL3: &str = "mysql://localhost/foo?require_ssl=true&verify_ca=false";
let opts = Opts::from_url(URL3).unwrap();
assert_eq!(
opts.ssl_opts(),
Some(&SslOpts::default().with_danger_accept_invalid_certs(true))
);

const URL4: &str =
"mysql://localhost/foo?require_ssl=true&verify_ca=false&verify_identity=false";
let opts = Opts::from_url(URL4).unwrap();
assert_eq!(
opts.ssl_opts(),
Some(
&SslOpts::default()
.with_danger_accept_invalid_certs(true)
.with_danger_skip_domain_validation(true)
)
);

const URL5: &str =
"mysql://localhost/foo?require_ssl=false&verify_ca=false&verify_identity=false";
let opts = Opts::from_url(URL5).unwrap();
assert_eq!(opts.ssl_opts(), None);
}

#[test]
#[should_panic]
fn should_panic_on_invalid_url() {
Expand Down

0 comments on commit 0e8d22e

Please sign in to comment.