Skip to content

Commit 302b989

Browse files
committed
Merge remote-tracking branch 'origin/trunk' into wl15808-otel-missing-bits
2 parents 13021ee + 6f18831 commit 302b989

File tree

8 files changed

+544
-214
lines changed

8 files changed

+544
-214
lines changed

jdbc/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ set(AUTH_PLUGINS
421421
)
422422

423423
if(NOT CMAKE_SYSTEM_NAME MATCHES "SunOS")
424-
list(APPEND AUTH_PLUGINS fido)
424+
list(APPEND AUTH_PLUGINS webauthn fido)
425425
# Note: Kerberos authentication plugin is not supported on macOS
426426
if(NOT APPLE)
427427
list(APPEND AUTH_PLUGINS kerberos)
@@ -435,6 +435,7 @@ endif()
435435
# should be listed first, otherwise the logic detecting missing dependencies
436436
# will break... For example: `krb5support` must go before `krb5`
437437

438+
set(AUTH_DEPS_webauthn fido2)
438439
set(AUTH_DEPS_fido fido2)
439440

440441

jdbc/cppconn/callback.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,103 @@ class MySQL_Connection;
4545
class MySQL_Driver;
4646
}
4747

48+
49+
/*
50+
A callback to be used with `Driver::setCallback()` to define reaction
51+
to the user action request during WebAuthn authentication handshake.
52+
53+
The client library defines default reaction which prints message on stderr.
54+
This callback can be used to change it.
55+
56+
Example usage:
57+
58+
// Use lambda
59+
60+
driver->setCallback(WebAuthn_Callback{[](SQLString msg){
61+
cerr << "User action request: " << msg << endl;
62+
}});
63+
64+
// Disable default behavior (and do nothing upon action request)
65+
66+
driver->setCallback(WebAuthn_Callback{});
67+
68+
// Return to default behavior
69+
70+
driver->setCallbacak(WebAuthn_Callback{nullptr});
71+
72+
// User defined callback
73+
74+
struct My_Callback : WebAuthn_Callback
75+
{
76+
void ActionRequested(SQLString) override;
77+
}
78+
cb;
79+
80+
driver->setCallback(cb);
81+
*/
82+
83+
class WebAuthn_Callback
84+
{
85+
std::function<void(SQLString)> callback_func;
86+
87+
public:
88+
89+
/*
90+
Create a callback that will call given lambda upon user action request.
91+
*/
92+
93+
WebAuthn_Callback(std::function<void(SQLString)>&& cb)
94+
: callback_func{std::move(cb)}
95+
{}
96+
97+
/*
98+
Create an empty callback that will do nothing upon user action request.
99+
This disables the default callback defined by the client library.
100+
*/
101+
102+
WebAuthn_Callback()
103+
: callback_func{[](SQLString){}}
104+
{}
105+
106+
/*
107+
Create a null callback. Setting such callback has the effect of using
108+
the default callback defined by the client library.
109+
*/
110+
111+
WebAuthn_Callback(std::nullptr_t)
112+
{}
113+
114+
/*
115+
Derived class can override this method to react to user action request.
116+
*/
117+
118+
virtual void ActionRequested(sql::SQLString msg)
119+
{
120+
if (callback_func)
121+
callback_func(msg);
122+
}
123+
124+
// Returns true if this callback is not null.
125+
126+
operator bool() const
127+
{
128+
return (bool)callback_func;
129+
}
130+
131+
void operator()(sql::SQLString msg)
132+
{
133+
ActionRequested(msg);
134+
}
135+
136+
};
137+
138+
48139
/*
49140
* Class that provides functionality allowing user code to set the
50141
* callback functions through inheriting, passing the callback as
51142
* constructor parameters or using lambdas.
52143
*/
144+
53145
class Fido_Callback
54146
{
55147
std::function<void(SQLString)> callback_func = nullptr;
@@ -97,6 +189,7 @@ class Fido_Callback
97189
friend class mysql::MySQL_Driver;
98190
};
99191

192+
100193
} /* namespace sql */
101194

102195
#endif // _SQL_CONNECTION_H_

jdbc/cppconn/driver.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ class CPPCONN_PUBLIC_FUNC Driver
6060
virtual const sql::SQLString & getName() = 0;
6161

6262
virtual void setCallBack(sql::Fido_Callback &cb) = 0;
63-
6463
virtual void setCallBack(sql::Fido_Callback &&cb) = 0;
6564

6665
virtual void threadInit() = 0;
6766

6867
virtual void threadEnd() = 0;
68+
69+
virtual void setCallBack(sql::WebAuthn_Callback &cb) = 0;
70+
virtual void setCallBack(sql::WebAuthn_Callback &&cb) = 0;
6971
};
7072

7173
} /* namespace sql */

jdbc/driver/mysql_connection.cpp

Lines changed: 144 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,9 @@
9595
# define ER_MUST_CHANGE_PASSWORD_LOGIN 1820
9696
#endif
9797

98-
std::mutex callback_mutex;
99-
100-
sql::Fido_Callback * fido_callback_instance = nullptr;
10198

10299
bool oci_plugin_is_loaded = false;
103100

104-
static void fido_callback_func(const char* msg)
105-
{
106-
if (!fido_callback_instance)
107-
return;
108-
(*fido_callback_instance)(msg);
109-
}
110-
111101

112102
namespace sql
113103
{
@@ -414,6 +404,7 @@ bool get_connection_option(const sql::SQLString optionName,
414404
return false;
415405
}
416406

407+
417408
struct Prio
418409
{
419410
uint16_t prio;
@@ -429,6 +420,143 @@ struct Prio
429420
}
430421
};
431422

423+
424+
/*
425+
A callback setter object arranges for correct WebAuthn/Fido authentication
426+
callbacks to be used by the correpsonding clientlib authentication plugin.
427+
428+
If a user has registered a callback with a driver that creates a connection
429+
then a callback function is registered with authentication plugins which will
430+
call the callback stored in the driver.
431+
432+
The callback function registered with authentication plugins must be changed
433+
depending on which driver is used to create a connection. A callback setter
434+
object makes necessary changes when it detects that the current driver passed
435+
to its ctor is different from the one used last time.
436+
437+
While exists, callback setter also prevents modification of authentication
438+
plugin callbacks by concurrent threads.
439+
*/
440+
441+
struct MySQL_Driver::WebAuthn_Callback_Setter
442+
{
443+
using Proxy = NativeAPI::NativeConnectionWrapper;
444+
445+
WebAuthn_Callback_Setter(MySQL_Driver &drv, Proxy *prx)
446+
: lock{mutex}
447+
{
448+
/*
449+
Note: Meaning of callback type value:
450+
451+
0 or 3 = no callback
452+
1 or 4 = webauthn only callback
453+
2 or 5 = webauthn and fido callback
454+
455+
Values 3,4,5 indicate that the callback function has been already
456+
(de-)registered with the plugin(s).
457+
*/
458+
459+
auto callback_type = reinterpret_cast<intptr_t>(drv.fido_callback);
460+
461+
/*
462+
Do nothing if we use the same driver as last time nad (de-)registration
463+
was already done.
464+
*/
465+
466+
if ((2 < callback_type) && (driver == &drv))
467+
return;
468+
469+
driver = &drv; // Set current driver.
470+
471+
/*
472+
Note: A webauthn callback (callback_type 2 or 5) is registered with both
473+
"fido" and "webauthn" plugins. A fido callback (callback_type 1 or 4)
474+
is registered only with "fido" plugin. And if user did not register any
475+
callback (callback_type 0 or 3) then both plugin callbacks are re-set
476+
to null.
477+
*/
478+
479+
register_callback(prx, "fido", (callback_type % 3) > 1);
480+
register_callback(prx, "webauthn", (callback_type % 3) > 0);
481+
482+
/*
483+
Note: This will be reset to value 0-2 when user deregisters
484+
the callback or registers a new one.
485+
*/
486+
487+
drv.fido_callback = reinterpret_cast<Fido_Callback*>(callback_type + 3);
488+
}
489+
490+
private:
491+
492+
// The driver whose callback will be called by authentication plugins.
493+
494+
static sql::mysql::MySQL_Driver * driver;
495+
496+
/*
497+
Callback function to be registered with authentication plugins.
498+
If the current driver has a stored callback then it is being called.
499+
*/
500+
501+
static void callback_func(const char* msg)
502+
{
503+
if (!driver || !driver->fido_callback)
504+
return;
505+
driver->webauthn_callback(msg);
506+
}
507+
508+
static std::mutex mutex;
509+
std::lock_guard<std::mutex> lock;
510+
511+
static
512+
void register_callback(Proxy *proxy, std::string which, bool set_or_reset)
513+
{
514+
std::string plugin = "authentication_" + which + "_client";
515+
std::string opt = (which == "webauthn" ?
516+
"plugin_authentication_webauthn_client" : which) +
517+
"_messages_callback";
518+
519+
try
520+
{
521+
proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
522+
plugin.c_str(), opt.c_str(),
523+
set_or_reset ? (const void*)callback_func : nullptr
524+
);
525+
}
526+
catch (sql::MethodNotImplementedException &)
527+
{
528+
// Note: Ignore errors when re-setting the callback
529+
530+
if(!set_or_reset)
531+
return;
532+
533+
/*
534+
If failed, plugin is not present, we ignore this fact for deprected
535+
fido plugin.
536+
*/
537+
538+
if ("fido" != which)
539+
throw;
540+
}
541+
catch (sql::InvalidArgumentException &e)
542+
{
543+
if(!set_or_reset)
544+
return;
545+
546+
throw ::sql::SQLException(
547+
"Failed to set fido message callback for "
548+
+ plugin + " plugin");
549+
}
550+
};
551+
552+
};
553+
554+
555+
std::mutex MySQL_Driver::WebAuthn_Callback_Setter::mutex;
556+
sql::mysql::MySQL_Driver *MySQL_Driver::WebAuthn_Callback_Setter::driver
557+
= nullptr;
558+
559+
432560
/*
433561
We support :
434562
- hostName
@@ -1412,62 +1540,14 @@ void MySQL_Connection::init(ConnectOptionsMap & properties)
14121540
}
14131541

14141542
/*
1415-
* Helper class to simplify setting and resetting of the plugin callback.
1543+
Note: If needed the setter will update callback functions registered with
1544+
webauthn/fido authentication plugins to call the callback stored
1545+
in the driver. It also protects the callbacks from being modified while
1546+
connection is being made.
14161547
*/
1417-
struct Fido_Callback_Setter
1418-
{
1419-
NativeAPI::NativeConnectionWrapper *proxy = nullptr;
1420-
1421-
/*
1422-
* Construct the setter using the callback and proxy.
1423-
*/
1424-
Fido_Callback_Setter(Fido_Callback *callback,
1425-
NativeAPI::NativeConnectionWrapper *_proxy) :
1426-
proxy(_proxy)
1427-
{
1428-
if (proxy && callback && *callback)
1429-
{
1430-
callback_mutex.lock();
1431-
try
1432-
{
1433-
fido_callback_instance = callback;
1434-
proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1435-
"authentication_fido_client",
1436-
"fido_messages_callback",
1437-
(const void*)fido_callback_func
1438-
);
1439-
1440-
}
1441-
catch (sql::InvalidArgumentException& e) {
1442-
throw ::sql::SQLUnsupportedOptionException(
1443-
"Failed to set fido message callback for authentication_fido_client plugin",
1444-
OPT_OCI_CONFIG_FILE
1445-
);
1446-
}
1447-
}
1448-
}
1449-
1450-
~Fido_Callback_Setter()
1451-
{
1452-
if(fido_callback_instance && proxy)
1453-
{
1454-
try
1455-
{
1456-
proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
1457-
"authentication_fido_client",
1458-
"fido_messages_callback",
1459-
nullptr);
1460-
}
1461-
catch(...) {}
1462-
fido_callback_instance = nullptr;
1463-
callback_mutex.unlock();
1464-
}
1465-
}
1466-
};
14671548

1468-
Fido_Callback_Setter setter(
1469-
static_cast<MySQL_Driver*>(driver)->fido_callback,
1470-
proxy.get());
1549+
MySQL_Driver::WebAuthn_Callback_Setter
1550+
setter{*static_cast<MySQL_Driver*>(driver), proxy.get()};
14711551

14721552
//Connect loop
14731553
{

0 commit comments

Comments
 (0)