Skip to content

Commit 9ba8550

Browse files
committed
JDBC: Support LDAP/SASL/SCRAM-SHA-1 authentication
1 parent f4bbd35 commit 9ba8550

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

CMakeLists.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,37 @@ set_target_properties(connector-jdbc
265265
VERSION "${MYSQLCPPCONN_SOVERSION}.${CONNECTOR_NUMERIC_VERSION}"
266266
)
267267

268+
#
269+
# Embed rpath information in the connector library.
270+
#
271+
272+
set_property(TARGET connector-jdbc PROPERTY BUILD_WITH_INSTALL_RPATH ON)
273+
274+
# The $ORIGIN/@loader_path entry tells to look for dependent libraries in the
275+
# location where our connector library is stored.
276+
277+
if(APPLE)
278+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "@loader_path")
279+
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
280+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "@loader_path/../private")
281+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "@loader_path/../plugin")
282+
else()
283+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "@loader_path/private")
284+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "@loader_path/plugin")
285+
endif()
286+
elseif(NOT WIN32)
287+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "$ORIGIN")
288+
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
289+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "$ORIGIN/../private")
290+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "$ORIGIN/../plugin")
291+
else()
292+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "$ORIGIN/private")
293+
set_property(TARGET connector-jdbc APPEND PROPERTY INSTALL_RPATH "$ORIGIN/plugin")
294+
endif()
295+
296+
endif()
297+
298+
268299

269300
install(TARGETS connector-jdbc
270301
CONFIGURATIONS Release RelWithDebInfo

cmake/DepFindMySQL.cmake

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
# MYSQL_VERSION, MYSQL_VERSION_ID
4545
# MYSQL_INCLUDE_DIR
4646
# MYSQL_LIB_DIR
47+
# MYSQL_PLUGIN_DIR
4748
# MYSQL_EXTERNAL_DEPENDENCIES
4849
#
4950
##########################################################################
@@ -59,6 +60,7 @@ add_config_option(WITH_MYSQL PATH
5960

6061
add_config_option(MYSQL_INCLUDE_DIR PATH ADVANCED "Path to MYSQL headers.")
6162
add_config_option(MYSQL_LIB_DIR PATH ADVANCED "Path to MYSQL libraries.")
63+
add_config_option(MYSQL_PLUGIN_DIR PATH ADVANCED "Path to MYSQL plugin libraries.")
6264

6365

6466
function(main)
@@ -119,6 +121,10 @@ function(main)
119121
set(MYSQL_LIB_DIR "${MYSQL_DIR}/lib")
120122
endif()
121123

124+
if(NOT DEFINED MYSQL_PLUGIN_DIR AND MYSQL_LIB_DIR)
125+
set(MYSQL_PLUGIN_DIR "${MYSQL_LIB_DIR}/plugin")
126+
endif()
127+
122128
endif()
123129

124130
endif(MYSQL_CONFIG_EXECUTABLE)
@@ -316,6 +322,10 @@ function(main)
316322
# Stores result in MYSQL_EXTERNAL_DEPENDENCIES.
317323
#
318324

325+
if(BUNDLE_DEPENDENCIES)
326+
bundle_dependencies()
327+
endif()
328+
319329
get_dependencies()
320330

321331
message(" version: ${MYSQL_VERSION}")
@@ -449,6 +459,48 @@ endfunction(get_dependencies)
449459
##################################################################
450460

451461

462+
function(bundle_dependencies)
463+
# Get client side plugins and its dependencies
464+
465+
message("MYSQL_PLUGIN_DIR: ${MYSQL_PLUGIN_DIR}")
466+
467+
find_file(SASL_CLIENT
468+
NAMES authentication_ldap_sasl_client.so authentication_ldap_sasl_client.dll authentication_ldap_sasl_client.dylib
469+
HINTS ${MYSQL_PLUGIN_DIR}
470+
NO_DEFAULT_PATH
471+
)
472+
473+
message("SASL_CLIENT: ${SASL_CLIENT}")
474+
475+
if(SASL_CLIENT)
476+
477+
install(FILES ${SASL_CLIENT}
478+
DESTINATION "${INSTALL_LIB_DIR}/plugin"
479+
COMPONENT SASLDll
480+
)
481+
482+
INCLUDE(GetPrerequisites)
483+
GET_PREREQUISITES(${SASL_CLIENT} SASL_DEPENDENCIES 1 0 "" "")
484+
485+
if(SASL_DEPENDENCIES)
486+
message("SASL_DEPENDENCIES: ${SASL_DEPENDENCIES}")
487+
foreach (_file ${SASL_DEPENDENCIES})
488+
get_filename_component(_resolvedFile "${_file}" REALPATH)
489+
install(FILES ${_file} ${_resolvedFile}
490+
DESTINATION "${INSTALL_LIB_DIR}/private"
491+
COMPONENT SASLDll
492+
)
493+
endforeach()
494+
495+
endif()
496+
497+
endif()
498+
499+
endfunction(bundle_dependencies)
500+
501+
##################################################################
502+
503+
452504
function(use_mysql_config)
453505

454506
if(NOT EXISTS "${MYSQL_CONFIG_EXECUTABLE}")
@@ -460,12 +512,15 @@ function(use_mysql_config)
460512

461513
_mysql_conf(MYSQL_INCLUDE_DIR --variable=pkgincludedir)
462514
_mysql_conf(MYSQL_LIB_DIR --variable=pkglibdir)
515+
_mysql_conf(MYSQL_PLUGIN_DIR --variable=plugindir)
463516

464517
file(TO_CMAKE_PATH "${MYSQL_INCLUDE_DIR}" MYSQL_INCLUDE_DIR)
465518
file(TO_CMAKE_PATH "${MYSQL_LIB_DIR}" MYSQL_LIB_DIR)
519+
file(TO_CMAKE_PATH "${MYSQL_PLUGIN_DIR}" MYSQL_PLUGIN_DIR)
466520

467521
set(MYSQL_INCLUDE_DIR "${MYSQL_INCLUDE_DIR}" PARENT_SCOPE)
468522
set(MYSQL_LIB_DIR "${MYSQL_LIB_DIR}" PARENT_SCOPE)
523+
set(MYSQL_PLUGIN_DIR "${MYSQL_PLUGIN_DIR}" PARENT_SCOPE)
469524

470525
# client library version (note: it will be cleaned up in get_version())
471526

examples/connect.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ int main(int argc, const char **argv)
6565
const char* mysql_port = getenv("MYSQL_PORT");
6666
const char* mysql_user = getenv("MYSQL_USER");
6767
const char* mysql_password = getenv("MYSQL_PASSWORD");
68+
const char* ldap_user = getenv("LDAP_USER");
69+
const char* ldap_simple_pwd = getenv("LDAP_SIMPLE_PWD");
70+
const char* ldap_scram_pwd = getenv("LDAP_SCRAM_PWD");
71+
const char* plugin_dir = getenv("PLUGIN_DIR");
6872

6973
string url(EXAMPLE_HOST);
7074
string user(EXAMPLE_USER);
@@ -220,6 +224,88 @@ int main(int argc, const char **argv)
220224

221225
cout << "#" << endl;
222226
cout << "#\t Demo of connection URL syntax" << endl;
227+
228+
if(ldap_simple_pwd)
229+
{
230+
//AUTH USING SASL client side plugin
231+
try {
232+
/*
233+
When using ldap simple authentication, we need to enable cleartext
234+
plugin
235+
*/
236+
237+
sql::ConnectOptionsMap opts;
238+
opts[OPT_HOSTNAME] = url;
239+
// We expect ldap_simple is the mysql user
240+
opts[OPT_USERNAME] = "ldap_simple";
241+
opts[OPT_PASSWORD] = ldap_simple_pwd;
242+
243+
244+
opts[OPT_ENABLE_CLEARTEXT_PLUGIN] = true;
245+
246+
con.reset(driver->connect(opts));
247+
248+
auto *stmt = con->createStatement();
249+
auto *res = stmt->executeQuery("select 'Hello Simple LDAP'");
250+
251+
res->next();
252+
253+
std::cout << res->getString(1) << std::endl;
254+
255+
con->close();
256+
257+
} catch (sql::SQLException &e) {
258+
cout << "#\t\t " << url << " caused expected exception when connecting using ldap_simple" << endl;
259+
cout << "#\t\t " << e.what() << " (MySQL error code: " << e.getErrorCode();
260+
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
261+
throw;
262+
}
263+
}
264+
265+
if(ldap_user && ldap_scram_pwd)
266+
{
267+
//AUTH USING SASL client side plugin
268+
try {
269+
/*
270+
When using client side plugins (this case for SCRAM-SHA1 SASL
271+
authentication, plugin_dir might have to be set (if not using default
272+
location)
273+
*/
274+
275+
sql::ConnectOptionsMap opts;
276+
opts[OPT_HOSTNAME] = url;
277+
opts[OPT_USERNAME] = ldap_user;
278+
opts[OPT_PASSWORD] = ldap_scram_pwd;
279+
280+
if(plugin_dir)
281+
{
282+
opts[OPT_PLUGIN_DIR] = plugin_dir;
283+
}
284+
285+
try {
286+
con.reset(driver->connect(opts));
287+
}
288+
catch(...){}
289+
con.reset(driver->connect(opts));
290+
291+
auto *stmt = con->createStatement();
292+
auto *res = stmt->executeQuery("select 'Hello SASL'");
293+
294+
res->next();
295+
296+
std::cout << res->getString(1) << std::endl;
297+
298+
con->close();
299+
300+
} catch (sql::SQLException &e) {
301+
cout << "#\t\t " << url << " caused expected exception when connecting using "<< user << endl;
302+
cout << "#\t\t " << e.what() << " (MySQL error code: " << e.getErrorCode();
303+
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
304+
throw;
305+
}
306+
}
307+
308+
223309
try {
224310
/*s This will implicitly assume that the host is 'localhost' */
225311
url = "unix://path_to_mysql_socket.sock";

0 commit comments

Comments
 (0)