Skip to content

Commit ca13cf0

Browse files
Allow HTTPS sources that have SSL certificate problems (#5674)
1 parent b869c3c commit ca13cf0

20 files changed

Lines changed: 785 additions & 16 deletions

File tree

src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetSourcesService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ private IReadOnlyList<PackageSource> GetPackageSourcesToUpdate(IReadOnlyList<Pac
9494
&& packageSource.Source.Equals(packageSourceContextInfo.Source, StringComparison.InvariantCulture)
9595
&& packageSource.ProtocolVersion == packageSourceContextInfo.ProtocolVersion
9696
&& packageSource.AllowInsecureConnections == packageSourceContextInfo.AllowInsecureConnections
97+
&& packageSource.DisableTLSCertificateValidation == packageSourceContextInfo.DisableTLSCertificateValidation
9798
&& packageSource.IsEnabled == packageSourceContextInfo.IsEnabled)
9899
{
99100
newPackageSources.Add(packageSource);
@@ -113,6 +114,7 @@ private IReadOnlyList<PackageSource> GetPackageSourcesToUpdate(IReadOnlyList<Pac
113114
Description = packageSource.Description,
114115
ProtocolVersion = packageSourceContextInfo.ProtocolVersion,
115116
AllowInsecureConnections = packageSourceContextInfo.AllowInsecureConnections,
117+
DisableTLSCertificateValidation = packageSourceContextInfo.DisableTLSCertificateValidation,
116118
MaxHttpRequestsPerSource = packageSource.MaxHttpRequestsPerSource,
117119
};
118120

src/NuGet.Clients/NuGet.VisualStudio.Internal.Contracts/ContextInfos/PackageSourceContextInfo.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public PackageSourceContextInfo(string source, string name, bool isEnabled, int
3333
}
3434

3535
public PackageSourceContextInfo(string source, string name, bool isEnabled, int protocolVersion, bool allowInsecureConnections)
36+
: this(source, name, isEnabled, protocolVersion, allowInsecureConnections, disableTLSCertificateValidation: false)
37+
{
38+
}
39+
40+
public PackageSourceContextInfo(string source, string name, bool isEnabled, int protocolVersion, bool allowInsecureConnections, bool disableTLSCertificateValidation)
3641
{
3742
Assumes.NotNullOrEmpty(name);
3843
Assumes.NotNullOrEmpty(source);
@@ -42,12 +47,14 @@ public PackageSourceContextInfo(string source, string name, bool isEnabled, int
4247
IsEnabled = isEnabled;
4348
ProtocolVersion = protocolVersion;
4449
AllowInsecureConnections = allowInsecureConnections;
50+
DisableTLSCertificateValidation = disableTLSCertificateValidation;
4551

4652
var hash = new HashCodeCombiner();
4753
hash.AddStringIgnoreCase(Name);
4854
hash.AddStringIgnoreCase(Source);
4955
hash.AddObject(ProtocolVersion);
5056
hash.AddObject(AllowInsecureConnections);
57+
hash.AddObject(DisableTLSCertificateValidation);
5158
_hashCode = hash.CombinedHash;
5259
OriginalHashCode = _hashCode;
5360
}
@@ -56,6 +63,7 @@ public PackageSourceContextInfo(string source, string name, bool isEnabled, int
5663
public string Source { get; set; }
5764
public int ProtocolVersion { get; set; }
5865
public bool AllowInsecureConnections { get; set; }
66+
public bool DisableTLSCertificateValidation { get; set; }
5967
public bool IsMachineWide { get; internal set; }
6068
public bool IsEnabled { get; set; }
6169
public string? Description { get; internal set; }
@@ -94,7 +102,7 @@ public override int GetHashCode()
94102

95103
public PackageSourceContextInfo Clone()
96104
{
97-
return new PackageSourceContextInfo(Source, Name, IsEnabled, ProtocolVersion, AllowInsecureConnections)
105+
return new PackageSourceContextInfo(Source, Name, IsEnabled, ProtocolVersion, AllowInsecureConnections, DisableTLSCertificateValidation)
98106
{
99107
IsMachineWide = IsMachineWide,
100108
Description = Description,
@@ -104,7 +112,7 @@ public PackageSourceContextInfo Clone()
104112

105113
public static PackageSourceContextInfo Create(PackageSource packageSource)
106114
{
107-
return new PackageSourceContextInfo(packageSource.Source, packageSource.Name, packageSource.IsEnabled, packageSource.ProtocolVersion, packageSource.AllowInsecureConnections)
115+
return new PackageSourceContextInfo(packageSource.Source, packageSource.Name, packageSource.IsEnabled, packageSource.ProtocolVersion, packageSource.AllowInsecureConnections, packageSource.DisableTLSCertificateValidation)
108116
{
109117
IsMachineWide = packageSource.IsMachineWide,
110118
Description = packageSource.Description,

src/NuGet.Clients/NuGet.VisualStudio.Internal.Contracts/Formatters/PackageSourceContextInfoFormatter.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal sealed class PackageSourceContextInfoFormatter : NuGetMessagePackFormat
1414
private const string IsEnabledPropertyName = "isenabled";
1515
private const string ProtocolVersionPropertyName = "protocolversion";
1616
private const string AllowInsecureConnectionsPropertyName = "allowInsecureConnections";
17+
private const string DisableTLSCertificateValidationPropertyName = "disableTLSCertificateValidation";
1718
private const string IsMachineWidePropertyName = "ismachinewide";
1819
private const string NamePropertyName = "name";
1920
private const string DescriptionPropertyName = "description";
@@ -35,6 +36,7 @@ private PackageSourceContextInfoFormatter()
3536
int originalHashCode = 0;
3637
int protocolVersion = PackageSource.DefaultProtocolVersion;
3738
bool allowInsecureConnections = false;
39+
bool disableTLSCertificateValidation = false;
3840

3941
int propertyCount = reader.ReadMapHeader();
4042
for (int propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++)
@@ -65,6 +67,9 @@ private PackageSourceContextInfoFormatter()
6567
case AllowInsecureConnectionsPropertyName:
6668
allowInsecureConnections = reader.ReadBoolean();
6769
break;
70+
case DisableTLSCertificateValidationPropertyName:
71+
disableTLSCertificateValidation = reader.ReadBoolean();
72+
break;
6873
default:
6974
reader.Skip();
7075
break;
@@ -74,7 +79,7 @@ private PackageSourceContextInfoFormatter()
7479
Assumes.NotNullOrEmpty(source);
7580
Assumes.NotNullOrEmpty(name);
7681

77-
return new PackageSourceContextInfo(source, name, isEnabled, protocolVersion, allowInsecureConnections)
82+
return new PackageSourceContextInfo(source, name, isEnabled, protocolVersion, allowInsecureConnections, disableTLSCertificateValidation)
7883
{
7984
IsMachineWide = isMachineWide,
8085
Description = description,
@@ -84,13 +89,15 @@ private PackageSourceContextInfoFormatter()
8489

8590
protected override void SerializeCore(ref MessagePackWriter writer, PackageSourceContextInfo value, MessagePackSerializerOptions options)
8691
{
87-
writer.WriteMapHeader(count: 8);
92+
writer.WriteMapHeader(count: 9);
8893
writer.Write(SourcePropertyName);
8994
writer.Write(value.Source);
9095
writer.Write(ProtocolVersionPropertyName);
9196
writer.Write(value.ProtocolVersion);
9297
writer.Write(AllowInsecureConnectionsPropertyName);
9398
writer.Write(value.AllowInsecureConnections);
99+
writer.Write(DisableTLSCertificateValidationPropertyName);
100+
writer.Write(value.DisableTLSCertificateValidation);
94101
writer.Write(IsEnabledPropertyName);
95102
writer.Write(value.IsEnabled);
96103
writer.Write(IsMachineWidePropertyName);

src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSource.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class PackageSource : IEquatable<PackageSource>
1919
public const int MaxProtocolVersion = 3;
2020

2121
internal const bool DefaultAllowInsecureConnections = false;
22+
internal const bool DefaultDisableTLSCertificateValidation = false;
2223

2324
private int _hashCode;
2425
private string _source;
@@ -107,6 +108,11 @@ public string Source
107108
/// </summary>
108109
public bool AllowInsecureConnections { get; set; } = DefaultAllowInsecureConnections;
109110

111+
///<summary>
112+
/// Gets or sets disableTLSCertificateValidation of the source. Defaults to false.
113+
///</summary>
114+
public bool DisableTLSCertificateValidation { get; set; } = DefaultDisableTLSCertificateValidation;
115+
110116
/// <summary>
111117
/// Whether the source is using the HTTP protocol, including HTTPS.
112118
/// </summary>
@@ -160,11 +166,16 @@ public SourceItem AsSourceItem()
160166
}
161167

162168
string? allowInsecureConnections = null;
169+
string? disableTLSCertificateValidation = null;
163170
if (AllowInsecureConnections != DefaultAllowInsecureConnections)
164171
{
165172
allowInsecureConnections = $"{AllowInsecureConnections}";
166173
}
167-
return new SourceItem(Name, Source, protocolVersion, allowInsecureConnections);
174+
if (DisableTLSCertificateValidation != DefaultDisableTLSCertificateValidation)
175+
{
176+
disableTLSCertificateValidation = $"{DisableTLSCertificateValidation}";
177+
}
178+
return new SourceItem(Name, Source, protocolVersion, allowInsecureConnections, disableTLSCertificateValidation);
168179
}
169180

170181
public bool Equals(PackageSource? other)
@@ -202,6 +213,7 @@ public PackageSource Clone()
202213
IsMachineWide = IsMachineWide,
203214
ProtocolVersion = ProtocolVersion,
204215
AllowInsecureConnections = AllowInsecureConnections,
216+
DisableTLSCertificateValidation = DisableTLSCertificateValidation,
205217
};
206218
}
207219
}

src/NuGet.Core/NuGet.Configuration/PackageSource/PackageSourceProvider.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ internal static PackageSource ReadPackageSource(SourceItem setting, bool isEnabl
244244

245245
packageSource.ProtocolVersion = ReadProtocolVersion(setting);
246246
packageSource.AllowInsecureConnections = ReadAllowInsecureConnections(setting);
247+
packageSource.DisableTLSCertificateValidation = ReadDisableTLSCertificateValidation(setting);
247248

248249
return packageSource;
249250
}
@@ -258,6 +259,16 @@ private static int ReadProtocolVersion(SourceItem setting)
258259
return PackageSource.DefaultProtocolVersion;
259260
}
260261

262+
private static bool ReadDisableTLSCertificateValidation(SourceItem setting)
263+
{
264+
if (bool.TryParse(setting.DisableTLSCertificateValidation, out var disableTLSCertificateValidation))
265+
{
266+
return disableTLSCertificateValidation;
267+
}
268+
269+
return PackageSource.DefaultDisableTLSCertificateValidation;
270+
}
271+
261272
private static bool ReadAllowInsecureConnections(SourceItem setting)
262273
{
263274
if (bool.TryParse(setting.AllowInsecureConnections, out var allowInsecureConnections))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
#nullable enable
2+
NuGet.Configuration.PackageSource.DisableTLSCertificateValidation.get -> bool
3+
NuGet.Configuration.PackageSource.DisableTLSCertificateValidation.set -> void
4+
NuGet.Configuration.SourceItem.DisableTLSCertificateValidation.get -> string?
5+
NuGet.Configuration.SourceItem.DisableTLSCertificateValidation.set -> void
6+
NuGet.Configuration.SourceItem.SourceItem(string! key, string! value, string? protocolVersion, string? allowInsecureConnections, string? disableTLSCertificateValidation) -> void
7+
static readonly NuGet.Configuration.ConfigurationConstants.DisableTLSCertificateValidation -> string!

src/NuGet.Core/NuGet.Configuration/Settings/Items/SourceItem.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,36 @@ public string? AllowInsecureConnections
3535
set => AddOrUpdateAttribute(ConfigurationConstants.AllowInsecureConnections, value);
3636
}
3737

38+
public string? DisableTLSCertificateValidation
39+
{
40+
get
41+
{
42+
if (Attributes.TryGetValue(ConfigurationConstants.DisableTLSCertificateValidation, out var attribute))
43+
{
44+
return Settings.ApplyEnvironmentTransform(attribute);
45+
}
46+
47+
return null;
48+
}
49+
set => AddOrUpdateAttribute(ConfigurationConstants.DisableTLSCertificateValidation, value);
50+
}
51+
3852
public SourceItem(string key, string value)
39-
: this(key, value, protocolVersion: "", allowInsecureConnections: "")
53+
: this(key, value, protocolVersion: "", allowInsecureConnections: "", disableTLSCertificateValidation: "")
4054
{
4155
}
4256

4357
public SourceItem(string key, string value, string? protocolVersion)
44-
: this(key, value, protocolVersion, allowInsecureConnections: "")
58+
: this(key, value, protocolVersion, allowInsecureConnections: "", disableTLSCertificateValidation: "")
4559
{
4660
}
4761

4862
public SourceItem(string key, string value, string? protocolVersion, string? allowInsecureConnections)
63+
: this(key, value, protocolVersion, allowInsecureConnections, disableTLSCertificateValidation: "")
64+
{
65+
}
66+
67+
public SourceItem(string key, string value, string? protocolVersion, string? allowInsecureConnections, string? disableTLSCertificateValidation)
4968
: base(key, value)
5069
{
5170
if (!string.IsNullOrEmpty(protocolVersion))
@@ -56,6 +75,10 @@ public SourceItem(string key, string value, string? protocolVersion, string? all
5675
{
5776
AllowInsecureConnections = allowInsecureConnections;
5877
}
78+
if (!string.IsNullOrEmpty(disableTLSCertificateValidation))
79+
{
80+
DisableTLSCertificateValidation = disableTLSCertificateValidation;
81+
}
5982
}
6083

6184
internal SourceItem(XElement element, SettingsFile origin)
@@ -65,7 +88,7 @@ internal SourceItem(XElement element, SettingsFile origin)
6588

6689
public override SettingBase Clone()
6790
{
68-
var newSetting = new SourceItem(Key, Value, ProtocolVersion, AllowInsecureConnections);
91+
var newSetting = new SourceItem(Key, Value, ProtocolVersion, AllowInsecureConnections, DisableTLSCertificateValidation);
6992

7093
if (Origin != null)
7194
{

src/NuGet.Core/NuGet.Configuration/Utility/ConfigurationContants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public static class ConfigurationConstants
5353

5454
public static readonly string DisabledPackageSources = "disabledPackageSources";
5555

56+
public static readonly string DisableTLSCertificateValidation = "disableTLSCertificateValidation";
57+
5658
public static readonly string DoNotShowPackageManagementSelectionKey = "disabled";
5759

5860
public static readonly string Enabled = "enabled";

src/NuGet.Core/NuGet.Protocol/HttpSource/HttpHandlerResourceV3Provider.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using System.Linq;
77
using System.Net;
88
using System.Net.Http;
9+
using System.Net.Security;
10+
using System.Security.Cryptography.X509Certificates;
911
using System.Threading;
1012
using System.Threading.Tasks;
1113
using NuGet.Configuration;
@@ -17,6 +19,11 @@ public class HttpHandlerResourceV3Provider : ResourceProvider
1719
{
1820
private readonly IProxyCache _proxyCache;
1921

22+
#if NETSTANDARD2_0
23+
internal static Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> DangerousAcceptAnyServerCertificateValidator =
24+
(message, certificate, chain, policyErrors) => true;
25+
#endif
26+
2027
public HttpHandlerResourceV3Provider()
2128
: this(ProxyCache.Instance)
2229
{
@@ -56,6 +63,18 @@ private HttpHandlerResourceV3 CreateResource(PackageSource packageSource)
5663
AutomaticDecompression = (DecompressionMethods.GZip | DecompressionMethods.Deflate),
5764
};
5865

66+
#if NETSTANDARD2_0
67+
if (packageSource.DisableTLSCertificateValidation)
68+
{
69+
clientHandler.ServerCertificateCustomValidationCallback = DangerousAcceptAnyServerCertificateValidator;
70+
}
71+
#else
72+
if (packageSource.DisableTLSCertificateValidation)
73+
{
74+
clientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
75+
}
76+
#endif
77+
5978
#if IS_DESKTOP
6079
if (packageSource.MaxHttpRequestsPerSource > 0)
6180
{

test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetSourcesServiceTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,5 +168,42 @@ public async Task Save_SourceWithDifferentAllowInsecureConnections_SavesNewValue
168168
savedSources[0].ProtocolVersion.Should().Be(3);
169169
savedSources[0].AllowInsecureConnections.Should().Be(true);
170170
}
171+
172+
[Fact]
173+
public async Task Save_SourceWithDifferentDisableTLSCertificateVerification_SavesNewValue()
174+
{
175+
PackageSource packageSource = new(name: "Source-Name", source: "Source-Path")
176+
{
177+
ProtocolVersion = 3,
178+
DisableTLSCertificateValidation = false
179+
};
180+
181+
Mock<IPackageSourceProvider> packageSourceProvider = new();
182+
packageSourceProvider.Setup(psp => psp.LoadPackageSources())
183+
.Returns(new[] { packageSource });
184+
185+
List<PackageSource>? savedSources = null;
186+
packageSourceProvider.Setup(psp => psp.SavePackageSources(It.IsAny<IEnumerable<PackageSource>>()))
187+
.Callback((IEnumerable<PackageSource> newSources) => { savedSources = newSources.ToList(); });
188+
189+
var target = new NuGetSourcesService(options: default,
190+
Mock.Of<IServiceBroker>(),
191+
new AuthorizationServiceClient(Mock.Of<IAuthorizationService>()),
192+
packageSourceProvider.Object);
193+
194+
List<PackageSourceContextInfo> updatedSources = new(1)
195+
{
196+
new PackageSourceContextInfo(packageSource.Source, packageSource.Name, packageSource.IsEnabled, protocolVersion: 3, allowInsecureConnections: false, disableTLSCertificateValidation: true)
197+
};
198+
199+
// Act
200+
await target.SavePackageSourceContextInfosAsync(updatedSources, CancellationToken.None);
201+
202+
// Assert
203+
savedSources.Should().NotBeNull();
204+
savedSources!.Count.Should().Be(1);
205+
savedSources[0].ProtocolVersion.Should().Be(3);
206+
savedSources[0].DisableTLSCertificateValidation.Should().Be(true);
207+
}
171208
}
172209
}

0 commit comments

Comments
 (0)