Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit 3e1db16

Browse files
committed
PERL-1129 Apply TLS options from URI
Prior to this commit, TLS options were parsed, but not applied to the client. This commit sets IO::Socket::SSL options based on tls options on the URI.
1 parent e597b62 commit 3e1db16

File tree

5 files changed

+296
-25
lines changed

5 files changed

+296
-25
lines changed

‎devel/lib/MongoDBTest/Role/Server.pm

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ sub _command_args {
512512
push @args, split ' ', $self->config->{args} if exists $self->config->{args};
513513
push @args, split ' ', $self->command_args;
514514
push @args, '--port', $self->port, '--logpath', $self->logfile, '--logappend';
515-
if ($self->did_auth_setup) {
515+
if ($self->did_auth_setup || $self->did_ssl_auth_setup) {
516516
push @args, '--auth';
517517
}
518518
if (my $ssl = $self->ssl_config) {
@@ -525,7 +525,12 @@ sub _command_args {
525525
if ( $ssl->{disabled_protocols} ) {
526526
push @args, '--sslDisabledProtocols', join(",", @{$ssl->{disabled_protocols}});
527527
}
528-
if (! $self->did_ssl_auth_setup) {
528+
if ( $self->did_ssl_auth_setup) {
529+
if ( $ssl->{client_cert_not_required} ) {
530+
push @args, '--sslAllowConnectionsWithoutCertificates';
531+
}
532+
}
533+
else {
529534
push @args,
530535
$self->server_version >= v3.0.0
531536
? '--sslAllowConnectionsWithoutCertificates'

‎devel/t-dynamic/AUTH-X509.t

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ sub customize_config {
7575
username => $cert_user,
7676
servercn => $server_cn,
7777
certs => { map { $_ => $certs{$_} } qw/server ca client/ },
78+
client_cert_not_required => 1,
7879
};
7980
my $config_path = Path::Tiny->tempfile;
8081
DumpFile( "$config_path", $config );
@@ -117,6 +118,183 @@ sub last_auth_line {
117118
return $last_auth;
118119
}
119120

121+
#--------------------------------------------------------------------------#
122+
# URI vs OO attribute TLS configuration
123+
#--------------------------------------------------------------------------#
124+
subtest "URI vs OO attribute config" => sub {
125+
my $orc = launch_server( customize_config("3.4") );
126+
my $uri = $orc->as_uri;
127+
128+
# naming: "URI; OO" options
129+
my $cases = [
130+
# URI tls undef
131+
{
132+
name => "undef; undef",
133+
uri_tls => "",
134+
opt_tls => undef,
135+
expect_ssl => 0,
136+
error_like => qr/MongoDB::NetworkError/,
137+
},
138+
{
139+
name => "undef; 0",
140+
uri_tls => "",
141+
opt_tls => 0,
142+
expect_ssl => 0,
143+
error_like => qr/MongoDB::NetworkError/,
144+
},
145+
{
146+
name => "undef; 1",
147+
uri_tls => "",
148+
opt_tls => 1,
149+
expect_ssl => 1,
150+
error_like => qr/MongoDB::HandshakeError/,
151+
},
152+
{
153+
name => "undef; SSL_verify_mode=0",
154+
uri_tls => "",
155+
opt_tls => { SSL_verify_mode => 0x00 },
156+
expect_ssl => { SSL_verify_mode => 0x00 },
157+
error_like => qr/MongoDB::DatabaseError: not authorized/,
158+
},
159+
160+
# URI tls false
161+
{
162+
name => "tls=false; SSL_verify_mode=0",
163+
uri_tls => "tls=false",
164+
opt_tls => { SSL_verify_mode => 0x00 },
165+
expect_ssl => 0,
166+
error_like => qr/MongoDB::NetworkError/,
167+
},
168+
{
169+
name => "ssl=false; SSL_verify_mode=0",
170+
uri_tls => "ssl=false",
171+
opt_tls => { SSL_verify_mode => 0x00 },
172+
expect_ssl => 0,
173+
error_like => qr/MongoDB::NetworkError/,
174+
},
175+
176+
# URI tls true
177+
{
178+
name => "tls=true; 0",
179+
uri_tls => "tls=true",
180+
opt_tls => 0,
181+
expect_ssl => 1,
182+
error_like => qr/MongoDB::HandshakeError/,
183+
},
184+
{
185+
name => "ssl=true; 0",
186+
uri_tls => "ssl=true",
187+
opt_tls => 0,
188+
expect_ssl => 1,
189+
error_like => qr/MongoDB::HandshakeError/,
190+
},
191+
{
192+
name => "tls=true; SSL_verify_mode=0",
193+
uri_tls => "tls=true",
194+
opt_tls => { SSL_verify_mode => 0x00 },
195+
expect_ssl => { SSL_verify_mode => 0x00 },
196+
error_like => qr/MongoDB::DatabaseError: not authorized/,
197+
},
198+
{
199+
name => "ssl=true; SSL_verify_mode=0",
200+
uri_tls => "ssl=true",
201+
opt_tls => { SSL_verify_mode => 0x00 },
202+
expect_ssl => { SSL_verify_mode => 0x00 },
203+
error_like => qr/MongoDB::DatabaseError: not authorized/,
204+
},
205+
206+
# URI tls with options (but not client certs)
207+
{
208+
name => "tls=true&tlsInsecure=true; 0",
209+
uri_tls => "tls=true&tlsInsecure=true",
210+
opt_tls => 0,
211+
expect_ssl => { SSL_verify_mode => 0x00, SSL_verifycn_scheme => "none" },
212+
error_like => qr/MongoDB::DatabaseError: not authorized/,
213+
},
214+
{
215+
name => "tlsInsecure=true; 0",
216+
uri_tls => "tlsInsecure=true",
217+
opt_tls => 0,
218+
expect_ssl => { SSL_verify_mode => 0x00, SSL_verifycn_scheme => "none" },
219+
error_like => qr/MongoDB::DatabaseError: not authorized/,
220+
},
221+
{
222+
name => "tlsInsecure=true; SSL_verify_mode=0",
223+
uri_tls => "tlsInsecure=true",
224+
opt_tls => { SSL_verify_mode => 0x01 },
225+
expect_ssl => { SSL_verify_mode => 0x00, SSL_verifycn_scheme => "none" },
226+
error_like => qr/MongoDB::DatabaseError: not authorized/,
227+
},
228+
{
229+
name => "tlsAllowInvalidHostNames=true&tlsCAFile=<path>; undef",
230+
uri_tls => "tlsAllowInvalidHostNames=true&tlsCAFile=$certs{ca}",
231+
opt_tls => undef,
232+
expect_ssl => {
233+
SSL_ca_file => $certs{ca},
234+
SSL_verifycn_scheme => "none",
235+
},
236+
error_like => qr/MongoDB::DatabaseError: not authorized/,
237+
},
238+
{
239+
name => "tlsAllowInvalidCertificates; undef",
240+
uri_tls => "tlsAllowInvalidCertificates=true",
241+
opt_tls => undef,
242+
expect_ssl => { SSL_verify_mode => 0x00 },
243+
error_like => qr/MongoDB::DatabaseError: not authorized/,
244+
},
245+
{
246+
name => "tlsCertificateKeyFilePassword; undef",
247+
uri_tls => "tlsCertificateKeyFilePassword=password",
248+
opt_tls => undef,
249+
expect_ssl => {
250+
SSL_passwd_cb => "password",
251+
},
252+
error_like => qr/MongoDB::HandshakeError/,
253+
},
254+
255+
# URI tls with options (with certs and X509 auth)
256+
{
257+
name => "tlsInsecure=true&tlsCertificateKeyFile=<path>; undef",
258+
uri_tls => "tlsInsecure=true&tlsCertificateKeyFile=$certs{client}&authMechanism=MONGODB-X509",
259+
opt_tls => undef,
260+
expect_ssl => {
261+
SSL_verify_mode => 0x00,
262+
SSL_verifycn_scheme => "none",
263+
SSL_cert_file => $certs{client},
264+
},
265+
error_like => undef,
266+
},
267+
268+
];
269+
270+
for my $c (@$cases) {
271+
subtest $c->{name}, sub {
272+
local $SIG{__WARN__} = sub { 0 };
273+
local *MongoDB::_Constants::WITH_ASSERTS = "";
274+
my $test_uri = $uri . "/?$c->{uri_tls}";
275+
my $mc = MongoDB->connect( $test_uri,
276+
defined $c->{opt_tls} ? { ssl => $c->{opt_tls} } : () );
277+
278+
if (ref $c->{expect_ssl} && exists $c->{expect_ssl}{SSL_passwd_cb}) {
279+
my $pwd = delete $c->{expect_ssl}{SSL_passwd_cb};
280+
my $cb = delete $mc->{ssl}{SSL_passwd_cb};
281+
is( ref $cb, "CODE", "password callback is code")
282+
&& is( $cb->(), $pwd, "callback gave correct password");
283+
}
284+
is_deeply( $mc->{ssl}, $c->{expect_ssl}, "ssl attribute" );
285+
286+
my $coll = $mc->ns("x509.test_collection");
287+
my $err = exception { $coll->insert_one({}) };
288+
if ( defined $c->{error_like} ) {
289+
like( $err, $c->{error_like}, "insert should error with $c->{error_like}" );
290+
}
291+
else {
292+
is( $err, undef, "insert_one should not error" );
293+
}
294+
};
295+
}
296+
};
297+
120298
#--------------------------------------------------------------------------#
121299
# Test X509 authentication with username provided
122300
#--------------------------------------------------------------------------#

‎lib/MongoDB/MongoClient.pm

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -931,8 +931,9 @@ B<Disabling certificate or hostname verification is a security risk and is not
931931
recommended>.
932932
933933
This may be set to the string 'true' or 'false' in a connection string with the
934-
C<ssl> option, which will enable ssl with default configuration. (A future
935-
version of the driver may support customizing ssl via the connection string.)
934+
C<ssl> option, which will enable ssl with default configuration. (See
935+
L<connection string URI|/CONNECTION STRING URI> for additional TLS
936+
configuration options.)
936937
937938
=cut
938939

@@ -944,14 +945,83 @@ has ssl => (
944945

945946
sub _build_ssl {
946947
my ($self) = @_;
947-
my $ssl = $self->__uri_or_else(
948-
u => 'ssl',
949-
e => 'ssl',
950-
d => 0,
951-
);
952-
# allow optional arguments to override as long as SSL is already enabled
953-
if ( $ssl && exists $self->_deferred->{ssl} ) {
954-
return $self->_deferred->{ssl};
948+
949+
# options will be undef if not provided
950+
my $uri_ssl = $self->__ssl_from_uri();
951+
my $opt_ssl = exists $self->_deferred->{ssl} ? $self->_deferred->{ssl} : undef;
952+
953+
# no SSL options exist
954+
if ( !defined $uri_ssl && !defined $opt_ssl ) {
955+
return 0;
956+
}
957+
958+
# validate deferred ssl arg type
959+
if ( ref $opt_ssl && ref $opt_ssl ne 'HASH' ) {
960+
MongoDB::UsageError->throw("ssl attribute must be scalar or hashref")
961+
}
962+
963+
# no URI SSL defined means use opts SSL
964+
if ( !defined $uri_ssl ) {
965+
return $opt_ssl;
966+
}
967+
968+
# if URI SSL is false, that takes precedence
969+
if ( ! $uri_ssl ) {
970+
return $uri_ssl;
971+
}
972+
973+
# if opt SSL isn't a hashref, it's irrelevant
974+
if ( ref $opt_ssl ne 'HASH' ) {
975+
return $uri_ssl;
976+
}
977+
978+
# if uri SSL isn't a hashref, we prefer opt SSL hashref
979+
if ( ref $uri_ssl ne 'HASH' ) {
980+
return $opt_ssl;
981+
}
982+
983+
# both are hashes, so merge them with URI taking precedence
984+
return { %$opt_ssl, %$uri_ssl };
985+
}
986+
987+
my @tls_options = qw(
988+
tlsallowinvalidcertificates
989+
tlsallowinvalidhostnames
990+
tlscafile
991+
tlscertificatekeyfile
992+
tlscertificatekeyfilepassword
993+
tlsinsecure
994+
);
995+
996+
sub __ssl_from_uri {
997+
my ($self) = @_;
998+
my $uri_options = $self->_uri->options;
999+
my $saw_tls_boolean = exists $uri_options->{tls};
1000+
my $saw_tls_options = grep { length } map { exists $uri_options->{$_} } @tls_options;
1001+
1002+
if (!$saw_tls_options) {
1003+
return $saw_tls_boolean ? $uri_options->{tls} : undef;
1004+
}
1005+
1006+
my $ssl = {};
1007+
if (exists($uri_options->{tlscafile})) {
1008+
$ssl->{SSL_ca_file} = $uri_options->{tlscafile};
1009+
}
1010+
if (exists($uri_options->{tlscertificatekeyfile})) {
1011+
$ssl->{SSL_cert_file} = $uri_options->{tlscertificatekeyfile};
1012+
}
1013+
if (exists($uri_options->{tlscertificatekeyfilepassword})) {
1014+
$ssl->{SSL_passwd_cb} = sub { $uri_options->{tlscertificatekeyfilepassword} };
1015+
}
1016+
if (exists($uri_options->{tlsallowinvalidhostnames})) {
1017+
$ssl->{SSL_verifycn_scheme} = 'none';
1018+
}
1019+
if (exists($uri_options->{tlsallowinvalidcertificates})) {
1020+
$ssl->{SSL_verify_mode} = 0x00;
1021+
}
1022+
if (exists($uri_options->{tlsinsecure})) {
1023+
$ssl->{SSL_verify_mode} = 0x00;
1024+
$ssl->{SSL_verifycn_scheme} = 'none';
9551025
}
9561026
return $ssl;
9571027
}
@@ -2089,6 +2159,13 @@ The currently supported connection string options are:
20892159
* C<socketCheckIntervalMS>
20902160
* C<socketTimeoutMS>
20912161
* C<ssl>
2162+
* C<tls> (an alias for C<ssl>)
2163+
* C<tlsAllowInvalidCertificates>
2164+
* C<tlsAllowInvalidHostnames>
2165+
* C<tlsCAFile>
2166+
* C<tlsCertificateKeyFile>
2167+
* C<tlsCertificateKeyFilePassword>
2168+
* C<tlsInsecure>
20922169
* C<w>
20932170
* C<wTimeoutMS>
20942171
* C<zlibCompressionLevel>

‎lib/MongoDB/_URI.pm

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,9 @@ sub _build_valid_options {
125125
serverSelectionTryOnce
126126
socketCheckIntervalMS
127127
socketTimeoutMS
128-
ssl
129128
tlsCAFile
130129
tlsCertificateKeyFile
131130
tlsCertificateKeyFilePassword
132-
tlsCertificateKeyPassword
133131
w
134132
wTimeoutMS
135133
zlibCompressionLevel
@@ -160,16 +158,15 @@ has _valid_str_to_bool_options => (
160158
sub _build_valid_str_to_bool_options {
161159
return {
162160
map { lc($_) => 1 } qw(
163-
ssl
164161
journal
162+
retryReads
163+
retryWrites
165164
serverselectiontryonce
165+
ssl
166166
tls
167167
tlsAllowInvalidCertificates
168168
tlsAllowInvalidHostnames
169169
tlsInsecure
170-
retryWrites
171-
retryReads
172-
tlsAllowInsecure
173170
)
174171
};
175172
}
@@ -319,14 +316,28 @@ sub _parse_options {
319316
$parsed{$lc_k} = $v;
320317
}
321318
}
322-
if (exists $parsed{'tlsinsecure'} || exists $parsed{'tlsallowinsecure'}) {
323-
if (exists $parsed{'tlsallowinvalidcertificates'} || exists $parsed{'tlsallowinvalidhostnames'}) {
324-
MongoDB::Error->throw('tlsInsecure conflicts with other options');
325-
}
319+
if (
320+
exists $parsed{tlsinsecure}
321+
&& ( exists $parsed{tlsallowinvalidcertificates}
322+
|| exists $parsed{tlsallowinvalidhostnames} )
323+
)
324+
{
325+
MongoDB::Error->throw('tlsInsecure conflicts with other options');
326326
}
327-
if ( exists ($parsed{'tls'}) && exists($parsed{'ssl'}) && $parsed{'tls'} != $parsed{'ssl'}) {
327+
# If both exist, they must be identical.
328+
if ( exists( $parsed{tls} )
329+
&& exists( $parsed{ssl} )
330+
&& $parsed{tls} != $parsed{ssl} )
331+
{
328332
MongoDB::Error->throw('tls and ssl must have the same value');
329333
}
334+
# If either exists, set them both.
335+
if ( exists $parsed{tls} ) {
336+
$parsed{ssl} = $parsed{tls};
337+
}
338+
elsif ( exists $parsed{ssl} ) {
339+
$parsed{tls} = $parsed{ssl};
340+
}
330341
return \%parsed;
331342
}
332343

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /