Skip to content

Commit fa076a2

Browse files
authored
fix(auth): HMAC is recreated and re-issued on redirect. (Azure#22748)
* fix(auth): HMAC is recreated and re-issued on redirect.
1 parent 7510abd commit fa076a2

File tree

10 files changed

+130
-11
lines changed

10 files changed

+130
-11
lines changed

sdk/communication/Azure.Communication.CallingServer/api/Azure.Communication.CallingServer.netstandard2.0.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public CallingServerClient(string connectionString, Azure.Communication.CallingS
7979
}
8080
public partial class CallingServerClientOptions : Azure.Core.ClientOptions
8181
{
82-
public CallingServerClientOptions(Azure.Communication.CallingServer.CallingServerClientOptions.ServiceVersion version = Azure.Communication.CallingServer.CallingServerClientOptions.ServiceVersion.V2021_06_15_Preview) { }
82+
public CallingServerClientOptions(Azure.Communication.CallingServer.CallingServerClientOptions.ServiceVersion version = Azure.Communication.CallingServer.CallingServerClientOptions.ServiceVersion.V2021_06_15_Preview, bool allowAutoRedirect = false) { }
8383
public enum ServiceVersion
8484
{
8585
V2021_06_15_Preview = 1,

sdk/communication/Azure.Communication.CallingServer/src/Azure.Communication.CallingServer.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<ItemGroup>
1919
<Compile Include="..\..\Shared\src\ClientOptionsExtensions.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2020
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
21+
<Compile Include="..\..\Shared\src\RedirectPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2122
<Compile Include="..\..\Shared\src\CommunicationIdentifierSerializer.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2223
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
2324
<Compile Include="$(AzureCoreSharedSources)ArrayBufferWriter.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Azure.Communication.CallingServer/src/CallingServerClient.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ public virtual ServerCall InitializeServerCall(string serverCallId)
290290
/// </param>
291291
/// <param name="cancellationToken">
292292
/// Optional <see cref="CancellationToken"/> to propagate
293-
/// notifications that the operation should be cancelled.
293+
/// notifications that the operation should be canceled.
294294
/// </param>
295295
/// <returns>
296296
/// A <see cref="Response{Stream}"/> containing the
@@ -325,7 +325,7 @@ await _contentDownloader.DownloadStreamingInternal(
325325
/// </param>
326326
/// <param name="cancellationToken">
327327
/// Optional <see cref="CancellationToken"/> to propagate
328-
/// notifications that the operation should be cancelled.
328+
/// notifications that the operation should be canceled.
329329
/// </param>
330330
/// <returns>
331331
/// A <see cref="Response{Stream}"/> containing the
@@ -363,7 +363,7 @@ public virtual Response<Stream> DownloadStreaming(
363363
/// </param>
364364
/// <param name="cancellationToken">
365365
/// Optional <see cref="CancellationToken"/> to propagate
366-
/// notifications that the operation should be cancelled.
366+
/// notifications that the operation should be canceled.
367367
/// </param>
368368
/// <returns>
369369
/// A <see cref="Response"/> describing the operation.
@@ -393,7 +393,7 @@ public virtual Response DownloadTo(Uri sourceEndpoint, Stream destinationStream,
393393
/// </param>
394394
/// <param name="cancellationToken">
395395
/// Optional <see cref="CancellationToken"/> to propagate
396-
/// notifications that the operation should be cancelled.
396+
/// notifications that the operation should be canceled.
397397
/// </param>
398398
/// <returns>
399399
/// A <see cref="Response"/> describing the operation.
@@ -422,7 +422,7 @@ public virtual async Task<Response> DownloadToAsync(Uri sourceEndpoint, Stream d
422422
/// </param>
423423
/// <param name="cancellationToken">
424424
/// Optional <see cref="CancellationToken"/> to propagate
425-
/// notifications that the operation should be cancelled.
425+
/// notifications that the operation should be canceled.
426426
/// </param>
427427
/// <returns>
428428
/// A <see cref="Response"/> describing the operation.
@@ -456,7 +456,7 @@ public virtual Response DownloadTo(Uri sourceEndpoint, string destinationPath,
456456
/// </param>
457457
/// <param name="cancellationToken">
458458
/// Optional <see cref="CancellationToken"/> to propagate
459-
/// notifications that the operation should be cancelled.
459+
/// notifications that the operation should be canceled.
460460
/// </param>
461461
/// <returns>
462462
/// A <see cref="Response"/> describing the operation.

sdk/communication/Azure.Communication.CallingServer/src/CallingServerClientOptions.cs

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

44
using System;
5+
using System.Net.Http;
56
using Azure.Core;
7+
using Azure.Core.Pipeline;
68

79
namespace Azure.Communication.CallingServer
810
{
@@ -18,16 +20,29 @@ public class CallingServerClientOptions : ClientOptions
1820

1921
internal string ApiVersion { get; }
2022

23+
/// <summary>
24+
/// Enable auto redirect
25+
/// </summary>
26+
internal bool AllowAutoRedirect { get; set; }
27+
2128
/// <summary>
2229
/// Initializes a new instance of the <see cref="CallingServerClientOptions"/>.
2330
/// </summary>
24-
public CallingServerClientOptions(ServiceVersion version = LatestVersion)
31+
public CallingServerClientOptions(ServiceVersion version = LatestVersion, bool allowAutoRedirect = false)
2532
{
33+
AllowAutoRedirect = allowAutoRedirect;
2634
ApiVersion = version switch
2735
{
2836
ServiceVersion.V2021_06_15_Preview => "2021-06-15-preview",
2937
_ => throw new ArgumentOutOfRangeException(nameof(version)),
3038
};
39+
40+
var clientHandler = new HttpClientHandler()
41+
{
42+
AllowAutoRedirect = allowAutoRedirect
43+
};
44+
45+
Transport = new HttpClientTransport(clientHandler);
3146
}
3247

3348
/// <summary>

sdk/communication/Azure.Communication.Identity/src/Azure.Communication.Identity.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<Compile Include="..\..\Shared\src\ClientOptionsExtensions.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2828
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2929
<Compile Include="..\..\Shared\Properties\CommunicationAssembyInfo.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
30+
<Compile Include="..\..\Shared\src\RedirectPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
3031
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
3132
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
3233
<Compile Include="$(AzureCoreSharedSources)ArrayBufferWriter.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Azure.Communication.NetworkTraversal/src/Azure.Communication.NetworkTraversal.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<ItemGroup>
2424
<Compile Include="..\..\Shared\src\ClientOptionsExtensions.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2525
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
26+
<Compile Include="..\..\Shared\src\RedirectPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2627
<Compile Include="..\..\Shared\Properties\CommunicationAssembyInfo.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2728
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
2829
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Azure.Communication.PhoneNumbers/src/Azure.Communication.PhoneNumbers.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<ItemGroup>
2626
<Compile Include="..\..\Shared\src\ClientOptionsExtensions.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2727
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
28+
<Compile Include="..\..\Shared\src\RedirectPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2829
<Compile Include="..\..\Shared\Properties\CommunicationAssembyInfo.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2930
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />
3031
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Azure.Communication.Sms/src/Azure.Communication.Sms.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<ItemGroup>
2525
<Compile Include="..\..\Shared\src\ClientOptionsExtensions.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2626
<Compile Include="..\..\Shared\src\HMACAuthenticationPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
27+
<Compile Include="..\..\Shared\src\RedirectPolicy.cs" Link="Shared\Communication\%(RecursiveDir)\%(Filename)%(Extension)" />
2728
<Compile Include="$(AzureCoreSharedSources)Argument.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
2829
<Compile Include="$(AzureCoreSharedSources)ArrayBufferWriter.cs" Link="Shared\%(RecursiveDir)\%(Filename)%(Extension)" />
2930
<Compile Include="$(AzureCoreSharedSources)AzureResourceProviderNamespaceAttribute.cs" Link="Shared\Core\%(RecursiveDir)\%(Filename)%(Extension)" />

sdk/communication/Shared/src/ClientOptionsExtensions.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,24 @@ namespace Azure.Communication.Pipeline
88
{
99
internal static class ClientOptionsExtensions
1010
{
11+
private static readonly RedirectPolicy _redirectPolicy = new();
12+
1113
public static HttpPipeline BuildHttpPipeline(this ClientOptions options, ConnectionString connectionString)
1214
{
1315
var authPolicy = new HMACAuthenticationPolicy(new AzureKeyCredential(connectionString.GetRequired("accesskey")));
14-
return HttpPipelineBuilder.Build(options, authPolicy);
16+
return HttpPipelineBuilder.Build(options, _redirectPolicy, authPolicy);
1517
}
1618

1719
public static HttpPipeline BuildHttpPipeline(this ClientOptions options, AzureKeyCredential keyCredential)
1820
{
1921
var authPolicy = new HMACAuthenticationPolicy(keyCredential);
20-
return HttpPipelineBuilder.Build(options, authPolicy);
22+
return HttpPipelineBuilder.Build(options, _redirectPolicy, authPolicy);
2123
}
2224

2325
public static HttpPipeline BuildHttpPipeline(this ClientOptions options, TokenCredential tokenCredential)
2426
{
2527
var authPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, "https://communication.azure.com//.default");
26-
return HttpPipelineBuilder.Build(options, authPolicy);
28+
return HttpPipelineBuilder.Build(options, _redirectPolicy, authPolicy);
2729
}
2830
}
2931
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Net;
6+
using System.Threading.Tasks;
7+
using Azure.Core;
8+
using Azure.Core.Pipeline;
9+
10+
namespace Azure.Communication.Pipeline
11+
{
12+
internal class RedirectPolicy : HttpPipelinePolicy
13+
{
14+
private const string LOCATION_HEADER_STRING = "LOCATION";
15+
private readonly int maxRedirects;
16+
17+
public RedirectPolicy(int maxRedirects = 10)
18+
{
19+
this.maxRedirects = maxRedirects;
20+
}
21+
22+
public override void Process(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
23+
{
24+
ProcessAsync(message, pipeline, false).EnsureCompleted();
25+
}
26+
27+
public override ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
28+
{
29+
return ProcessAsync(message, pipeline, true);
30+
}
31+
32+
private async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline, bool async)
33+
{
34+
var redirectCount = 0;
35+
36+
while (true)
37+
{
38+
if (async)
39+
{
40+
await ProcessNextAsync(message, pipeline).ConfigureAwait(false);
41+
}
42+
else
43+
{
44+
ProcessNext(message, pipeline);
45+
}
46+
47+
if (!IsRedirectResponse(message))
48+
{
49+
// Request does not require a redirect, continue
50+
// up the policy pipeline.
51+
return;
52+
}
53+
54+
if (!TryGetRedirect(message, out Uri location))
55+
{
56+
throw new MissingFieldException("Location header was not retrieved from the redirect response, or URL was invalid.");
57+
}
58+
59+
if (++redirectCount > maxRedirects)
60+
{
61+
throw new RequestFailedException("Maximum number of redirections exceeded.");
62+
}
63+
64+
message.Request.Uri.Reset(location);
65+
}
66+
}
67+
68+
private static bool IsRedirectResponse(HttpMessage message)
69+
{
70+
if (message is null || !message.HasResponse)
71+
{
72+
return false;
73+
}
74+
75+
switch ((HttpStatusCode)message.Response.Status)
76+
{
77+
case HttpStatusCode.Moved:
78+
case HttpStatusCode.Found:
79+
return true;
80+
default:
81+
return false;
82+
}
83+
}
84+
85+
private static bool TryGetRedirect(HttpMessage message, out Uri location)
86+
{
87+
location = default;
88+
89+
if (!message.Response.Headers.TryGetValue(LOCATION_HEADER_STRING, out string locationHeader))
90+
{
91+
return false;
92+
}
93+
94+
return Uri.TryCreate(locationHeader, UriKind.Absolute, out location);
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)