Skip to content

Commit 00f3bb7

Browse files
authored
Support KeyVault with Track2 (Azure#17523)
* Az.accounts implements track 2 interface * upgrade to azure.core 1.22
1 parent 98e720f commit 00f3bb7

File tree

60 files changed

+991
-76
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+991
-76
lines changed

src/Accounts/Accounts.sln

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ Global
6464
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
6565
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
6666
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.Build.0 = Release|Any CPU
67+
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
68+
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.Build.0 = Debug|Any CPU
69+
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.ActiveCfg = Release|Any CPU
70+
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.Build.0 = Release|Any CPU
71+
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
72+
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
73+
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
74+
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.Build.0 = Release|Any CPU
75+
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
76+
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
77+
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
78+
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.Build.0 = Release|Any CPU
79+
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
80+
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
81+
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
82+
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.Build.0 = Release|Any CPU
6783
EndGlobalSection
6884
GlobalSection(SolutionProperties) = preSolution
6985
HideSolutionNode = FALSE

src/Accounts/Accounts/Accounts.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@
4646
<ItemGroup>
4747
<ProjectReference Include="..\Authentication.ResourceManager\Authentication.ResourceManager.csproj" />
4848
<ProjectReference Include="..\Authentication\Authentication.csproj" />
49-
<ProjectReference Include="..\Authenticators\Authenticators.csproj" />
49+
<ProjectReference Include="..\Authenticators\Authenticators.csproj" />
5050
</ItemGroup>
51-
51+
5252
<ItemGroup>
5353
<Compile Update="Properties\Resources.Designer.cs">
5454
<DesignTime>True</DesignTime>

src/Accounts/Authentication/Authentication.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<ItemGroup>
1515
<PackageReference Include="Azure.Identity" Version="1.5.0" />
1616
</ItemGroup>
17-
17+
1818
<ItemGroup>
1919
<Compile Update="Properties\Resources.Designer.cs">
2020
<DesignTime>True</DesignTime>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using Azure.Core;
2+
3+
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
12+
namespace Microsoft.Azure.Commands.Common.Authentication.Authentication
13+
{
14+
public class AzureTokenCredential : TokenCredential
15+
{
16+
public string AccessToken { get; set; }
17+
18+
private readonly Func<string> GetTokenImpl;
19+
20+
public AzureTokenCredential(string accessToken, Func<string> getTokenImpl = null)
21+
{
22+
AccessToken = accessToken;
23+
GetTokenImpl = getTokenImpl;
24+
}
25+
26+
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
27+
{
28+
return new AccessToken(GetTokenImpl == null ? AccessToken : GetTokenImpl(),
29+
DateTimeOffset.UtcNow);
30+
}
31+
32+
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
33+
{
34+
return new ValueTask<AccessToken>(this.GetToken(requestContext, cancellationToken));
35+
}
36+
}
37+
}

src/Accounts/Authentication/Authentication/RenewingTokenCredential.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// ----------------------------------------------------------------------------------
1+

2+
3+
4+
// ----------------------------------------------------------------------------------
25
//
36
// Copyright Microsoft Corporation
47
// Licensed under the Apache License, Version 2.0 (the "License");
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Azure.Core;
2+
using Azure.Core.Pipeline;
3+
using Azure.ResourceManager;
4+
5+
using Microsoft.Azure.Commands.Common.Authentication.Policy;
6+
using Microsoft.WindowsAzure.Commands.Utilities.Common;
7+
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Net.Http;
11+
using System.Net.Http.Headers;
12+
using System.Threading;
13+
using System.Threading.Tasks;
14+
15+
using static Azure.Core.HttpHeader;
16+
17+
namespace Microsoft.Azure.Commands.Common.Authentication.Extensions
18+
{
19+
internal static class ArmClientOptionExtension
20+
{
21+
22+
internal class AzPsHttpMessageHandler : HttpMessageHandler
23+
{
24+
private IEnumerable<ProductInfoHeaderValue> _userAgent;
25+
26+
public AzPsHttpMessageHandler(IEnumerable<ProductInfoHeaderValue> userAgent)
27+
{
28+
_userAgent = userAgent;
29+
}
30+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
31+
{
32+
_userAgent?.ForEach((agent) => {
33+
request.Headers.UserAgent.Add(agent);
34+
});
35+
36+
return SendAsync(request, cancellationToken);
37+
}
38+
}
39+
40+
/// <summary>
41+
/// Set max retry times of retry after handler that is used to handle the response with retry-after header
42+
/// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429
43+
/// </summary>
44+
/// <returns>Whether succeed to set max retry times or not</returns>
45+
public static void AddUserAgent(this ArmClientOptions option, ProductInfoHeaderValue[] userAgent)
46+
{
47+
option.AddPolicy(new UserAgentPolicy(userAgent), HttpPipelinePosition.PerCall);
48+
}
49+
50+
/// <summary>
51+
/// Set max retry times of retry after handler that is used to handle the response with retry-after header
52+
/// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429
53+
/// </summary>
54+
/// <returns>Whether succeed to set max retry times or not</returns>
55+
public static void SetMaxDelayForRetryOption(this ArmClientOptions option, int maxDelay)
56+
{
57+
int? maxretriesfor429 = HttpRetryTimes.AzurePsHttpMaxRetriesFor429;
58+
if (maxretriesfor429 != null && maxretriesfor429 >= 0)
59+
{
60+
option.Retry.MaxDelay = new TimeSpan();
61+
}
62+
}
63+
64+
/// <summary>
65+
/// Set max retry count of retry policy from environement variable AZURE_PS_HTTP_MAX_RETRIES
66+
/// </summary>
67+
/// <returns>Whether succeed to set retry count or not</returns>
68+
public static void SetMaxRetryCountofRetryOption(this ArmClientOptions option, int maxRetries)
69+
{
70+
option.Retry.MaxRetries = maxRetries;
71+
}
72+
}
73+
}

src/Accounts/Authentication/Extensions/ServiceClientExtension.cs

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,14 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Microsoft.Azure.Commands.Common.Authentication.Policy;
1516
using Microsoft.Rest.TransientFaultHandling;
1617
using System;
1718

1819
namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions
1920
{
2021
internal static class ServiceClientExtension
2122
{
22-
private class HttpRetryTimes
23-
{
24-
private const string maxRetriesVariableName = "AZURE_PS_HTTP_MAX_RETRIES";
25-
private const string maxRetriesFor429VariableName = "AZURE_PS_HTTP_MAX_RETRIES_FOR_429";
26-
27-
public static int? AzurePsHttpMaxRetries
28-
{
29-
get
30-
{
31-
return TryGetAzurePsHttpMaxRetries();
32-
}
33-
}
34-
public static int? AzurePsHttpMaxRetriesFor429
35-
{
36-
get
37-
{
38-
return TryGetAzurePsHttpMaxRetriesFor429();
39-
}
40-
}
41-
42-
private static int? TryGetValue(string environmentVariable)
43-
{
44-
int? retries = null;
45-
var value = Environment.GetEnvironmentVariable(environmentVariable);
46-
if (value != null)
47-
{
48-
int valueParsed = int.MinValue;
49-
if (int.TryParse(value, out valueParsed))
50-
{
51-
retries = valueParsed;
52-
}
53-
}
54-
return retries;
55-
}
56-
57-
private static int? TryGetAzurePsHttpMaxRetries()
58-
{
59-
return TryGetValue(maxRetriesVariableName);
60-
}
61-
62-
private static int? TryGetAzurePsHttpMaxRetriesFor429()
63-
{
64-
return TryGetValue(maxRetriesFor429VariableName);
65-
}
66-
}
67-
6823
private static bool SetMaxTimesForRetryAfterHandler<TClient>(this Microsoft.Rest.ServiceClient<TClient> serviceClient, uint retrytimes) where TClient : Microsoft.Rest.ServiceClient<TClient>
6924
{
7025
bool findRetryHandler = false;
@@ -101,7 +56,7 @@ public static bool TrySetMaxTimesForRetryAfterHandler<TClient>(this Microsoft.Re
10156
/// <returns>Whether succeed to set retry count or not</returns>
10257
public static bool TrySetRetryCountofRetryPolicy<TClient>(this Microsoft.Rest.ServiceClient<TClient> serviceClient) where TClient : Microsoft.Rest.ServiceClient<TClient>
10358
{
104-
int? maxretries = ServiceClientExtension.HttpRetryTimes.AzurePsHttpMaxRetries;
59+
int? maxretries = HttpRetryTimes.AzurePsHttpMaxRetries;
10560
if (maxretries != null && maxretries >= 0)
10661
{
10762
TimeSpan defaultBackoffDelta = new TimeSpan(0, 0, 10);

src/Accounts/Authentication/Factories/AuthenticationFactory.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Azure.Core;
16+
1517
using Hyak.Common;
1618
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
1719
using Microsoft.Azure.Commands.Common.Authentication.Authentication;
@@ -325,6 +327,85 @@ public SubscriptionCloudCredentials GetSubscriptionCloudCredentials(IAzureContex
325327
}
326328
}
327329

330+
public TokenCredential GetTokenCredential(IAzureContext context) =>
331+
GetTokenCredential(context, AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId);
332+
333+
public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint)
334+
{
335+
if (context == null)
336+
{
337+
throw new AzPSApplicationException("Azure context is empty");
338+
}
339+
return GetTokenCredential(context, targetEndpoint, context.Environment.GetTokenAudience(targetEndpoint));
340+
}
341+
342+
public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint, string resourceId)
343+
{
344+
if (context.Account == null)
345+
{
346+
throw new AzPSArgumentException(Resources.ArmAccountNotFound, "context.Account", ErrorKind.UserError);
347+
}
348+
switch (context.Account.Type)
349+
{
350+
case AzureAccount.AccountType.Certificate:
351+
throw new NotSupportedException(AzureAccount.AccountType.Certificate.ToString());
352+
case AzureAccount.AccountType.AccessToken:
353+
return new AzureTokenCredential(GetEndpointToken(context.Account, targetEndpoint),
354+
() => GetEndpointToken(context.Account, targetEndpoint));
355+
}
356+
357+
string tenant = null;
358+
359+
if (context.Subscription != null && context.Account != null)
360+
{
361+
tenant = context.Subscription.GetPropertyAsArray(AzureSubscription.Property.Tenants)
362+
.Intersect(context.Account.GetPropertyAsArray(AzureAccount.Property.Tenants))
363+
.FirstOrDefault();
364+
}
365+
366+
if (tenant == null && context.Tenant != null && new Guid(context.Tenant.Id) != Guid.Empty)
367+
{
368+
tenant = context.Tenant.Id.ToString();
369+
}
370+
371+
if (tenant == null)
372+
{
373+
throw new ArgumentException(Resources.NoTenantInContext);
374+
}
375+
376+
try
377+
{
378+
TracingAdapter.Information(Resources.UPNAuthenticationTrace,
379+
context.Account.Id, context.Environment.Name, tenant);
380+
381+
IAccessToken accesstoken = null;
382+
switch (context.Account.Type)
383+
{
384+
case AzureAccount.AccountType.ManagedService:
385+
case AzureAccount.AccountType.User:
386+
case AzureAccount.AccountType.ServicePrincipal:
387+
case "ClientAssertion":
388+
accesstoken = Authenticate(context.Account, context.Environment, tenant, null, ShowDialog.Never, null, resourceId);
389+
break;
390+
default:
391+
throw new NotSupportedException(context.Account.Type.ToString());
392+
}
393+
394+
TracingAdapter.Information(Resources.UPNAuthenticationTokenTrace,
395+
accesstoken.LoginType, accesstoken.TenantId, accesstoken.UserId);
396+
return new AzureTokenCredential(accesstoken.AccessToken);
397+
}
398+
catch (Exception ex)
399+
{
400+
TracingAdapter.Information(Resources.AdalAuthException, ex.Message);
401+
throw new AzPSArgumentException(Resources.InvalidArmContext + System.Environment.NewLine + ex.Message, ex);
402+
}
403+
}
404+
405+
public TokenCredential GetTokenCredential(string accessToken, Func<string> renew = null)
406+
{
407+
return new AzureTokenCredential(accessToken, renew);
408+
}
328409

329410
public ServiceClientCredentials GetServiceClientCredentials(IAzureContext context)
330411
{

0 commit comments

Comments
 (0)