Skip to content

Commit 2842af3

Browse files
committed
Bump mysql_common to 0.30, add cleartext plugin support
1 parent f1afb7c commit 2842af3

File tree

7 files changed

+143
-32
lines changed

7 files changed

+143
-32
lines changed

Cargo.toml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ edition = "2018"
1313
categories = ["asynchronous", "database"]
1414

1515
[dependencies]
16-
bytes = "1.0"
16+
bytes = "1.4"
1717
crossbeam = "0.8.1"
1818
flate2 = { version = "1.0", default-features = false }
1919
futures-core = "0.3"
@@ -22,7 +22,9 @@ futures-sink = "0.3"
2222
lazy_static = "1"
2323
lru = "0.8.1"
2424
mio = { version = "0.8.0", features = ["os-poll", "net"] }
25-
mysql_common = { version = "0.29.2", default-features = false }
25+
mysql_common = { version = "0.30", default-features = false, features = [
26+
"derive",
27+
] }
2628
once_cell = "1.7.2"
2729
pem = "1.0.1"
2830
percent-encoding = "2.1.0"
@@ -34,7 +36,9 @@ socket2 = "0.4.2"
3436
thiserror = "1.0.4"
3537
tokio = { version = "1.0", features = ["io-util", "fs", "net", "time", "rt"] }
3638
tokio-util = { version = "0.7.2", features = ["codec", "io"] }
37-
tracing = { version = "0.1.37", default-features = false, features = ["attributes"], optional = true }
39+
tracing = { version = "0.1.37", default-features = false, features = [
40+
"attributes",
41+
], optional = true }
3842
twox-hash = "1"
3943
url = "2.1"
4044

@@ -76,20 +80,20 @@ rand = "0.8.0"
7680
[features]
7781
default = [
7882
"flate2/zlib",
79-
"mysql_common/bigdecimal03",
83+
"mysql_common/bigdecimal",
8084
"mysql_common/rust_decimal",
81-
"mysql_common/time03",
82-
"mysql_common/uuid",
85+
"mysql_common/time",
8386
"mysql_common/frunk",
87+
"derive",
8488
"native-tls-tls",
8589
]
8690
default-rustls = [
8791
"flate2/zlib",
88-
"mysql_common/bigdecimal03",
92+
"mysql_common/bigdecimal",
8993
"mysql_common/rust_decimal",
90-
"mysql_common/time03",
91-
"mysql_common/uuid",
94+
"mysql_common/time",
9295
"mysql_common/frunk",
96+
"derive",
9397
"rustls-tls",
9498
]
9599
minimal = ["flate2/zlib"]
@@ -102,6 +106,7 @@ rustls-tls = [
102106
"rustls-pemfile",
103107
]
104108
tracing = ["dep:tracing"]
109+
derive = ["mysql_common/derive"]
105110
nightly = []
106111

107112
[lib]

src/conn/mod.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -473,17 +473,15 @@ impl Conn {
473473
.unwrap_or((0, 0, 0));
474474
self.inner.id = handshake.connection_id();
475475
self.inner.status = handshake.status_flags();
476+
477+
// Allow only CachingSha2Password and MysqlNativePassword here
478+
// because sha256_password is deprecated and other plugins won't
479+
// appear here.
476480
self.inner.auth_plugin = match handshake.auth_plugin() {
477-
Some(AuthPlugin::MysqlNativePassword | AuthPlugin::MysqlOldPassword) => {
478-
AuthPlugin::MysqlNativePassword
479-
}
480481
Some(AuthPlugin::CachingSha2Password) => AuthPlugin::CachingSha2Password,
481-
Some(AuthPlugin::Other(ref name)) => {
482-
let name = String::from_utf8_lossy(name).into();
483-
return Err(DriverError::UnknownAuthPlugin { name }.into());
484-
}
485-
None => AuthPlugin::MysqlNativePassword,
482+
_ => AuthPlugin::MysqlNativePassword,
486483
};
484+
487485
Ok(())
488486
}
489487

@@ -567,13 +565,32 @@ impl Conn {
567565

568566
self.inner.auth_plugin = auth_switch_request.auth_plugin().clone().into_owned();
569567

570-
let plugin_data = self
571-
.inner
572-
.auth_plugin
573-
.gen_data(self.inner.opts.pass(), &*self.inner.nonce);
568+
let plugin_data = match &self.inner.auth_plugin {
569+
x @ AuthPlugin::CachingSha2Password => {
570+
x.gen_data(self.inner.opts.pass(), &self.inner.nonce)
571+
}
572+
x @ AuthPlugin::MysqlNativePassword => {
573+
x.gen_data(self.inner.opts.pass(), &self.inner.nonce)
574+
}
575+
x @ AuthPlugin::MysqlOldPassword => {
576+
if self.inner.opts.secure_auth() {
577+
return Err(DriverError::MysqlOldPasswordDisabled.into());
578+
} else {
579+
x.gen_data(self.inner.opts.pass(), &self.inner.nonce)
580+
}
581+
}
582+
x @ AuthPlugin::MysqlClearPassword => {
583+
if self.inner.opts.enable_cleartext_plugin() {
584+
x.gen_data(self.inner.opts.pass(), &self.inner.nonce)
585+
} else {
586+
return Err(DriverError::CleartextPluginDisabled.into());
587+
}
588+
}
589+
x @ AuthPlugin::Other(_) => x.gen_data(self.inner.opts.pass(), &self.inner.nonce),
590+
};
574591

575592
if let Some(plugin_data) = plugin_data {
576-
self.write_struct(&plugin_data).await?;
593+
self.write_struct(&plugin_data.into_owned()).await?;
577594
} else {
578595
self.write_packet(crate::BUFFER_POOL.get()).await?;
579596
}
@@ -599,6 +616,14 @@ impl Conn {
599616
self.continue_caching_sha2_password_auth().await?;
600617
Ok(())
601618
}
619+
AuthPlugin::MysqlClearPassword => {
620+
if self.inner.opts.enable_cleartext_plugin() {
621+
self.continue_mysql_native_password_auth().await?;
622+
Ok(())
623+
} else {
624+
Err(DriverError::CleartextPluginDisabled.into())
625+
}
626+
}
602627
AuthPlugin::Other(ref name) => Err(DriverError::UnknownAuthPlugin {
603628
name: String::from_utf8_lossy(name.as_ref()).to_string(),
604629
}

src/conn/pool/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ mod test {
461461

462462
#[tokio::test]
463463
async fn should_connect() -> super::Result<()> {
464-
let pool = Pool::new(get_opts());
464+
let pool = Pool::new(crate::Opts::from(get_opts()));
465465
pool.get_conn().await?.ping().await?;
466466
pool.disconnect().await?;
467467
Ok(())

src/error/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ pub enum DriverError {
163163

164164
#[error("Client asked for SSL but server does not have this capability")]
165165
NoClientSslFlagFromServer,
166+
167+
#[error("mysql_clear_password must be enabled on the client side")]
168+
CleartextPluginDisabled,
166169
}
167170

168171
#[derive(Debug, Error)]

src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@
418418
#[cfg(feature = "nightly")]
419419
extern crate test;
420420

421+
#[cfg(feature = "derive")]
422+
extern crate mysql_common;
423+
421424
pub use mysql_common::{constants as consts, params};
422425

423426
use std::sync::Arc;
@@ -481,7 +484,7 @@ pub use mysql_common::packets::{
481484
Gtids, Schema, SessionStateChange, SystemVariable, TransactionCharacteristics,
482485
TransactionState, Unsupported,
483486
},
484-
BinlogDumpFlags, Column, Interval, OkPacket, SessionStateInfo, Sid,
487+
BinlogDumpFlags, Column, GnoInterval, OkPacket, SessionStateInfo, Sid,
485488
};
486489

487490
pub mod binlog {
@@ -541,9 +544,9 @@ pub mod prelude {
541544
#[doc(inline)]
542545
pub use crate::queryable::Queryable;
543546
#[doc(inline)]
544-
pub use mysql_common::row::convert::FromRow;
547+
pub use mysql_common::prelude::FromRow;
545548
#[doc(inline)]
546-
pub use mysql_common::value::convert::{ConvIr, FromValue, ToValue};
549+
pub use mysql_common::prelude::{FromValue, ToValue};
547550

548551
/// Everything that is a statement.
549552
///

src/opts/mod.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,17 @@ pub(crate) struct MysqlOpts {
410410
/// Changes the behavior of the affected count returned for writes (UPDATE/INSERT etc).
411411
/// It makes MySQL return the FOUND rows instead of the AFFECTED rows.
412412
client_found_rows: bool,
413+
414+
/// Enables Client-Side Cleartext Pluggable Authentication (defaults to `false`).
415+
///
416+
/// Enables client to send passwords to the server as cleartext, without hashing or encryption
417+
/// (consult MySql documentation for more info).
418+
///
419+
/// # Security Notes
420+
///
421+
/// Sending passwords as cleartext may be a security problem in some configurations. Please
422+
/// consider using TLS or encrypted tunnels for server connection.
423+
enable_cleartext_plugin: bool,
413424
}
414425

415426
/// Mysql connection options.
@@ -747,6 +758,31 @@ impl Opts {
747758
self.inner.mysql_opts.client_found_rows
748759
}
749760

761+
/// Returns `true` if `mysql_clear_password` plugin support is enabled (defaults to `false`).
762+
///
763+
/// `mysql_clear_password` enables client to send passwords to the server as cleartext, without
764+
/// hashing or encryption (consult MySql documentation for more info).
765+
///
766+
/// # Security Notes
767+
///
768+
/// Sending passwords as cleartext may be a security problem in some configurations. Please
769+
/// consider using TLS or encrypted tunnels for server connection.
770+
///
771+
/// # Connection URL
772+
///
773+
/// Use `enable_cleartext_plugin` URL parameter to set this value. E.g.
774+
///
775+
/// ```
776+
/// # use mysql_async::*;
777+
/// # fn main() -> Result<()> {
778+
/// let opts = Opts::from_url("mysql://localhost/db?enable_cleartext_plugin=true")?;
779+
/// assert!(opts.enable_cleartext_plugin());
780+
/// # Ok(()) }
781+
/// ```
782+
pub fn enable_cleartext_plugin(&self) -> bool {
783+
self.inner.mysql_opts.enable_cleartext_plugin
784+
}
785+
750786
pub(crate) fn get_capabilities(&self) -> CapabilityFlags {
751787
let mut out = CapabilityFlags::CLIENT_PROTOCOL_41
752788
| CapabilityFlags::CLIENT_SECURE_CONNECTION
@@ -797,6 +833,7 @@ impl Default for MysqlOpts {
797833
wait_timeout: None,
798834
secure_auth: true,
799835
client_found_rows: false,
836+
enable_cleartext_plugin: false,
800837
}
801838
}
802839
}
@@ -1053,6 +1090,32 @@ impl OptsBuilder {
10531090
self.opts.client_found_rows = client_found_rows;
10541091
self
10551092
}
1093+
1094+
/// Enables Client-Side Cleartext Pluggable Authentication (defaults to `false`).
1095+
///
1096+
/// Enables client to send passwords to the server as cleartext, without hashing or encryption
1097+
/// (consult MySql documentation for more info).
1098+
///
1099+
/// # Security Notes
1100+
///
1101+
/// Sending passwords as cleartext may be a security problem in some configurations. Please
1102+
/// consider using TLS or encrypted tunnels for server connection.
1103+
///
1104+
/// # Connection URL
1105+
///
1106+
/// Use `enable_cleartext_plugin` URL parameter to set this value. E.g.
1107+
///
1108+
/// ```
1109+
/// # use mysql_async::*;
1110+
/// # fn main() -> Result<()> {
1111+
/// let opts = Opts::from_url("mysql://localhost/db?enable_cleartext_plugin=true")?;
1112+
/// assert!(opts.enable_cleartext_plugin());
1113+
/// # Ok(()) }
1114+
/// ```
1115+
pub fn enable_cleartext_plugin(mut self, enable_cleartext_plugin: bool) -> Self {
1116+
self.opts.enable_cleartext_plugin = enable_cleartext_plugin;
1117+
self
1118+
}
10561119
}
10571120

10581121
impl From<OptsBuilder> for Opts {
@@ -1235,6 +1298,16 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result<MysqlOpts, UrlError> {
12351298
});
12361299
}
12371300
}
1301+
} else if key == "enable_cleartext_plugin" {
1302+
match bool::from_str(&*value) {
1303+
Ok(parsed) => opts.enable_cleartext_plugin = parsed,
1304+
Err(_) => {
1305+
return Err(UrlError::InvalidParamValue {
1306+
param: key.to_string(),
1307+
value,
1308+
});
1309+
}
1310+
}
12381311
} else if key == "tcp_nodelay" {
12391312
match bool::from_str(&*value) {
12401313
Ok(value) => opts.tcp_nodelay = value,

tests/exports.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ use mysql_async::{
44
futures::{DisconnectPool, GetConn},
55
params,
66
prelude::{
7-
BatchQuery, ConvIr, FromRow, FromValue, GlobalHandler, Protocol, Query, Queryable,
8-
StatementLike, ToValue,
7+
BatchQuery, FromRow, FromValue, GlobalHandler, Protocol, Query, Queryable, StatementLike,
8+
ToValue,
99
},
10-
BinaryProtocol, Column, Conn, Deserialized, DriverError, Error, FromRowError, FromValueError,
11-
IoError, IsolationLevel, Opts, OptsBuilder, Params, ParseError, Pool, PoolConstraints,
12-
PoolOpts, QueryResult, Result, Row, Serialized, ServerError, SslOpts, Statement, TextProtocol,
13-
Transaction, TxOpts, UrlError, Value, WhiteListFsHandler, DEFAULT_INACTIVE_CONNECTION_TTL,
10+
BinaryProtocol, BinlogDumpFlags, BinlogRequest, Column, Conn, Deserialized, DriverError, Error,
11+
FromRowError, FromValueError, GnoInterval, Gtids, IoError, IsolationLevel, OkPacket, Opts,
12+
OptsBuilder, Params, ParseError, Pool, PoolConstraints, PoolOpts, QueryResult, Result, Row,
13+
Schema, Serialized, ServerError, SessionStateChange, SessionStateInfo, Sid, SslOpts, Statement,
14+
SystemVariable, TextProtocol, Transaction, TransactionCharacteristics, TransactionState,
15+
TxOpts, Unsupported, UrlError, Value, WhiteListFsHandler, DEFAULT_INACTIVE_CONNECTION_TTL,
1416
DEFAULT_TTL_CHECK_INTERVAL,
1517
};

0 commit comments

Comments
 (0)