Skip to content

Commit 383f192

Browse files
authored
Merge pull request duckdb#85 from Mytherin/issue71
Implement duckdb#71: add SSL connection parameters
2 parents 6cc9282 + 15ab269 commit 383f192

File tree

5 files changed

+119
-1
lines changed

5 files changed

+119
-1
lines changed

src/include/mysql_utils.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ struct MySQLConnectionParameters {
3838
uint32_t port = 0;
3939
string unix_socket;
4040
idx_t client_flag = CLIENT_COMPRESS | CLIENT_IGNORE_SIGPIPE | CLIENT_MULTI_STATEMENTS;
41+
unsigned int ssl_mode = SSL_MODE_PREFERRED;
42+
string ssl_ca;
43+
string ssl_ca_path;
44+
string ssl_cert;
45+
string ssl_cipher;
46+
string ssl_crl;
47+
string ssl_crl_path;
48+
string ssl_key;
4149
};
4250

4351
class MySQLUtils {

src/mysql_extension.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,24 @@ unique_ptr<BaseSecret> CreateMySQLSecretFunction(ClientContext &, CreateSecretIn
3838
result->secret_map["port"] = named_param.second.ToString();
3939
} else if (lower_name == "socket") {
4040
result->secret_map["socket"] = named_param.second.ToString();
41+
} else if (lower_name == "ssl_mode") {
42+
result->secret_map["ssl_mode"] = named_param.second.ToString();
43+
} else if (lower_name == "ssl_ca") {
44+
result->secret_map["ssl_ca"] = named_param.second.ToString();
45+
} else if (lower_name == "ssl_capath") {
46+
result->secret_map["ssl_capath"] = named_param.second.ToString();
47+
} else if (lower_name == "ssl_capath") {
48+
result->secret_map["ssl_capath"] = named_param.second.ToString();
49+
} else if (lower_name == "ssl_cert") {
50+
result->secret_map["ssl_cert"] = named_param.second.ToString();
51+
} else if (lower_name == "ssl_cipher") {
52+
result->secret_map["ssl_cipher"] = named_param.second.ToString();
53+
} else if (lower_name == "ssl_crl") {
54+
result->secret_map["ssl_crl"] = named_param.second.ToString();
55+
} else if (lower_name == "ssl_crlpath") {
56+
result->secret_map["ssl_crlpath"] = named_param.second.ToString();
57+
} else if (lower_name == "ssl_key") {
58+
result->secret_map["ssl_key"] = named_param.second.ToString();
4159
} else {
4260
throw InternalException("Unknown named parameter passed to CreateMySQLSecretFunction: " + lower_name);
4361
}
@@ -55,6 +73,14 @@ void SetMySQLSecretParameters(CreateSecretFunction &function) {
5573
function.named_parameters["user"] = LogicalType::VARCHAR;
5674
function.named_parameters["database"] = LogicalType::VARCHAR;
5775
function.named_parameters["socket"] = LogicalType::VARCHAR;
76+
function.named_parameters["ssl_mode"] = LogicalType::VARCHAR;
77+
function.named_parameters["ssl_ca"] = LogicalType::VARCHAR;
78+
function.named_parameters["ssl_capath"] = LogicalType::VARCHAR;
79+
function.named_parameters["ssl_cert"] = LogicalType::VARCHAR;
80+
function.named_parameters["ssl_cipher"] = LogicalType::VARCHAR;
81+
function.named_parameters["ssl_crl"] = LogicalType::VARCHAR;
82+
function.named_parameters["ssl_crlpath"] = LogicalType::VARCHAR;
83+
function.named_parameters["ssl_key"] = LogicalType::VARCHAR;
5884
}
5985

6086
static void LoadInternal(DatabaseInstance &db) {

src/mysql_storage.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,14 @@ static unique_ptr<Catalog> MySQLAttach(StorageExtensionInfo *storage_info, Clien
9090
new_connection_info += AddConnectionOption(kv_secret, "port");
9191
new_connection_info += AddConnectionOption(kv_secret, "database");
9292
new_connection_info += AddConnectionOption(kv_secret, "socket");
93-
93+
new_connection_info += AddConnectionOption(kv_secret, "ssl_mode");
94+
new_connection_info += AddConnectionOption(kv_secret, "ssl_ca");
95+
new_connection_info += AddConnectionOption(kv_secret, "ssl_capath");
96+
new_connection_info += AddConnectionOption(kv_secret, "ssl_cert");
97+
new_connection_info += AddConnectionOption(kv_secret, "ssl_cipher");
98+
new_connection_info += AddConnectionOption(kv_secret, "ssl_crl");
99+
new_connection_info += AddConnectionOption(kv_secret, "ssl_crlpath");
100+
new_connection_info += AddConnectionOption(kv_secret, "ssl_key");
94101
connection_string = new_connection_info + connection_string;
95102
} else if (explicit_secret) {
96103
// secret not found and one was explicitly provided - throw an error

src/mysql_utils.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,43 @@ MySQLConnectionParameters MySQLUtils::ParseConnectionParameters(const string &ds
125125
} else {
126126
result.client_flag &= ~CLIENT_COMPRESS;
127127
}
128+
} else if (key == "ssl_mode") {
129+
set_options.insert("ssl_mode");
130+
auto val = StringUtil::Lower(value);
131+
if (val == "disabled") {
132+
result.ssl_mode = SSL_MODE_DISABLED;
133+
} else if (val == "required") {
134+
result.ssl_mode = SSL_MODE_REQUIRED;
135+
} else if (val == "verify_ca") {
136+
result.ssl_mode = SSL_MODE_VERIFY_CA;
137+
} else if (val == "verify_identity") {
138+
result.ssl_mode = SSL_MODE_VERIFY_IDENTITY;
139+
} else if (val == "preferred") {
140+
result.ssl_mode = SSL_MODE_PREFERRED;
141+
} else {
142+
throw InvalidInputException("Invalid dsn - ssl mode must be either disabled, required, verify_ca, verify_identity or preferred - got %s", value);
143+
}
144+
} else if (key == "ssl_ca") {
145+
set_options.insert("ssl_ca");
146+
result.ssl_ca = value;
147+
} else if (key == "ssl_capath") {
148+
set_options.insert("ssl_capath");
149+
result.ssl_ca_path = value;
150+
} else if (key == "ssl_cert") {
151+
set_options.insert("ssl_cert");
152+
result.ssl_cert = value;
153+
} else if (key == "ssl_cipher") {
154+
set_options.insert("ssl_cipher");
155+
result.ssl_cipher = value;
156+
} else if (key == "ssl_crl") {
157+
set_options.insert("ssl_crl");
158+
result.ssl_crl = value;
159+
} else if (key == "ssl_crlpath") {
160+
set_options.insert("ssl_crlpath");
161+
result.ssl_crl_path = value;
162+
} else if (key == "ssl_key") {
163+
set_options.insert("ssl_key");
164+
result.ssl_key = value;
128165
} else {
129166
throw InvalidInputException("Unrecognized configuration parameter \"%s\" "
130167
"- expected options are host, "
@@ -167,13 +204,36 @@ MySQLConnectionParameters MySQLUtils::ParseConnectionParameters(const string &ds
167204
return result;
168205
}
169206

207+
void SetMySQLOption(MYSQL *mysql, enum mysql_option option, const string &value) {
208+
if (value.empty()) {
209+
return;
210+
}
211+
int rc = mysql_options(mysql, option, value.c_str());
212+
if (rc != 0) {
213+
throw InternalException("Failed to set MySQL option");
214+
}
215+
}
216+
170217
MYSQL *MySQLUtils::Connect(const string &dsn) {
171218
MYSQL *mysql = mysql_init(NULL);
172219
if (!mysql) {
173220
throw IOException("Failure in mysql_init");
174221
}
175222
MYSQL *result;
176223
auto config = ParseConnectionParameters(dsn);
224+
// set SSL options (if any)
225+
if (config.ssl_mode != SSL_MODE_PREFERRED) {
226+
mysql_options(mysql, MYSQL_OPT_SSL_MODE, &config.ssl_mode);
227+
}
228+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CA, config.ssl_ca);
229+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CAPATH, config.ssl_ca_path);
230+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CERT, config.ssl_cert);
231+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CIPHER, config.ssl_cipher);
232+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CRL, config.ssl_crl);
233+
SetMySQLOption(mysql, MYSQL_OPT_SSL_CRLPATH, config.ssl_crl_path);
234+
SetMySQLOption(mysql, MYSQL_OPT_SSL_KEY, config.ssl_key);
235+
236+
// get connection options
177237
const char *host = config.host.empty() ? nullptr : config.host.c_str();
178238
const char *user = config.user.empty() ? nullptr : config.user.c_str();
179239
const char *passwd = config.passwd.empty() ? nullptr : config.passwd.c_str();

test/sql/attach_ssl.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# name: test/sql/attach_ssl.test
2+
# description: ATTACH with SSL parameters
3+
# group: [sql]
4+
5+
require mysql_scanner
6+
7+
require-env MYSQL_TEST_DATABASE_AVAILABLE
8+
9+
# invalid ssl mode
10+
statement error
11+
ATTACH 'host=localhost user=root port=0 database=mysql ssl_mode=xxx' AS simple (TYPE MYSQL_SCANNER)
12+
----
13+
ssl mode must be either
14+
15+
# don't ask me why this works
16+
statement ok
17+
ATTACH 'host=localhost user=root port=0 database=mysql ssl_mode=required ssl_ca=/xxx/ ssl_capath=/xxx/ ssl_cert=/xxx/ ssl_cipher=/xxx/ ssl_crl=/xxx/ ssl_crlpath=/xxx/ ssl_key=/xxx/' AS simple (TYPE MYSQL_SCANNER)

0 commit comments

Comments
 (0)