Skip to content

Push Release 2019 01 30 -> master #8488

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

Merged
merged 6 commits into from
Feb 7, 2019
Merged
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
10 changes: 10 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 1.2.1 - January 2019
#### Az.Accounts
* Release with correct version of Authentication

#### Az.AnalysisServices
* Release with updated Authentication dependency

#### Az.RecoveryServices
* Release with updated Authentication dependency

## 1.2.0 - January 2019
#### Az.Accounts
* Add interactive and username/password authentication for Windows PowerShell 5.1 only
Expand Down
15 changes: 13 additions & 2 deletions src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,24 @@ public override void ExecuteCmdlet()
Path = "/oauth2/token"
};

var envSecret = System.Environment.GetEnvironmentVariable(MSISecretVariable);

var msiSecret = this.IsBound(nameof(ManagedServiceSecret))
? ManagedServiceSecret.ConvertToString()
: System.Environment.GetEnvironmentVariable(MSISecretVariable);
: envSecret;

var envUri = System.Environment.GetEnvironmentVariable(MSIEndpointVariable);

var suppliedUri = this.IsBound(nameof(ManagedServiceHostName))
? builder.Uri.ToString()
: System.Environment.GetEnvironmentVariable(MSIEndpointVariable);
: envUri;

if (!this.IsBound(nameof(ManagedServiceHostName)) && !string.IsNullOrWhiteSpace(envUri)
&& !this.IsBound(nameof(ManagedServiceSecret)) && !string.IsNullOrWhiteSpace(envSecret))
{
// set flag indicating this is AppService Managed Identity ad hoc mode
azureAccount.SetProperty(AuthenticationFactory.AppServiceManagedIdentityFlag, "the value not used");
}

if (!string.IsNullOrWhiteSpace(msiSecret))
{
Expand Down
6 changes: 2 additions & 4 deletions src/Accounts/Accounts/Az.Accounts.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# RootModule = ''

# Version number of this module.
ModuleVersion = '1.2.0'
ModuleVersion = '1.2.1'

# Supported PSEditions
CompatiblePSEditions = 'Core', 'Desktop'
Expand Down Expand Up @@ -141,9 +141,7 @@ PrivateData = @{
# IconUri = ''

# ReleaseNotes of this module
ReleaseNotes = '* Add interactive and username/password authentication for Windows PowerShell 5.1 only
* Update incorrect online help URLs
* Add warning message in PS Core for Uninstall-AzureRm'
ReleaseNotes = '* Release with correct version of Authentication'

# Prerelease string of this module
# Prerelease = ''
Expand Down
4 changes: 4 additions & 0 deletions src/Accounts/Accounts/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
-->
## Upcoming Release

## Version 1.2.1
* Release with correct version of Authentication
* Enable MSI Authentication in Azure Functions and WebApps

## Version 1.2.0
* Add interactive and username/password authentication for Windows PowerShell 5.1 only
* Update incorrect online help URLs
Expand Down
4 changes: 2 additions & 2 deletions src/Accounts/Accounts/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:

[assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyVersion("1.2.1")]
[assembly: AssemblyFileVersion("1.2.1")]
#if SIGN
[assembly: InternalsVisibleTo("Microsoft.Azure.PowerShell.Cmdlets.Accounts.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("Microsoft.WindowsAzure.Commands.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
Expand Down
52 changes: 44 additions & 8 deletions src/Accounts/Authentication.Test/AuthenticationFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

using Microsoft.Azure.Commands.Common.Authentication;
using Microsoft.Azure.Commands.Common.Authentication.Factories;
using Microsoft.Azure.Commands.Common.Authentication.Models;
using Microsoft.WindowsAzure.Commands.Test.Utilities.Common;
using System;
using System.Collections.Generic;
Expand All @@ -25,8 +24,6 @@
using Microsoft.Azure.Commands.Common.Authentication.Test;
using Microsoft.WindowsAzure.Commands.Utilities.Common;
using Xunit.Abstractions;
using Microsoft.Rest.Azure;
using Microsoft.Azure.Commands.ResourceManager.Common;

namespace Common.Authentication.Test
{
Expand Down Expand Up @@ -180,7 +177,7 @@ public void CanAuthenticateUsingMSIDefault()
IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
Assert.Equal(3600, Math.Round(token.ExpiresOn.Subtract(DateTimeOffset.Now).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
Expand Down Expand Up @@ -230,7 +227,7 @@ public void CanAuthenticateUsingMSIResourceId()
IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
Assert.Equal(3600, Math.Round(token.ExpiresOn.Subtract(DateTimeOffset.Now).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
Expand Down Expand Up @@ -279,7 +276,7 @@ public void CanAuthenticateUsingMSIClientId()
IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
Assert.Equal(3600, Math.Round(token.ExpiresOn.Subtract(DateTimeOffset.Now).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
Expand Down Expand Up @@ -328,7 +325,7 @@ public void CanAuthenticateUsingMSIObjectId()
IRenewableToken token = (IRenewableToken) authFactory.Authenticate(account, environment, tenant, null, null, null);
_output.WriteLine($"Received access token for default Uri ${token.AccessToken}");
Assert.Equal(expectedAccessToken, token.AccessToken);
Assert.Equal(3600, Math.Round(token.ExpiresOn.DateTime.Subtract(DateTime.UtcNow).TotalSeconds));
Assert.Equal(3600, Math.Round(token.ExpiresOn.Subtract(DateTimeOffset.Now).TotalSeconds));
var account2 = new AzureAccount
{
Id = userId,
Expand All @@ -351,7 +348,6 @@ void ResponseRedactionWorks()

void VerifyToken(IAccessToken checkToken, string expectedAccessToken, string expectedUserId, string expectedTenant)
{

Assert.True(checkToken is RawAccessToken);
Assert.Equal(expectedAccessToken, checkToken.AccessToken);
Assert.Equal(expectedUserId, checkToken.UserId);
Expand All @@ -363,5 +359,45 @@ void VerifyToken(IAccessToken checkToken, string expectedAccessToken, string exp
});
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void AppServiceManagedIdentity()
{
AzureSessionInitializer.InitializeAzureSession();
var tenant = Guid.NewGuid().ToString();
var userId = Guid.NewGuid().ToString();
var environment = AzureEnvironment.PublicEnvironments["AzureCloud"];
var account = new AzureAccount
{
Id = userId,
Type = AzureAccount.AccountType.ManagedService
};
const string resource = @"https://management.azure.com/";
const string endpoint = @"http://127.0.0.1:41217/MSI/token/";
var expectedUri = $"{endpoint}?resource={resource}&api-version=2017-09-01";
account.SetProperty(AzureAccount.Property.MSILoginUri , endpoint);
account.SetProperty(AzureAccount.Property.MSILoginSecret , @"bar");
const string expectedAccessToken = "foo";
var expectedExpiresOn = DateTimeOffset.Parse("1/23/2019 7:15:42 AM +00:00");
var responses = new Dictionary<string, ManagedServiceAppServiceTokenInfo>(StringComparer.OrdinalIgnoreCase)
{
{
expectedUri,
new ManagedServiceAppServiceTokenInfo()
{
AccessToken = expectedAccessToken,
ExpiresOn = expectedExpiresOn,
Resource = resource,
TokenType = "Bearer",
}
}
};
AzureSession.Instance.RegisterComponent(HttpClientOperationsFactory.Name, () => TestHttpOperationsFactory.Create(responses, _output), true);
var msat = new ManagedServiceAppServiceAccessToken(account, environment, tenant);
Assert.Equal(expectedUri, msat.RequestUris.Peek());
var accessToken = msat.AccessToken;
Assert.Equal(expectedAccessToken, accessToken);
Assert.Equal(expectedExpiresOn, msat.ExpiresOn);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,204 +13,24 @@
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.Common.Authentication.Properties;
using Microsoft.Rest.Azure;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;

namespace Microsoft.Azure.Commands.Common.Authentication
{
public class ManagedServiceAccessToken : IRenewableToken
public class ManagedServiceAccessToken : ManagedServiceAccessTokenBase<ManagedServiceTokenInfo>
{
IAzureAccount _account;
string _tenant;
string _resourceId;
IHttpOperations<ManagedServiceTokenInfo> _tokenGetter;
DateTime _expiration = DateTime.UtcNow;
string _accessToken;

public ManagedServiceAccessToken(IAzureAccount account, IAzureEnvironment environment, string resourceId, string tenant = "Common")
: base(account, environment, resourceId, tenant)
{
if (account == null || string.IsNullOrEmpty(account.Id) || !account.IsPropertySet(AzureAccount.Property.MSILoginUri))
{
throw new ArgumentNullException(nameof(account));
}

if (string.IsNullOrWhiteSpace(tenant))
{
throw new ArgumentNullException(nameof(tenant));
}

if (environment == null)
{
throw new ArgumentNullException(nameof(environment));
}

_account = account;
_resourceId = GetResource(resourceId, environment);
var idType = GetIdentityType(account);
foreach (var uri in BuildTokenUri(_account.GetProperty(AzureAccount.Property.MSILoginUri), account, idType, _resourceId))
{
RequestUris.Enqueue(uri);
}

if (account.IsPropertySet(AzureAccount.Property.MSILoginUriBackup))
{
foreach (var uri in BuildTokenUri(_account.GetProperty(AzureAccount.Property.MSILoginUriBackup), account, idType, _resourceId))
{
RequestUris.Enqueue(uri);
}
}

_tenant = tenant;
IHttpOperationsFactory factory;
if (!AzureSession.Instance.TryGetComponent(HttpClientOperationsFactory.Name, out factory))
{
factory = HttpClientOperationsFactory.Create();
}

_tokenGetter = factory.GetHttpOperations<ManagedServiceTokenInfo>(true).WithHeader("Metadata", new[] { "true" });
if (account.IsPropertySet(AzureAccount.Property.MSILoginSecret))
{
_tokenGetter = _tokenGetter.WithHeader("Secret", new[] { account.GetProperty(AzureAccount.Property.MSILoginSecret) });
}
}

public string AccessToken
{
get
{
try
{
GetOrRenewAuthentication();
}
catch (CloudException httpException)
{
throw new InvalidOperationException(string.Format(Resources.MSITokenRequestFailed, _resourceId, httpException?.Request?.RequestUri?.ToString()), httpException);
}

return _accessToken;
}
}

public Queue<string> RequestUris { get; } = new Queue<string>();

public string LoginType => "ManagedService";

public string TenantId => _tenant;

public string UserId => _account.Id;

public DateTimeOffset ExpiresOn
{
get
{
return _expiration;
}
}

public void AuthorizeRequest(Action<string, string> authTokenSetter)
{
authTokenSetter("Bearer", AccessToken);
}

void GetOrRenewAuthentication()
{
if (_expiration - DateTime.UtcNow < ManagedServiceTokenInfo.TimeoutThreshold)
{
ManagedServiceTokenInfo info = null;
while (info == null && RequestUris.Count > 0)
{
var currentRequestUri = RequestUris.Dequeue();
try
{
info = _tokenGetter.GetAsync(currentRequestUri, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
// if a request was succesful, we should not check any other Uris
RequestUris.Clear();
RequestUris.Enqueue(currentRequestUri);
}
catch (Exception e) when ( (e is CloudException || e is HttpRequestException) && RequestUris.Count > 0)
{
// skip to the next uri
}
}

SetToken(info);
}
}

void SetToken(ManagedServiceTokenInfo info)
protected override void SetToken(ManagedServiceTokenInfo info)
{
if (info != null)
{
_expiration = DateTime.UtcNow + TimeSpan.FromSeconds(info.ExpiresIn);
_accessToken = info.AccessToken;
}
}

static IdentityType GetIdentityType(IAzureAccount account)
{
if (account == null || string.IsNullOrWhiteSpace(account.Id) || account.Id.Contains("@"))
{
return IdentityType.SystemAssigned;
}

if (account.Id.Contains("/"))
{
return IdentityType.Resource;
}

return IdentityType.ClientId;
}

static string GetResource(string endpointOrResource, IAzureEnvironment environment)
{
return environment.GetEndpoint(endpointOrResource) ?? endpointOrResource;
}

static IEnumerable<string> BuildTokenUri(string baseUri, IAzureAccount account, IdentityType identityType, string resourceId)
{
UriBuilder builder = new UriBuilder(baseUri);
builder.Query = BuildTokenQuery(account, identityType, resourceId);
yield return builder.Uri.ToString();

if (identityType == IdentityType.ClientId)
{
builder = new UriBuilder(baseUri);
builder.Query = BuildTokenQuery(account, IdentityType.ObjectId, resourceId);
yield return builder.Uri.ToString();
Expiration = DateTimeOffset.Now + TimeSpan.FromSeconds(info.ExpiresIn);
accessToken = info.AccessToken;
}
}

static string BuildTokenQuery(IAzureAccount account, IdentityType idType, string resource)
{
StringBuilder query = new StringBuilder($"resource={Uri.EscapeDataString(resource)}");
switch (idType)
{
case IdentityType.Resource:
query.Append($"&msi_res_id={Uri.EscapeDataString(account.Id)}");
break;
case IdentityType.ClientId:
query.Append($"&client_id={Uri.EscapeDataString(account.Id)}");
break;
case IdentityType.ObjectId:
query.Append($"&object_id={Uri.EscapeDataString(account.Id)}");
break;
}

query.Append("&api-version=2018-02-01");
return query.ToString();
}

enum IdentityType
{
Resource,
ClientId,
ObjectId,
SystemAssigned
}
}
}
Loading