Skip to content

Commit e710b13

Browse files
committed
Various fixes
1 parent a715fef commit e710b13

File tree

7 files changed

+228
-87
lines changed

7 files changed

+228
-87
lines changed

src/MongoDB.Driver/Core/Configuration/ClusterBuilderExtensions.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using MongoDB.Driver.Authentication;
2424
using MongoDB.Driver.Authentication.Gssapi;
2525
using MongoDB.Driver.Authentication.Oidc;
26+
using MongoDB.Driver.Core.Connections;
2627
using MongoDB.Driver.Core.Events.Diagnostics;
2728
using MongoDB.Driver.Core.Misc;
2829

@@ -121,10 +122,11 @@ public static ClusterBuilder ConfigureWithConnectionString(
121122
if (connectionString.ProxyHost != null)
122123
{
123124
builder = builder.ConfigureTcp(s => s.With(
124-
proxyHost: connectionString.ProxyHost,
125-
proxyPort: connectionString.ProxyPort,
126-
proxyUsername: connectionString.ProxyUsername,
127-
proxyPassword: connectionString.ProxyPassword));
125+
socks5ProxySettings: Socks5ProxySettings.Create(
126+
connectionString.ProxyHost,
127+
connectionString.ProxyPort,
128+
connectionString.ProxyUsername,
129+
connectionString.ProxyPassword)));
128130
}
129131

130132
if (connectionString.SocketTimeout != null)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Driver.Core.Misc;
17+
using MongoDB.Shared;
18+
19+
namespace MongoDB.Driver.Core.Connections;
20+
21+
/// <summary>
22+
/// Represents the settings for SOCKS5 authentication.
23+
/// </summary>
24+
public abstract class Socks5AuthenticationSettings
25+
{
26+
/// <summary>
27+
/// Creates authentication settings that do not require any authentication.
28+
/// </summary>
29+
public static Socks5AuthenticationSettings None => new NoAuthenticationSettings();
30+
31+
/// <summary>
32+
/// Creates authentication settings for username and password.
33+
/// </summary>
34+
/// <param name="username"></param>
35+
/// <param name="password"></param>
36+
/// <returns></returns>
37+
public static Socks5AuthenticationSettings UsernamePassword(string username, string password)
38+
=> new UsernamePasswordAuthenticationSettings(username, password);
39+
40+
/// <summary>
41+
/// Represents settings for no authentication in SOCKS5.
42+
/// </summary>
43+
public sealed class NoAuthenticationSettings : Socks5AuthenticationSettings
44+
{
45+
}
46+
47+
/// <summary>
48+
/// Represents settings for username and password authentication in SOCKS5.
49+
/// </summary>
50+
public sealed class UsernamePasswordAuthenticationSettings : Socks5AuthenticationSettings
51+
{
52+
/// <summary>
53+
/// Gets the username for authentication.
54+
/// </summary>
55+
public string Username { get; }
56+
57+
/// <summary>
58+
/// Gets the password for authentication.
59+
/// </summary>
60+
public string Password { get; }
61+
62+
internal UsernamePasswordAuthenticationSettings(string username, string password)
63+
{
64+
Username = Ensure.IsNotNullOrEmpty(username, nameof(username));
65+
Password = Ensure.IsNotNullOrEmpty(password, nameof(password));
66+
}
67+
68+
/// <inheritdoc />
69+
public override bool Equals(object obj)
70+
{
71+
if (obj is UsernamePasswordAuthenticationSettings other)
72+
{
73+
return Username == other.Username && Password == other.Password;
74+
}
75+
76+
return false;
77+
}
78+
79+
/// <inheritdoc />
80+
public override int GetHashCode()
81+
{
82+
return new Hasher()
83+
.Hash(Username)
84+
.Hash(Password)
85+
.GetHashCode();
86+
}
87+
}
88+
}

src/MongoDB.Driver/Core/Connections/Socks5Helper.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ internal static class Socks5Helper
4545
private const int BufferSize = 512;
4646

4747
//TODO Make an async version of this method
48-
public static void PerformSocks5Handshake(Stream stream, EndPoint endPoint, string proxyUsername, string proxyPassword, CancellationToken cancellationToken)
48+
public static void PerformSocks5Handshake(Stream stream, EndPoint endPoint, Socks5AuthenticationSettings authenticationSettings, CancellationToken cancellationToken)
4949
{
5050
var (targetHost, targetPort) = endPoint.GetHostAndPort();
5151

5252
var buffer = ArrayPool<byte>.Shared.Rent(BufferSize);
5353
try
5454
{
55-
var useAuth = !string.IsNullOrEmpty(proxyUsername) && !string.IsNullOrEmpty(proxyPassword);
55+
var useAuth = authenticationSettings is Socks5AuthenticationSettings.UsernamePasswordAuthenticationSettings;
5656

5757
// Greeting request
5858
// +----+----------+----------+
@@ -97,6 +97,10 @@ public static void PerformSocks5Handshake(Stream stream, EndPoint endPoint, stri
9797
throw new IOException("SOCKS5 proxy requires authentication, but no credentials were provided.");
9898
}
9999

100+
var usernamePasswordAuthenticationSettings = (Socks5AuthenticationSettings.UsernamePasswordAuthenticationSettings)authenticationSettings;
101+
var proxyUsername = usernamePasswordAuthenticationSettings!.Username;
102+
var proxyPassword = usernamePasswordAuthenticationSettings!.Password;
103+
100104
// Authentication request
101105
// +----+------+----------+------+----------+
102106
// |VER | ULEN | UNAME | PLEN | PASSWD |

src/MongoDB.Driver/Core/Connections/Socks5ProxySettings.cs

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@
1313
* limitations under the License.
1414
*/
1515

16-
using System;
16+
using System.Text;
1717
using MongoDB.Driver.Core.Misc;
18+
using MongoDB.Shared;
1819

1920
namespace MongoDB.Driver.Core.Connections
2021
{
2122
/// <summary>
2223
/// Represents the settings for a SOCKS5 proxy connection.
2324
/// </summary>
24-
public class Socks5ProxySettings
25+
public sealed class Socks5ProxySettings
2526
{
27+
private const int DefaultPort = 1080;
28+
2629
/// <summary>
2730
/// Gets the host of the SOCKS5 proxy.
2831
/// </summary>
@@ -38,85 +41,65 @@ public class Socks5ProxySettings
3841
/// </summary>
3942
public Socks5AuthenticationSettings Authentication { get; }
4043

41-
private Socks5ProxySettings(string host, int port, Socks5AuthenticationSettings authentication)
44+
internal Socks5ProxySettings(string host, int? port, Socks5AuthenticationSettings authentication)
4245
{
4346
Host = Ensure.IsNotNullOrEmpty(host, nameof(host));
44-
Port = Ensure.IsBetween(port, 0, 65535, nameof(port));
45-
Authentication = Ensure.IsNotNull(authentication, nameof(authentication));
47+
Port = port is null ? DefaultPort : Ensure.IsBetween(port.Value, 1, 65535, nameof(port));
48+
Authentication = authentication ?? Socks5AuthenticationSettings.None;
4649
}
4750

51+
// Convenience method used internally.
4852
internal static Socks5ProxySettings Create(string host, int? port, string username, string password)
4953
{
50-
Socks5AuthenticationSettings authentication;
54+
var authentication = !string.IsNullOrEmpty(username) ?
55+
Socks5AuthenticationSettings.UsernamePassword(username, password) : Socks5AuthenticationSettings.None;
5156

52-
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
53-
{
54-
authentication = Socks5AuthenticationSettings.UsernamePassword(username, password);
55-
}
56-
else
57+
return new Socks5ProxySettings(host, port, authentication);
58+
}
59+
60+
/// <inheritdoc />
61+
public override bool Equals(object obj)
62+
{
63+
if (obj is Socks5ProxySettings other)
5764
{
58-
authentication = Socks5AuthenticationSettings.None;
65+
return Host == other.Host &&
66+
Port == other.Port &&
67+
Equals(Authentication, other.Authentication);
5968
}
6069

61-
return new Socks5ProxySettings(host, port ?? 1080, authentication);
70+
return false;
6271
}
6372

64-
/// <summary>
65-
/// Creates a new instance of <see cref="Socks5ProxySettings"/>.
66-
/// </summary>
67-
/// <param name="host">The host.</param>
68-
/// <param name="port">The port</param>
69-
/// <param name="authentication">The authentication settings.</param>
70-
/// <returns></returns>
71-
public static Socks5ProxySettings Create(string host, int port = 1080, Socks5AuthenticationSettings authentication = null)
73+
/// <inheritdoc />
74+
public override int GetHashCode()
7275
{
73-
return new Socks5ProxySettings(host, port, authentication ?? Socks5AuthenticationSettings.None);
76+
return new Hasher()
77+
.Hash(Host)
78+
.Hash(Port)
79+
.Hash(Authentication)
80+
.GetHashCode();
7481
}
75-
}
7682

77-
internal enum Socks5AuthenticationType
78-
{
79-
None,
80-
UsernamePassword
81-
}
8283

83-
/// <summary>
84-
/// Represents the settings for SOCKS5 authentication.
85-
/// </summary>
86-
public abstract class Socks5AuthenticationSettings
87-
{
88-
internal abstract Socks5AuthenticationType Type { get; }
89-
90-
/// <summary>
91-
/// Creates authentication settings that do not require any authentication.
92-
/// </summary>
93-
public static Socks5AuthenticationSettings None => new NoAuthenticationSettings();
94-
95-
/// <summary>
96-
/// Creates authentication settings for username and password.
97-
/// </summary>
98-
/// <param name="username"></param>
99-
/// <param name="password"></param>
100-
/// <returns></returns>
101-
public static Socks5AuthenticationSettings UsernamePassword(string username, string password)
102-
=> new UsernamePasswordAuthenticationSettings(username, password);
103-
104-
private sealed class NoAuthenticationSettings : Socks5AuthenticationSettings
84+
/// <inheritdoc/>
85+
public override string ToString()
10586
{
106-
internal override Socks5AuthenticationType Type => Socks5AuthenticationType.None;
107-
}
108-
109-
private sealed class UsernamePasswordAuthenticationSettings : Socks5AuthenticationSettings
110-
{
111-
internal override Socks5AuthenticationType Type => Socks5AuthenticationType.UsernamePassword;
112-
public string Username { get; }
113-
public string Password { get; }
114-
115-
internal UsernamePasswordAuthenticationSettings(string username, string password)
87+
var sb = new StringBuilder();
88+
sb.Append("{ Host : ");
89+
sb.Append(Host);
90+
sb.Append(", Port : ");
91+
sb.Append(Port);
92+
sb.Append(", Authentication : ");
93+
94+
sb.Append(Authentication switch
11695
{
117-
Username = Ensure.IsNotNullOrEmpty(username, nameof(username));
118-
Password = Ensure.IsNotNullOrEmpty(password, nameof(password));
119-
}
96+
Socks5AuthenticationSettings.UsernamePasswordAuthenticationSettings up =>
97+
$"UsernamePassword (Username: {up.Username}, Password: {up.Password})",
98+
_ => "None"
99+
});
100+
101+
sb.Append(" }");
102+
return sb.ToString();
120103
}
121104
}
122105
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
namespace MongoDB.Driver.Core.Connections;
17+
18+
/// <summary>
19+
/// Builder for creating <see cref="Socks5ProxySettings"/>.
20+
/// </summary>
21+
public class Socks5ProxySettingsBuilder
22+
{
23+
private readonly string _host;
24+
private int? _port;
25+
private Socks5AuthenticationSettings _authentication;
26+
27+
/// <summary>
28+
/// Initializes a new instance of the <see cref="Socks5ProxySettingsBuilder"/> class with the specified host.
29+
/// </summary>
30+
/// <param name="host">The host of the SOCKS5 proxy.</param>
31+
public Socks5ProxySettingsBuilder(string host)
32+
{
33+
_host = host;
34+
}
35+
36+
/// <summary>
37+
/// Sets the port for the SOCKS5 proxy.
38+
/// </summary>
39+
/// <param name="port">The port of the SOCKS5 proxy.</param>
40+
/// <returns>The builder instance for method chaining.</returns>
41+
public Socks5ProxySettingsBuilder Port(int port)
42+
{
43+
_port = port;
44+
return this;
45+
}
46+
47+
/// <summary>
48+
/// Sets the authentication for the SOCKS5 proxy using username and password.
49+
/// </summary>
50+
/// <param name="username">The username for authentication.</param>
51+
/// <param name="password">The password for authentication.</param>
52+
/// <returns>The builder instance for method chaining.</returns>
53+
public Socks5ProxySettingsBuilder UsernameAndPasswordAuth(string username, string password)
54+
{
55+
_authentication = Socks5AuthenticationSettings.UsernamePassword(username, password);
56+
return this;
57+
}
58+
59+
/// <summary>
60+
/// Builds the <see cref="Socks5ProxySettings"/> instance with the specified settings.
61+
/// </summary>
62+
public Socks5ProxySettings Build()
63+
{
64+
return new Socks5ProxySettings(_host, _port, _authentication);
65+
}
66+
}

0 commit comments

Comments
 (0)