Skip to content

Commit ca8ce2a

Browse files
committed
Merge branch 'mysql-8.0' into mysql-trunk
2 parents 9531c6b + 2c37ce0 commit ca8ce2a

File tree

6 files changed

+283
-134
lines changed

6 files changed

+283
-134
lines changed

mysql-test/suite/x/r/connection_default_schema.result

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,36 @@ GRANT SELECT ON ydb.* TO 'user_with_access_to_ydb'@'%';
1717
#
1818
## Test group 1.
1919
##
20+
## Authenticate using plain X Protocol flows to schema that:
21+
##
22+
## * account has permissions
23+
## * account has not permissions
24+
## * account has permissions still db-doesn't exist
25+
#
26+
connecting...
27+
active session is now 'non_root_user'
28+
Login OK
29+
closing session non_root_user
30+
Mysqlx.Ok {
31+
msg: "bye!"
32+
}
33+
switched to session default
34+
connecting...
35+
active session is now 'non_root_user'
36+
Got expected error: Access denied for user 'user_with_access_to_ydb'@'%' to database 'xdb' (code 1044)
37+
aborting session non_root_user
38+
switched to session default
39+
connecting...
40+
active session is now 'root_user'
41+
Got expected error: Unknown database 'non_existing_schema' (code 1049)
42+
aborting session root_user
43+
switched to session default
44+
Mysqlx.Ok {
45+
msg: "bye!"
46+
}
47+
#
48+
## Test group 2.
49+
##
2050
## Authenticate using an account which has permissions
2151
## to selected schema.
2252
#
@@ -37,7 +67,7 @@ Mysqlx.Ok {
3767
}
3868
ok
3969
#
40-
## Test group 2.
70+
## Test group 3.
4171
##
4272
## Authenticate using an account which has not permissions
4373
## to selected schema.
@@ -52,29 +82,20 @@ EXPECTED_ERROR_CODE(42000): Access denied for user 'user_with_access_to_xdb'@'%'
5282
in main, line 0:ERROR: Access denied for user 'user_with_access_to_xdb'@'%' to database 'ydb' (EXPECTED_ERROR_CODE)
5383
not ok
5484
#
55-
## Test group 3.
56-
##
57-
## Authenticate using plain X Protocol flows to schame that:
85+
## Test group 4.
5886
##
59-
## * account has permissions
60-
## * account has not permissions
87+
## Authenticate using an valid account to non existing
88+
## schema.
6189
#
62-
connecting...
63-
active session is now 'non_roo_user'
64-
Login OK
65-
closing session non_roo_user
66-
Mysqlx.Ok {
67-
msg: "bye!"
68-
}
69-
switched to session default
70-
connecting...
71-
active session is now 'non_roo_user'
72-
Got expected error: Access denied for user 'user_with_access_to_ydb'@'%' to database 'xdb' (code 1044)
73-
aborting session non_roo_user
74-
switched to session default
75-
Mysqlx.Ok {
76-
msg: "bye!"
77-
}
90+
91+
# Using MySQL client
92+
# Checking if requested schema was selected.
93+
EXPECTED_ERROR_CODE(42000): Unknown database 'non_existing_schema'
94+
95+
# Using mysqlxtest
96+
# Checking if requested schema was selected.
97+
in main, line 0:ERROR: Unknown database 'non_existing_schema' (EXPECTED_ERROR_CODE)
98+
not ok
7899
#
79100
## Cleanup
80101
#

mysql-test/suite/x/t/connection_default_schema.test

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,20 @@
99

1010
--write_file $MYSQL_TMP_DIR/connection_default_schema_manual.tmp
1111

12-
-->newsession non_roo_user -
12+
-->newsession non_root_user -
1313
-->login user_with_access_to_ydb ydb
1414
-->closesession
1515

16-
-->newsession non_roo_user -
16+
-->newsession non_root_user -
1717
-->expecterror ER_DBACCESS_DENIED_ERROR
1818
-->login user_with_access_to_ydb xdb
1919
-->closesession abort
2020

21+
-->newsession root_user -
22+
-->expecterror ER_BAD_DB_ERROR
23+
-->login root non_existing_schema sha256_memory
24+
-->closesession abort
25+
2126
EOF
2227

2328
call mtr.add_suppression("Plugin mysqlx reported: '.*: Unsuccessful login attempt");
@@ -36,9 +41,26 @@ GRANT SELECT ON ydb.* TO 'user_with_access_to_ydb'@'%';
3641
--echo ## Testcase execute
3742
--echo #
3843

44+
3945
--echo #
4046
--echo ## Test group 1.
4147
--echo ##
48+
--echo ## Authenticate using plain X Protocol flows to schema that:
49+
--echo ##
50+
--echo ## * account has permissions
51+
--echo ## * account has not permissions
52+
--echo ## * account has permissions still db-doesn't exist
53+
--echo #
54+
55+
exec $MYSQLXTEST
56+
-uroot
57+
--ssl-mode=REQUIRED
58+
-f $MYSQL_TMP_DIR/connection_default_schema_manual.tmp;
59+
60+
61+
--echo #
62+
--echo ## Test group 2.
63+
--echo ##
4264
--echo ## Authenticate using an account which has permissions
4365
--echo ## to selected schema.
4466
--echo #
@@ -58,7 +80,7 @@ let $schema=xdb;
5880

5981

6082
--echo #
61-
--echo ## Test group 2.
83+
--echo ## Test group 3.
6284
--echo ##
6385
--echo ## Authenticate using an account which has not permissions
6486
--echo ## to selected schema.
@@ -82,18 +104,28 @@ let $expect_error=code 1044;
82104

83105

84106
--echo #
85-
--echo ## Test group 3.
86-
--echo ##
87-
--echo ## Authenticate using plain X Protocol flows to schame that:
107+
--echo ## Test group 4.
88108
--echo ##
89-
--echo ## * account has permissions
90-
--echo ## * account has not permissions
109+
--echo ## Authenticate using an valid account to non existing
110+
--echo ## schema.
91111
--echo #
92112

93-
exec $MYSQLXTEST
94-
-uroot
95-
--ssl-mode=REQUIRED
96-
-f $MYSQL_TMP_DIR/connection_default_schema_manual.tmp;
113+
114+
--echo
115+
--echo # Using MySQL client
116+
let $execute_command=$MYSQL;
117+
let $user=root;
118+
let $schema=non_existing_schema;
119+
let $expect_error=ERROR 1049 ;
120+
--source ../include/connection_default_schema.inc
121+
122+
--echo
123+
--echo # Using mysqlxtest
124+
let $execute_command=$MYSQLXTEST;
125+
let $user=root;
126+
let $schema=non_existing_schema;
127+
let $expect_error=code 1049;
128+
--source ../include/connection_default_schema.inc
97129

98130

99131
--echo #

plugin/x/client/xprotocol_impl.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,9 @@ XError Protocol_impl::send(const Client_message_type_id mid,
372372
return XError{CR_MALFORMED_PACKET, ER_TEXT_PB_SERIALIZATION_FAILED};
373373
}
374374

375-
std::uint32_t *buf_ptr = reinterpret_cast<std::uint32_t *>(&msg_buffer[0]);
376-
*buf_ptr = static_cast<std::uint32_t>(msg_size + 1);
375+
const auto msg_size_to_buffer = static_cast<std::uint32_t>(msg_size + 1);
376+
377+
memcpy(&msg_buffer[0], &msg_size_to_buffer, sizeof(std::uint32_t));
377378
#ifdef WORDS_BIGENDIAN
378379
std::swap(msg_buffer[0], msg_buffer[3]);
379380
std::swap(msg_buffer[1], msg_buffer[2]);

plugin/x/client/xsession_impl.cc

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -699,11 +699,12 @@ XError Session_impl::authenticate(const char *user, const char *pass,
699699
if (error) return error;
700700

701701
bool has_sha256_memory = false;
702-
XError auth_error;
703-
XError reported_error =
704-
XError{ER_ACCESS_DENIED_ERROR, "Invalid user or password"};
702+
bool fatal_error_received = false;
703+
XError reported_error;
704+
705705
for (const auto &auth_method : optional_auth_methods.second) {
706706
const bool is_last = &auth_method == &optional_auth_methods.second.back();
707+
707708
if (auth_method == "PLAIN" && !is_secure_connection) {
708709
// If this is not the last authentication mechanism then do not report
709710
// error but try those other methods instead.
@@ -712,42 +713,70 @@ XError Session_impl::authenticate(const char *user, const char *pass,
712713
CR_X_INVALID_AUTH_METHOD,
713714
"Invalid authentication method: PLAIN over unsecure channel"};
714715
}
715-
} else {
716-
auth_error = protocol.execute_authenticate(
717-
details::value_or_empty_string(user),
718-
details::value_or_empty_string(pass),
719-
details::value_or_empty_string(schema), auth_method);
720-
721-
const auto current_error_code = auth_error.error();
722-
723-
// In case of 'broken pipe', 'peer disconnected' and timeouts we should
724-
// break the authentication sequence and return an error.
725-
if (current_error_code == CR_SERVER_GONE_ERROR ||
726-
current_error_code == CR_X_WRITE_TIMEOUT ||
727-
current_error_code == CR_X_READ_TIMEOUT ||
728-
current_error_code == CR_UNKNOWN_ERROR)
729-
return auth_error;
730-
731-
if (current_error_code != ER_ACCESS_DENIED_ERROR ||
732-
reported_error.error() == ER_ACCESS_DENIED_ERROR) {
733-
reported_error = auth_error;
734-
}
735716

736-
// Also we should stop the authentication sequence on any fatal error.
737-
if (auth_error.is_fatal()) return reported_error;
738-
739-
if (auth_method == "SHA256_MEMORY") has_sha256_memory = true;
717+
continue;
740718
}
741719

720+
XError current_error = protocol.execute_authenticate(
721+
details::value_or_empty_string(user),
722+
details::value_or_empty_string(pass),
723+
details::value_or_empty_string(schema), auth_method);
724+
742725
// Authentication successful, otherwise try to use different auth method
743-
if (!auth_error) return {};
726+
if (!current_error) return {};
727+
728+
const auto current_error_code = current_error.error();
729+
730+
// In case of connection errors ('broken pipe', 'peer disconnected',
731+
// timeouts...) we should break the authentication sequence and return
732+
// an error.
733+
if (current_error_code == CR_SERVER_GONE_ERROR ||
734+
current_error_code == CR_X_WRITE_TIMEOUT ||
735+
current_error_code == CR_X_READ_TIMEOUT ||
736+
current_error_code == CR_UNKNOWN_ERROR) {
737+
// Expected disconnection
738+
if (fatal_error_received) return reported_error;
739+
740+
// Unexpected disconnection
741+
return current_error;
742+
}
743+
744+
// Try to choose most important error:
745+
//
746+
// |Priority |Action |
747+
// |---------|------------------------------|
748+
// |1 |No error was set |
749+
// |2 |Last other than access denied |
750+
// |3 |Last access denied |
751+
if (!reported_error || current_error_code != ER_ACCESS_DENIED_ERROR ||
752+
reported_error.error() == ER_ACCESS_DENIED_ERROR) {
753+
reported_error = current_error;
754+
}
755+
756+
// Also we should stop the authentication sequence on fatal error.
757+
// Still it would break compatibility with servers that wrongly mark
758+
// Mysqlx::Error message with fatal flag.
759+
//
760+
// To workaround the problem of backward compatibility, we should
761+
// remember that fatal error was received and try to continue the
762+
// sequence. After reception of fatal error, following connection
763+
// errors are expected (CR_SERVER_GONE_ERROR, CR_X_WRITE_TIMEOUT....)
764+
// and must be ignored.
765+
if (current_error.is_fatal()) fatal_error_received = true;
766+
767+
if (auth_method == "SHA256_MEMORY") has_sha256_memory = true;
744768
}
745769

770+
// In case when SHA256_MEMORY was used and no PLAIN (because of not using
771+
// secure connection) and all errors where ER_ACCESS_DENIED, there is
772+
// possibility that password cache on the server side is empty.
773+
// We need overwrite the error to give the user a hint that
774+
// secure connection can be used.
746775
if (has_sha256_memory && !is_secure_connection &&
747776
reported_error.error() == ER_ACCESS_DENIED_ERROR) {
748777
reported_error = XError{CR_X_AUTH_PLUGIN_ERROR,
749-
"Authentication failed, check username and \
750-
password or try a secure connection"};
778+
"Authentication failed, check username and "
779+
"password or try a secure connection"};
751780
}
752781

753782
return reported_error;

plugin/x/ngs/src/client_session.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,9 @@ bool Session::can_forward_error_code_to_client(const int error_code) {
237237
// return general authentication problem. It may have not too
238238
// accurate error message.
239239
const static std::set<int> allowed_error_codes{
240-
ER_DBACCESS_DENIED_ERROR, ER_MUST_CHANGE_PASSWORD_LOGIN,
240+
ER_DBACCESS_DENIED_ERROR, ER_MUST_CHANGE_PASSWORD_LOGIN,
241241
ER_ACCOUNT_HAS_BEEN_LOCKED, ER_SECURE_TRANSPORT_REQUIRED,
242-
ER_SERVER_OFFLINE_MODE};
242+
ER_SERVER_OFFLINE_MODE, ER_BAD_DB_ERROR};
243243

244244
return 0 < allowed_error_codes.count(error_code);
245245
}

0 commit comments

Comments
 (0)