Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Accounts/Accounts.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Test", "Auth
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthenticationAssemblyLoadContext", "AuthenticationAssemblyLoadContext\AuthenticationAssemblyLoadContext.csproj", "{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Abstractions", "..\..\..\azure-powershell-common\src\Authentication.Abstractions\Authentication.Abstractions.csproj", "{97A8C183-F5DF-466D-B45B-B7FF70C04639}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "..\..\..\azure-powershell-common\src\Common\Common.csproj", "{E464D47C-DF5C-4B52-910E-59D326E0C1F7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graph.Rbac", "..\..\..\azure-powershell-common\src\Graph.Rbac\Graph.Rbac.csproj", "{A49450CD-4FC5-430B-BE9C-B3272E0981EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResourceManager", "..\..\..\azure-powershell-common\src\ResourceManager\ResourceManager.csproj", "{E05F1B15-5799-4864-8D20-CA8F04AB50EB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -64,6 +72,22 @@ Global
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.Build.0 = Release|Any CPU
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.Build.0 = Release|Any CPU
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.Build.0 = Release|Any CPU
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.Build.0 = Release|Any CPU
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
7 changes: 5 additions & 2 deletions src/Accounts/Accounts/Accounts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@
<ItemGroup>
<ProjectReference Include="..\Authentication.ResourceManager\Authentication.ResourceManager.csproj" />
<ProjectReference Include="..\Authentication\Authentication.csproj" />
<ProjectReference Include="..\Authenticators\Authenticators.csproj" />
<ProjectReference Include="..\Authenticators\Authenticators.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\Authentication.Abstractions\Authentication.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\Common\Common.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\ResourceManager\ResourceManager.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
Expand Down
4 changes: 2 additions & 2 deletions src/Accounts/Accounts/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory).., Directory.Build.targets))\Directory.Build.targets" />
<Target Name ="BuildAssemblyLoadContextProject" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<!--<Target Name ="BuildAssemblyLoadContextProject" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Exec Command="dotnet build ../AuthenticationAssemblyLoadContext/AuthenticationAssemblyLoadContext.csproj"/>
</Target>
</Target>-->
<Target Name="AddAccountsPsm1Dependency" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<Exec Command="pwsh -NonInteractive -NoLogo -NoProfile -Command &quot;. '$(OutDir)../../../tools/AddModulePsm1Dependency.ps1' -ModuleFolder '$(OutDir)' -IgnorePwshVersion &quot;" />
</Target>
Expand Down
7 changes: 6 additions & 1 deletion src/Accounts/Authentication/Authentication.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\Authentication.Abstractions\Authentication.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\Common\Common.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\ResourceManager\ResourceManager.csproj" />
<ProjectReference Include="..\..\..\..\azure-powershell-common\src\Graph.Rbac\Graph.Rbac.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
Expand Down
37 changes: 37 additions & 0 deletions src/Accounts/Authentication/Authentication/AzureTokenCredential.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Azure.Core;

using Microsoft.Azure.Commands.Common.Authentication.Abstractions;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Azure.Commands.Common.Authentication.Authentication
{
public class AzureTokenCredential : TokenCredential
{
public string AccessToken { get; set; }

private readonly Func<string> GetTokenImpl;

public AzureTokenCredential(string accessToken, Func<string> getTokenImpl = null)
{
AccessToken = accessToken;
GetTokenImpl = getTokenImpl;
}

public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new AccessToken(GetTokenImpl == null ? AccessToken : GetTokenImpl(),
DateTimeOffset.UtcNow);
}

public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
return new ValueTask<AccessToken>(this.GetToken(requestContext, cancellationToken));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// ----------------------------------------------------------------------------------



// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
80 changes: 80 additions & 0 deletions src/Accounts/Authentication/Extensions/ArmClientOptionExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Azure.Core;
using Azure.Core.Pipeline;
using Azure.ResourceManager;

using Microsoft.Azure.Commands.Common.Authentication.Policy;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

using static Azure.Core.HttpHeader;

namespace Microsoft.Azure.Commands.Common.Authentication.Extensions
{
internal static class ArmClientOptionExtension
{

internal class AzPsHttpMessageHandler : HttpMessageHandler
{
private IEnumerable<ProductInfoHeaderValue> _userAgent;

public AzPsHttpMessageHandler(IEnumerable<ProductInfoHeaderValue> userAgent)
{
_userAgent = userAgent;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_userAgent?.ForEach((agent) => {
request.Headers.UserAgent.Add(agent);
});

return SendAsync(request, cancellationToken);
}
}

/// <summary>
/// Set max retry times of retry after handler that is used to handle the response with retry-after header
/// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429
/// </summary>
/// <returns>Whether succeed to set max retry times or not</returns>
public static void AddUserAgent(this ArmClientOptions option, ProductInfoHeaderValue[] userAgent)
{
if (null == option.Transport || default(HttpPipelineTransport) == option.Transport)
{
option.Transport = new HttpClientTransport(new AzPsHttpMessageHandler(userAgent));
}
else
{
throw new Exception("Client Transport already has defined.");
}
}

/// <summary>
/// Set max retry times of retry after handler that is used to handle the response with retry-after header
/// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429
/// </summary>
/// <returns>Whether succeed to set max retry times or not</returns>
public static void SetMaxDelayForRetryOption(this ArmClientOptions option, int maxDelay)
{
int? maxretriesfor429 = HttpRetryTimes.AzurePsHttpMaxRetriesFor429;
if (maxretriesfor429 != null && maxretriesfor429 >= 0)
{
option.Retry.MaxDelay = new TimeSpan();
}
}

/// <summary>
/// Set max retry count of retry policy from environement variable AZURE_PS_HTTP_MAX_RETRIES
/// </summary>
/// <returns>Whether succeed to set retry count or not</returns>
public static void SetMaxRetryCountofRetryOption(this ArmClientOptions option, int maxRetries)
{
option.Retry.MaxRetries = maxRetries;
}
}
}
49 changes: 2 additions & 47 deletions src/Accounts/Authentication/Extensions/ServiceClientExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,14 @@
// limitations under the License.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.Common.Authentication.Policy;
using Microsoft.Rest.TransientFaultHandling;
using System;

namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions
{
internal static class ServiceClientExtension
{
private class HttpRetryTimes
{
private const string maxRetriesVariableName = "AZURE_PS_HTTP_MAX_RETRIES";
private const string maxRetriesFor429VariableName = "AZURE_PS_HTTP_MAX_RETRIES_FOR_429";

public static int? AzurePsHttpMaxRetries
{
get
{
return TryGetAzurePsHttpMaxRetries();
}
}
public static int? AzurePsHttpMaxRetriesFor429
{
get
{
return TryGetAzurePsHttpMaxRetriesFor429();
}
}

private static int? TryGetValue(string environmentVariable)
{
int? retries = null;
var value = Environment.GetEnvironmentVariable(environmentVariable);
if (value != null)
{
int valueParsed = int.MinValue;
if (int.TryParse(value, out valueParsed))
{
retries = valueParsed;
}
}
return retries;
}

private static int? TryGetAzurePsHttpMaxRetries()
{
return TryGetValue(maxRetriesVariableName);
}

private static int? TryGetAzurePsHttpMaxRetriesFor429()
{
return TryGetValue(maxRetriesFor429VariableName);
}
}

private static bool SetMaxTimesForRetryAfterHandler<TClient>(this Microsoft.Rest.ServiceClient<TClient> serviceClient, uint retrytimes) where TClient : Microsoft.Rest.ServiceClient<TClient>
{
bool findRetryHandler = false;
Expand Down Expand Up @@ -101,7 +56,7 @@ public static bool TrySetMaxTimesForRetryAfterHandler<TClient>(this Microsoft.Re
/// <returns>Whether succeed to set retry count or not</returns>
public static bool TrySetRetryCountofRetryPolicy<TClient>(this Microsoft.Rest.ServiceClient<TClient> serviceClient) where TClient : Microsoft.Rest.ServiceClient<TClient>
{
int? maxretries = ServiceClientExtension.HttpRetryTimes.AzurePsHttpMaxRetries;
int? maxretries = HttpRetryTimes.AzurePsHttpMaxRetries;
if (maxretries != null && maxretries >= 0)
{
TimeSpan defaultBackoffDelta = new TimeSpan(0, 0, 10);
Expand Down
81 changes: 81 additions & 0 deletions src/Accounts/Authentication/Factories/AuthenticationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// limitations under the License.
// ----------------------------------------------------------------------------------

using Azure.Core;

using Hyak.Common;
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.Common.Authentication.Authentication;
Expand Down Expand Up @@ -324,6 +326,85 @@ public SubscriptionCloudCredentials GetSubscriptionCloudCredentials(IAzureContex
}
}

public TokenCredential GetTokenCredential(IAzureContext context) =>
GetTokenCredential(context, AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId);

public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint)
{
if (context == null)
{
throw new AzPSApplicationException("Azure context is empty");
}
return GetTokenCredential(context, targetEndpoint, context.Environment.GetTokenAudience(targetEndpoint));
}

public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint, string resourceId)
{
if (context.Account == null)
{
throw new AzPSArgumentException(Resources.ArmAccountNotFound, "context.Account", ErrorKind.UserError);
}
switch (context.Account.Type)
{
case AzureAccount.AccountType.Certificate:
throw new NotSupportedException(AzureAccount.AccountType.Certificate.ToString());
case AzureAccount.AccountType.AccessToken:
return new AzureTokenCredential(GetEndpointToken(context.Account, targetEndpoint),
() => GetEndpointToken(context.Account, targetEndpoint));
}

string tenant = null;

if (context.Subscription != null && context.Account != null)
{
tenant = context.Subscription.GetPropertyAsArray(AzureSubscription.Property.Tenants)
.Intersect(context.Account.GetPropertyAsArray(AzureAccount.Property.Tenants))
.FirstOrDefault();
}

if (tenant == null && context.Tenant != null && new Guid(context.Tenant.Id) != Guid.Empty)
{
tenant = context.Tenant.Id.ToString();
}

if (tenant == null)
{
throw new ArgumentException(Resources.NoTenantInContext);
}

try
{
TracingAdapter.Information(Resources.UPNAuthenticationTrace,
context.Account.Id, context.Environment.Name, tenant);

IAccessToken accesstoken = null;
switch (context.Account.Type)
{
case AzureAccount.AccountType.ManagedService:
case AzureAccount.AccountType.User:
case AzureAccount.AccountType.ServicePrincipal:
case "ClientAssertion":
accesstoken = Authenticate(context.Account, context.Environment, tenant, null, ShowDialog.Never, null, resourceId);
break;
default:
throw new NotSupportedException(context.Account.Type.ToString());
}

TracingAdapter.Information(Resources.UPNAuthenticationTokenTrace,
accesstoken.LoginType, accesstoken.TenantId, accesstoken.UserId);
return new AzureTokenCredential(accesstoken.AccessToken);
}
catch (Exception ex)
{
TracingAdapter.Information(Resources.AdalAuthException, ex.Message);
throw new AzPSArgumentException(Resources.InvalidArmContext + System.Environment.NewLine + ex.Message, ex);
}
}

public TokenCredential GetTokenCredential(string accessToken, Func<string> renew = null)
{
return new AzureTokenCredential(accessToken, renew);
}

public ServiceClientCredentials GetServiceClientCredentials(IAzureContext context)
{
Expand Down
Loading