Skip to content

Commit

Permalink
Fix Azure#13687: Move to latest App Services MSI API version
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderSher committed Sep 1, 2020
1 parent a665460 commit 2a19fae
Show file tree
Hide file tree
Showing 13 changed files with 426 additions and 390 deletions.
13 changes: 1 addition & 12 deletions sdk/core/Azure.Core/src/Shared/ClientDiagnostics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,9 @@ public RequestFailedException CreateRequestFailedExceptionWithContent(
return exception;
}

public ValueTask<string> CreateRequestFailedMessageAsync(Response response, string? message = null, string? errorCode= null, IDictionary<string, string>? additionalInfo = null)
{
return CreateRequestFailedMessageAsync(response, message, errorCode, additionalInfo, true);
}

public string CreateRequestFailedMessage(Response response, string? message = null, string? errorCode = null, IDictionary<string, string>? additionalInfo = null)
{
return CreateRequestFailedMessageAsync(response, message, errorCode, additionalInfo, false).EnsureCompleted();
}

private async ValueTask<string> CreateRequestFailedMessageAsync(Response response, string? message, string? errorCode, IDictionary<string, string>? additionalInfo, bool async)
public async ValueTask<string> CreateRequestFailedMessageAsync(Response response, string? message, string? errorCode, IDictionary<string, string>? additionalInfo, bool async)
{
var content = await ReadContentAsync(response, async).ConfigureAwait(false);

return CreateRequestFailedMessageWithContent(response, message, content, errorCode, additionalInfo);
}

Expand Down
50 changes: 50 additions & 0 deletions sdk/core/Azure.Core/src/Shared/TaskExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace Azure.Core.Pipeline
{
internal static class TaskExtensions
{
public static WithCancellationTaskAwaitable AwaitWithCancellation(this Task task, CancellationToken cancellationToken)
=> new WithCancellationTaskAwaitable(task, cancellationToken);

public static WithCancellationTaskAwaitable<T> AwaitWithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
=> new WithCancellationTaskAwaitable<T>(task, cancellationToken);

Expand Down Expand Up @@ -141,6 +144,20 @@ private static void VerifyTaskCompleted(bool isCompleted)
#pragma warning restore AZC0107 // Do not call public asynchronous method in synchronous scope.
}

public readonly struct WithCancellationTaskAwaitable
{
private readonly CancellationToken _cancellationToken;
private readonly ConfiguredTaskAwaitable _awaitable;

public WithCancellationTaskAwaitable(Task task, CancellationToken cancellationToken)
{
_awaitable = task.ConfigureAwait(false);
_cancellationToken = cancellationToken;
}

public WithCancellationTaskAwaiter GetAwaiter() => new WithCancellationTaskAwaiter(_awaitable.GetAwaiter(), _cancellationToken);
}

public readonly struct WithCancellationTaskAwaitable<T>
{
private readonly CancellationToken _cancellationToken;
Expand Down Expand Up @@ -169,6 +186,39 @@ public WithCancellationValueTaskAwaitable(ValueTask<T> task, CancellationToken c
public WithCancellationValueTaskAwaiter<T> GetAwaiter() => new WithCancellationValueTaskAwaiter<T>(_awaitable.GetAwaiter(), _cancellationToken);
}

public readonly struct WithCancellationTaskAwaiter : ICriticalNotifyCompletion
{
private readonly CancellationToken _cancellationToken;
private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _taskAwaiter;

public WithCancellationTaskAwaiter(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter, CancellationToken cancellationToken)
{
_taskAwaiter = awaiter;
_cancellationToken = cancellationToken;
}

public bool IsCompleted => _taskAwaiter.IsCompleted || _cancellationToken.IsCancellationRequested;

public void OnCompleted(Action continuation) => _taskAwaiter.OnCompleted(WrapContinuation(continuation));

public void UnsafeOnCompleted(Action continuation) => _taskAwaiter.UnsafeOnCompleted(WrapContinuation(continuation));

public void GetResult()
{
Debug.Assert(IsCompleted);
if (!_taskAwaiter.IsCompleted)
{
_cancellationToken.ThrowIfCancellationRequested();
}
_taskAwaiter.GetResult();
}

private Action WrapContinuation(in Action originalContinuation)
=> _cancellationToken.CanBeCanceled
? new WithCancellationContinuationWrapper(originalContinuation, _cancellationToken).Continuation
: originalContinuation;
}

public readonly struct WithCancellationTaskAwaiter<T> : ICriticalNotifyCompletion
{
private readonly CancellationToken _cancellationToken;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure.Identity
{
internal class AppServiceV2017AuthRequestBuilder : IAuthRequestBuilder
{
// MSI Constants. Docs for MSI are available here https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity
private const string AppServiceMsiApiVersion = "2017-09-01";

private readonly HttpPipeline _pipeline;
private readonly Uri _endpoint;
private readonly string _secret;
private readonly string _clientId;

public AppServiceV2017AuthRequestBuilder(HttpPipeline pipeline, Uri endpoint, string secret, string clientId)
{
_pipeline = pipeline;
_endpoint = endpoint;
_secret = secret;
_clientId = clientId;
}

public Request CreateRequest(string[] scopes)
{
// covert the scopes to a resource string
string resource = ScopeUtilities.ScopesToResource(scopes);

Request request = _pipeline.CreateRequest();

request.Method = RequestMethod.Get;
request.Headers.Add("secret", _secret);
request.Uri.Reset(_endpoint);
request.Uri.AppendQuery("api-version", AppServiceMsiApiVersion);
request.Uri.AppendQuery("resource", resource);

if (!string.IsNullOrEmpty(_clientId))
{
request.Uri.AppendQuery("clientid", _clientId);
}

return request;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure.Identity
{
internal class AppServiceV2019AuthRequestBuilder : IAuthRequestBuilder
{
private const string AppServiceMsiApiVersion = "2019-08-01";

private readonly HttpPipeline _pipeline;
private readonly Uri _endpoint;
private readonly string _secret;
private readonly string _clientId;

public AppServiceV2019AuthRequestBuilder(HttpPipeline pipeline, Uri endpoint, string secret, string clientId)
{
_pipeline = pipeline;
_endpoint = endpoint;
_secret = secret;
_clientId = clientId;
}

public Request CreateRequest(string[] scopes)
{
// covert the scopes to a resource string
string resource = ScopeUtilities.ScopesToResource(scopes);

Request request = _pipeline.CreateRequest();

request.Method = RequestMethod.Get;
request.Headers.Add("X-IDENTITY-HEADER", _secret);
request.Uri.Reset(_endpoint);
request.Uri.AppendQuery("api-version", AppServiceMsiApiVersion);
request.Uri.AppendQuery("resource", resource);

if (!string.IsNullOrEmpty(_clientId))
{
request.Uri.AppendQuery("client_id", _clientId);
}

return request;
}
}
}
51 changes: 51 additions & 0 deletions sdk/identity/Azure.Identity/src/CloudShellAuthRequestBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Text;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure.Identity
{
internal class CloudShellAuthRequestBuilder : IAuthRequestBuilder
{
private readonly HttpPipeline _pipeline;
private readonly Uri _endpoint;
private readonly string _clientId;

public CloudShellAuthRequestBuilder(HttpPipeline pipeline, Uri endpoint, string clientId)
{
_pipeline = pipeline;
_endpoint = endpoint;
_clientId = clientId;
}

public Request CreateRequest(string[] scopes)
{
// covert the scopes to a resource string
string resource = ScopeUtilities.ScopesToResource(scopes);

Request request = _pipeline.CreateRequest();

request.Method = RequestMethod.Post;

request.Headers.Add(HttpHeader.Common.FormUrlEncodedContentType);

request.Uri.Reset(_endpoint);

request.Headers.Add("Metadata", "true");

var bodyStr = $"resource={Uri.EscapeDataString(resource)}";

if (!string.IsNullOrEmpty(_clientId))
{
bodyStr += $"&client_id={Uri.EscapeDataString(_clientId)}";
}

ReadOnlyMemory<byte> content = Encoding.UTF8.GetBytes(bodyStr).AsMemory();
request.Content = RequestContent.Create(content);
return request;
}
}
}
2 changes: 2 additions & 0 deletions sdk/identity/Azure.Identity/src/EnvironmentVariables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ internal class EnvironmentVariables
public static string ClientSecret => Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");
public static string ClientCertificatePath => Environment.GetEnvironmentVariable("AZURE_CLIENT_CERTIFICATE_PATH");

public static string IdentityEndpoint => Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT");
public static string IdentityHeader => Environment.GetEnvironmentVariable("IDENTITY_HEADER");
public static string MsiEndpoint => Environment.GetEnvironmentVariable("MSI_ENDPOINT");
public static string MsiSecret => Environment.GetEnvironmentVariable("MSI_SECRET");

Expand Down
12 changes: 12 additions & 0 deletions sdk/identity/Azure.Identity/src/IAuthRequestBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Azure.Core;

namespace Azure.Identity
{
internal interface IAuthRequestBuilder
{
Request CreateRequest(string[] scopes);
}
}
46 changes: 46 additions & 0 deletions sdk/identity/Azure.Identity/src/ImdsAuthRequestBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure.Identity
{
internal class ImdsAuthRequestBuilder : IAuthRequestBuilder
{
private const string ImdsApiVersion = "2018-02-01";

private readonly HttpPipeline _pipeline;
private readonly Uri _endpoint;
private readonly string _clientId;

public ImdsAuthRequestBuilder(HttpPipeline pipeline, Uri endpoint, string clientId)
{
_pipeline = pipeline;
_clientId = clientId;
_endpoint = endpoint;
}

public Request CreateRequest(string[] scopes)
{
// covert the scopes to a resource string
string resource = ScopeUtilities.ScopesToResource(scopes);

Request request = _pipeline.CreateRequest();
request.Method = RequestMethod.Get;
request.Headers.Add("Metadata", "true");
request.Uri.Reset(_endpoint);
request.Uri.AppendQuery("api-version", ImdsApiVersion);

request.Uri.AppendQuery("resource", resource);

if (!string.IsNullOrEmpty(_clientId))
{
request.Uri.AppendQuery("client_id", _clientId);
}

return request;
}
}
}
Loading

0 comments on commit 2a19fae

Please sign in to comment.