Skip to content

Commit 047dbbf

Browse files
committed
WL14113 JDBC: Support LDAP/SASL/SCRAM-SHA-1 authentication
1 parent d458e34 commit 047dbbf

File tree

3 files changed

+193
-32
lines changed

3 files changed

+193
-32
lines changed

CMakeLists.txt

Lines changed: 67 additions & 29 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
@@ -346,57 +377,64 @@ endif()
346377

347378
if(BUNDLE_DEPENDENCIES)
348379

349-
message("looking for bundled client lib deps: ${MYSQL_EXTERNAL_DEPENDENCIES}")
380+
message("looking for bundled client lib deps: ${MYSQL_EXTERNAL_DEPENDENCIES}")
381+
382+
#
383+
# Note: Currently we simply copy all libraries bundled in the server installation
384+
# filtering-out these that we know are not needed on the client side.
385+
#
386+
# More precise approach would be to get information about external dependencies
387+
# from mysql_config and other sources and bundle only these libraries that we
388+
# know are needed. But this is not implemented yet. Note also that dependencies
389+
# reported by mysql_config in MYSQL_EXTERNAL_DEPENDENCIES do not include things
390+
# like client-side plugins and their dependencies.
391+
#
350392

351-
if(MYSQL_EXTERNAL_DEPENDENCIES)
393+
file(GLOB _bundled1 "${MYSQL_LIB_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
394+
file(GLOB _bundled2 "${MYSQL_LIB_DIR}/private/*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
352395

353-
foreach(lib ${MYSQL_EXTERNAL_DEPENDENCIES})
396+
foreach(lib IN LISTS _bundled1 _bundled2)
354397

355-
#message("-- looking for: ${MYSQL_LIB_DIR}/*${lib}*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
356-
file(GLOB _bundled1 "${MYSQL_LIB_DIR}/private/*${CMAKE_SHARED_LIBRARY_PREFIX}${lib}${CMAKE_SHARED_LIBRARY_SUFFIX}*")
357-
file(GLOB _bundled2 "${MYSQL_LIB_DIR}/*${CMAKE_SHARED_LIBRARY_PREFIX}${lib}${CMAKE_SHARED_LIBRARY_SUFFIX}*")
398+
get_filename_component(lib_name ${lib} NAME_WE)
358399

359-
if(_bundled1 OR _bundled2)
400+
# ssl|crypto are bundled on cdk/cmake/DepFindSSL.cmake
401+
if(NOT lib_name MATCHES "mysql|protobuf|lber|ldap_r|ssl|crypto")
360402

361-
message("found bundled libs: ${_bundled1} ${_bundled2}")
403+
message("found bundled libs: ${lib}")
362404

363-
install(FILES ${_bundled1} ${_bundled2}
364-
DESTINATION "${INSTALL_LIB_DIR}"
365-
COMPONENT JDBCDll
366-
)
405+
install(FILES "${lib}"
406+
DESTINATION "${INSTALL_LIB_DIR}/private"
407+
COMPONENT JDBCDll
408+
)
367409

368410
endif()
369411

370412
endforeach()
371413

372-
else()
414+
file(GLOB _bundled "${MYSQL_PLUGIN_DIR}/*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
373415

374-
#
375-
# If detection of external MySQL library dependencies did not work for
376-
# some reason, copy known dependencies if they are bundled with
377-
# MySQL. This list would need to be updated if new required dependencies
378-
# appear.
379-
#
416+
foreach(lib ${_bundled})
380417

381-
file(GLOB _bundled "${MYSQL_DIR}/lib/*${CMAKE_SHARED_LIBRARY_SUFFIX}*")
418+
get_filename_component(lib_name ${lib} NAME_WE)
382419

383-
foreach(lib ${_bundled})
384-
if(lib MATCHES "eay|ssl|crypto")
420+
if(
421+
lib_name MATCHES "_client"
422+
AND NOT lib_name MATCHES "qa_auth_client"
423+
)
385424

386-
message("found bundled libs: ${lib}")
425+
message("found client plugin: ${lib}")
387426

388-
install(FILES "${lib}"
389-
DESTINATION "${INSTALL_LIB_DIR}"
390-
COMPONENT JDBCDll
391-
)
427+
install(FILES "${lib}"
428+
DESTINATION "${INSTALL_LIB_DIR}/plugin"
429+
COMPONENT JDBCDll
430+
)
392431

393432
endif()
394433
endforeach()
395434

396-
endif()
397-
398435
endif(BUNDLE_DEPENDENCIES)
399436

437+
400438
if(WITH_TESTS)
401439

402440
if(NOT BUILD_SHARED_LIBS)

cmake/DepFindMySQL.cmake

Lines changed: 14 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)
@@ -146,6 +152,11 @@ function(main)
146152
FORCE
147153
)
148154

155+
set(MYSQL_PLUGIN_DIR "${MYSQL_PLUGIN_DIR}"
156+
CACHE PATH "Path to MYSQL plugin libraries (computed)."
157+
FORCE
158+
)
159+
149160

150161
#
151162
# Searching for library.
@@ -460,12 +471,15 @@ function(use_mysql_config)
460471

461472
_mysql_conf(MYSQL_INCLUDE_DIR --variable=pkgincludedir)
462473
_mysql_conf(MYSQL_LIB_DIR --variable=pkglibdir)
474+
_mysql_conf(MYSQL_PLUGIN_DIR --variable=plugindir)
463475

464476
file(TO_CMAKE_PATH "${MYSQL_INCLUDE_DIR}" MYSQL_INCLUDE_DIR)
465477
file(TO_CMAKE_PATH "${MYSQL_LIB_DIR}" MYSQL_LIB_DIR)
478+
file(TO_CMAKE_PATH "${MYSQL_PLUGIN_DIR}" MYSQL_PLUGIN_DIR)
466479

467480
set(MYSQL_INCLUDE_DIR "${MYSQL_INCLUDE_DIR}" PARENT_SCOPE)
468481
set(MYSQL_LIB_DIR "${MYSQL_LIB_DIR}" PARENT_SCOPE)
482+
set(MYSQL_PLUGIN_DIR "${MYSQL_PLUGIN_DIR}" PARENT_SCOPE)
469483

470484
# client library version (note: it will be cleaned up in get_version())
471485

examples/connect.cpp

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ 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_user_dn = getenv("LDAP_USER_DN");
70+
const char* ldap_simple_pwd = getenv("LDAP_SIMPLE_PWD");
71+
const char* ldap_scram_pwd = getenv("LDAP_SCRAM_PWD");
72+
const char* plugin_dir = getenv("PLUGIN_DIR");
6873

6974
string url(EXAMPLE_HOST);
7075
string user(EXAMPLE_USER);
@@ -101,7 +106,6 @@ int main(int argc, const char **argv)
101106
pass = mysql_password;
102107
}
103108

104-
105109
/* sql::ResultSet.rowsCount() returns size_t */
106110
size_t row;
107111
stringstream sql;
@@ -120,8 +124,6 @@ int main(int argc, const char **argv)
120124
try {
121125
sql::Driver * driver = sql::mysql::get_driver_instance();
122126

123-
124-
125127
/* Using the Driver to create a connection */
126128
boost::scoped_ptr< sql::Connection > con(driver->connect(url, user, pass));
127129

@@ -220,6 +222,113 @@ int main(int argc, const char **argv)
220222

221223
cout << "#" << endl;
222224
cout << "#\t Demo of connection URL syntax" << endl;
225+
226+
//Lets first create ldap and sasl users
227+
if(ldap_user || ldap_user_dn)
228+
{
229+
if(ldap_user_dn)
230+
{
231+
stringstream user_create;
232+
stmt.reset(con->createStatement());
233+
user_create << "CREATE USER ldap_simple IDENTIFIED WITH "
234+
"authentication_ldap_simple AS \""
235+
<< ldap_user_dn
236+
<< "\"";
237+
try{
238+
stmt->execute(user_create.str());
239+
}catch(...)
240+
{}
241+
}
242+
243+
if(ldap_user)
244+
{
245+
stringstream user_create;
246+
stmt.reset(con->createStatement());
247+
user_create << "CREATE USER "
248+
<< ldap_user
249+
<< " IDENTIFIED WITH authentication_ldap_sasl";
250+
try{
251+
stmt->execute(user_create.str());
252+
}catch(...)
253+
{}
254+
}
255+
}
256+
257+
if(ldap_simple_pwd)
258+
{
259+
//AUTH USING SASL client side plugin
260+
try {
261+
/*
262+
When using ldap simple authentication, we need to enable cleartext
263+
plugin
264+
*/
265+
266+
sql::ConnectOptionsMap opts;
267+
opts[OPT_HOSTNAME] = url;
268+
opts[OPT_USERNAME] = "ldap_simple";
269+
opts[OPT_PASSWORD] = ldap_simple_pwd;
270+
271+
opts[OPT_ENABLE_CLEARTEXT_PLUGIN] = true;
272+
273+
con.reset(driver->connect(opts));
274+
275+
auto *stmt = con->createStatement();
276+
auto *res = stmt->executeQuery("select 'Hello Simple LDAP'");
277+
278+
res->next();
279+
280+
std::cout << res->getString(1) << std::endl;
281+
282+
con->close();
283+
284+
} catch (sql::SQLException &e) {
285+
cout << "#\t\t " << url << " caused expected exception when connecting using ldap_simple" << endl;
286+
cout << "#\t\t " << e.what() << " (MySQL error code: " << e.getErrorCode();
287+
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
288+
throw;
289+
}
290+
}
291+
292+
if(ldap_user && ldap_scram_pwd)
293+
{
294+
//AUTH USING SASL client side plugin
295+
try {
296+
/*
297+
When using client side plugins (this case for SCRAM-SHA1 SASL
298+
authentication, plugin_dir might have to be set (if not using default
299+
location)
300+
*/
301+
302+
sql::ConnectOptionsMap opts;
303+
opts[OPT_HOSTNAME] = url;
304+
opts[OPT_USERNAME] = ldap_user;
305+
opts[OPT_PASSWORD] = ldap_scram_pwd;
306+
307+
if(plugin_dir)
308+
{
309+
opts[OPT_PLUGIN_DIR] = plugin_dir;
310+
}
311+
312+
con.reset(driver->connect(opts));
313+
314+
auto *stmt = con->createStatement();
315+
auto *res = stmt->executeQuery("select 'Hello SASL'");
316+
317+
res->next();
318+
319+
std::cout << res->getString(1) << std::endl;
320+
321+
con->close();
322+
323+
} catch (sql::SQLException &e) {
324+
cout << "#\t\t " << url << " caused expected exception when connecting using "<< ldap_user << endl;
325+
cout << "#\t\t " << e.what() << " (MySQL error code: " << e.getErrorCode();
326+
cout << ", SQLState: " << e.getSQLState() << " )" << endl;
327+
throw;
328+
}
329+
}
330+
331+
223332
try {
224333
/*s This will implicitly assume that the host is 'localhost' */
225334
url = "unix://path_to_mysql_socket.sock";

0 commit comments

Comments
 (0)