Skip to content

Commit 88fe50a

Browse files
Disable cookies by default (Azure#26477)
* Disable cookies by default * PR fb * PR fb * fix * tab * Fix race condition * Specify cert path * Add constants * Move to ctor
1 parent dcac296 commit 88fe50a

File tree

7 files changed

+116
-13
lines changed

7 files changed

+116
-13
lines changed

sdk/core/Azure.Core.TestFramework/src/TestEnvironment.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public abstract class TestEnvironment
2828
[EditorBrowsableAttribute(EditorBrowsableState.Never)]
2929
public static string RepositoryRoot { get; }
3030

31+
public static string DevCertPath { get; }
32+
33+
public const string DevCertPassword = "password";
34+
3135
private static readonly Dictionary<Type, Task> s_environmentStateCache = new();
3236

3337
private readonly string _prefix;
@@ -122,6 +126,13 @@ static TestEnvironment()
122126
}
123127

124128
RepositoryRoot = directoryInfo?.Parent?.FullName;
129+
130+
DevCertPath = Path.Combine(
131+
RepositoryRoot,
132+
"eng",
133+
"common",
134+
"testproxy",
135+
"dotnet-devcert.pfx");
125136
}
126137

127138
public RecordedTestMode? Mode { get; set; }

sdk/core/Azure.Core.TestFramework/src/TestProxy.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,8 @@ private TestProxy(string proxyPath)
7373
["ASPNETCORE_URLS"] = $"http://{IpAddress}:0;https://{IpAddress}:0",
7474
["Logging__LogLevel__Default"] = "Error",
7575
["Logging__LogLevel__Microsoft.Hosting.Lifetime"] = "Information",
76-
["ASPNETCORE_Kestrel__Certificates__Default__Path"] = Path.Combine(
77-
TestEnvironment.RepositoryRoot,
78-
"eng",
79-
"common",
80-
"testproxy",
81-
"dotnet-devcert.pfx"),
82-
["ASPNETCORE_Kestrel__Certificates__Default__Password"] = "password"
76+
["ASPNETCORE_Kestrel__Certificates__Default__Path"] = TestEnvironment.DevCertPath,
77+
["ASPNETCORE_Kestrel__Certificates__Default__Password"] = TestEnvironment.DevCertPassword
8378
}
8479
};
8580

sdk/core/Azure.Core.TestFramework/src/TestServer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33

44
using System;
5+
using System.IO;
56
using System.Linq;
67
using System.Net;
78
using System.Reflection;
@@ -36,7 +37,7 @@ public TestServer(RequestDelegate app, bool https = false)
3637
{
3738
if (https)
3839
{
39-
listenOptions.UseHttps();
40+
listenOptions.UseHttps(TestEnvironment.DevCertPath, TestEnvironment.DevCertPassword);
4041
}
4142
});
4243
})

sdk/core/Azure.Core/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
### Breaking Changes
88

9+
- Cookies are no longer set on requests by default. Cookies can be re-enabled for `HttpClientTransport` by either setting an AppContext switch named "Azure.Core.Pipeline.HttpClientTransport.EnableCookies" to true or by setting the environment variable, "AZURE_CORE_HTTPCLIENT_ENABLE_COOKIES" to "true". Note: AppContext switches can also be configured via configuration like below:
10+
```xml
11+
<ItemGroup>
12+
<RuntimeHostConfigurationOption Include="Azure.Core.Pipeline.HttpClientTransport.EnableCookies" Value="true" />
13+
</ItemGroup>
14+
```
15+
916
### Bugs Fixed
1017

1118
### Other Changes

sdk/core/Azure.Core/src/Pipeline/HttpClientTransport.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,14 @@ private static HttpMessageHandler CreateDefaultHandler(HttpPipelineTransportOpti
159159
{
160160
if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")))
161161
{
162+
// UseCookies is not supported on "browser"
162163
return new HttpClientHandler();
163164
}
164165

165166
#if NETCOREAPP
166-
return ApplyOptionsToHandler(new SocketsHttpHandler { AllowAutoRedirect = false }, options);
167+
return ApplyOptionsToHandler(new SocketsHttpHandler { AllowAutoRedirect = false, UseCookies = UseCookies() }, options);
167168
#else
168-
return ApplyOptionsToHandler(new HttpClientHandler { AllowAutoRedirect = false }, options);
169+
return ApplyOptionsToHandler(new HttpClientHandler { AllowAutoRedirect = false, UseCookies = UseCookies() }, options);
169170
#endif
170171
}
171172

@@ -613,5 +614,9 @@ private static void SetPropertiesOrOptions<T>(HttpRequestMessage httpRequest, st
613614
httpRequest.Properties[name] = value;
614615
#endif
615616
}
617+
618+
private static bool UseCookies() => AppContextSwitchHelper.GetConfigValue(
619+
"Azure.Core.Pipeline.HttpClientTransport.EnableCookies",
620+
"AZURE_CORE_HTTPCLIENT_ENABLE_COOKIES");
616621
}
617622
}

sdk/core/Azure.Core/tests/HttpClientTransportFunctionalTest.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections;
6+
using System.Linq;
67
using System.Net;
78
using System.Net.Http;
89
using System.Net.Security;
@@ -12,10 +13,13 @@
1213
using System.Threading;
1314
using System.Threading.Tasks;
1415
using Azure.Core.Pipeline;
16+
using Azure.Core.TestFramework;
17+
using Microsoft.AspNetCore.Http;
1518
using NUnit.Framework;
1619

1720
namespace Azure.Core.Tests
1821
{
22+
[NonParallelizable]
1923
public class HttpClientTransportFunctionalTest : TransportFunctionalTests
2024
{
2125
private static RemoteCertificateValidationCallback certCallback = (_, _, _, _) => true;
@@ -34,6 +38,7 @@ protected override HttpPipelineTransport GetTransport(bool https = false, HttpPi
3438
}
3539

3640
#if NET461
41+
// These setup and teardown actions require that entire test class be NonParallelizable.
3742
[OneTimeSetUp]
3843
public void TestSetup()
3944
{
@@ -86,6 +91,59 @@ public void DisposeDoesNotDisposesSharedPipeline()
8691
Assert.DoesNotThrow(() => transport.Client.CancelPendingRequests());
8792
}
8893

94+
[Test]
95+
public async Task CookiesCanBeEnabledUsingSwitch()
96+
{
97+
using var appContextSwitch = new TestAppContextSwitch("Azure.Core.Pipeline.HttpClientTransport.EnableCookies", "true");
98+
99+
await TestCookiesEnabled();
100+
}
101+
102+
[Test]
103+
public async Task CookiesCanBeEnabledUsingEnvVar()
104+
{
105+
using var envVar = new TestEnvVar("AZURE_CORE_HTTPCLIENT_ENABLE_COOKIES", "true");
106+
107+
await TestCookiesEnabled();
108+
}
109+
110+
private async Task TestCookiesEnabled()
111+
{
112+
int requestCount = 0;
113+
using (TestServer testServer = new TestServer(
114+
async context =>
115+
{
116+
if (requestCount++ == 1)
117+
{
118+
Assert.IsTrue(context.Request.Headers.ContainsKey("cookie"));
119+
Assert.AreEqual("stsservicecookie=estsfd",
120+
context.Request.Headers["cookie"].First());
121+
}
122+
123+
context.Response.StatusCode = 200;
124+
context.Response.Headers.Add(
125+
"set-cookie",
126+
"stsservicecookie=estsfd; path=/; secure; samesite=none; httponly");
127+
await context.Response.WriteAsync("");
128+
},
129+
https: true))
130+
{
131+
var transport = GetTransport(https: true);
132+
Request request = transport.CreateRequest();
133+
request.Method = RequestMethod.Post;
134+
request.Uri.Reset(testServer.Address);
135+
request.Content = RequestContent.Create("Hello");
136+
await ExecuteRequest(request, transport);
137+
138+
// create a second request to verify cookies not set
139+
request = transport.CreateRequest();
140+
request.Method = RequestMethod.Post;
141+
request.Uri.Reset(testServer.Address);
142+
request.Content = RequestContent.Create("Hello");
143+
await ExecuteRequest(request, transport);
144+
}
145+
}
146+
89147
private static object GetHandler(HttpClient transportClient)
90148
{
91149
return typeof(HttpMessageInvoker).GetField("_handler", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(transportClient);

sdk/core/Azure.Core/tests/TransportFunctionalTests.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,6 @@ public void TransportExceptionsAreWrappedAndInnerExceptionIsPopulated()
881881
public Task ThrowsTaskCanceledExceptionWhenCancelled() => ThrowsTaskCanceledExceptionWhenCancelled(false);
882882

883883
[Test]
884-
[RunOnlyOnPlatforms(Linux = true, Windows = true, OSX = false, Reason = "https://github.com/Azure/azure-sdk-for-net/issues/17986")]
885884
public Task ThrowsTaskCanceledExceptionWhenCancelledHttps() => ThrowsTaskCanceledExceptionWhenCancelled(true);
886885

887886
private async Task ThrowsTaskCanceledExceptionWhenCancelled(bool https)
@@ -924,7 +923,6 @@ private async Task ThrowsTaskCanceledExceptionWhenCancelled(bool https)
924923
public Task CanCancelContentUpload() => CanCancelContentUpload(false);
925924

926925
[Test]
927-
[RunOnlyOnPlatforms(Linux = true, Windows = true, OSX = false, Reason = "https://github.com/Azure/azure-sdk-for-net/issues/17986")]
928926
public Task CanCancelContentUploadHttps() => CanCancelContentUpload(true);
929927

930928
private async Task CanCancelContentUpload(bool https)
@@ -995,7 +993,6 @@ public async Task StreamReadingExceptionsAreIOExceptions()
995993
}
996994

997995
[Test]
998-
[RunOnlyOnPlatforms(Linux = true, Windows = true, OSX = false, Reason = "https://github.com/Azure/azure-sdk-for-net/issues/17986")]
999996
public async Task ServerCertificateCustomValidationCallbackIsHonored([Values(true, false)] bool setCertCallback, [Values(true, false)] bool isValidCert)
1000997
{
1001998
// This test assumes ServicePointManager.ServerCertificateValidationCallback will be unset.
@@ -1114,6 +1111,35 @@ public async Task CanSendExpect100Continue()
11141111
}
11151112
}
11161113

1114+
[Test]
1115+
public async Task CookiesDisabledByDefault()
1116+
{
1117+
using (TestServer testServer = new TestServer(
1118+
context =>
1119+
{
1120+
Assert.IsFalse(context.Request.Headers.ContainsKey("cookie"));
1121+
context.Response.StatusCode = 200;
1122+
context.Response.Headers.Add(
1123+
"set-cookie",
1124+
"stsservicecookie=estsfd; path=/; secure; samesite=none; httponly");
1125+
}))
1126+
{
1127+
var transport = GetTransport();
1128+
Request request = transport.CreateRequest();
1129+
request.Method = RequestMethod.Post;
1130+
request.Uri.Reset(testServer.Address);
1131+
request.Content = RequestContent.Create("Hello");
1132+
await ExecuteRequest(request, transport);
1133+
1134+
// create a second request to verify cookies not set
1135+
request = transport.CreateRequest();
1136+
request.Method = RequestMethod.Post;
1137+
request.Uri.Reset(testServer.Address);
1138+
request.Content = RequestContent.Create("Hello");
1139+
await ExecuteRequest(request, transport);
1140+
}
1141+
}
1142+
11171143
private static Request CreateRequest(HttpPipelineTransport transport, TestServer server, byte[] bytes = null)
11181144
{
11191145
Request request = transport.CreateRequest();

0 commit comments

Comments
 (0)