update to ADAL 2.14.201151115 version

This commit is contained in:
Suwath Ch 2015-01-25 12:47:08 -08:00
Родитель 8aa6567157
Коммит 5563bbe554
20 изменённых файлов: 561 добавлений и 296 удалений

Просмотреть файл

@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ARMClient.Authentication.Contracts;
using ARMClient.Authentication.EnvironmentStorage;
using ARMClient.Authentication.TenantStorage;
using ARMClient.Authentication.TokenStorage;
using ARMClient.Authentication.Utilities;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json.Linq;
@ -36,93 +35,80 @@ namespace ARMClient.Authentication.AADAuthentication
public async Task AcquireTokens()
{
var tokenCache = new Dictionary<TokenCacheKey, string>();
var authResult = await GetAuthorizationResult(tokenCache, Constants.AADTenantId);
Trace.WriteLine(string.Format("Welcome {0} (Tenant: {1})", authResult.UserInfo.UserId, authResult.TenantId));
this.TokenStorage.ClearCache();
this.TenantStorage.ClearCache();
var tenantCache = await GetTokenForTenants(tokenCache, authResult);
var tokenCache = new CustomTokenCache();
var cacheInfo = await GetAuthorizationResult(tokenCache, Constants.AADTenantId);
Utils.Trace.WriteLine(string.Format("Welcome {0} (Tenant: {1})", cacheInfo.DisplayableId, cacheInfo.TenantId));
var tenantCache = await GetTokenForTenants(tokenCache, cacheInfo);
this.TokenStorage.SaveCache(tokenCache);
this.TenantStorage.SaveCache(tenantCache);
}
public async Task<AuthenticationResult> GetTokenByTenant(string tenantId)
public async Task<TokenCacheInfo> GetToken(string id, string resource)
{
var found = false;
var tenantCache = this.TenantStorage.GetCache();
if (tenantCache.ContainsKey(tenantId))
if (String.IsNullOrEmpty(id))
{
found = true;
return await GetRecentToken(resource);
}
if (!found)
string tenantId = null;
var tenantCache = this.TenantStorage.GetCache();
if (tenantCache.ContainsKey(id))
{
tenantId = id;
}
if (String.IsNullOrEmpty(tenantId))
{
foreach (var tenant in tenantCache)
{
if (tenant.Value.subscriptions.Any(s => s.subscriptionId == tenantId))
if (tenant.Value.subscriptions.Any(s => s.subscriptionId == id))
{
tenantId = tenant.Key;
found = true;
break;
}
}
}
if (!found)
if (String.IsNullOrEmpty(tenantId))
{
return await GetRecentToken();
return await GetRecentToken(resource);
}
if (resource == null)
{
resource = id == tenantId ? Constants.AADGraphUrls[(int)AzureEnvironments] : Constants.CSMResource;
}
var tokenCache = this.TokenStorage.GetCache();
var authResults = tokenCache.Where(p => p.Key.TenantId == tenantId && String.Equals(p.Key.Resource, Constants.CSMResource, StringComparison.OrdinalIgnoreCase))
.Select(p => AuthenticationResult.Deserialize(Encoding.UTF8.GetString(Convert.FromBase64String(p.Value)))).ToArray();
if (authResults.Length <= 0)
TokenCacheInfo cacheInfo;
if (!tokenCache.TryGetValue(tenantId, resource, out cacheInfo))
{
return await GetRecentToken();
return await GetRecentToken(resource);
}
if (authResults.Length > 1)
if (cacheInfo.ExpiresOn <= DateTimeOffset.UtcNow)
{
foreach (var authResult in authResults)
{
Trace.WriteLine(authResult.UserInfo.UserId);
}
throw new InvalidOperationException("Multiple users found. Please specify user argument!");
cacheInfo = await RefreshToken(tokenCache, cacheInfo);
this.TokenStorage.SaveCache(tokenCache);
}
else
{
var authResult = authResults[0];
if (authResult.ExpiresOn <= DateTime.UtcNow)
{
authResult = await RefreshToken(tokenCache, authResult);
this.TokenStorage.SaveCache(tokenCache);
}
this.TokenStorage.SaveRecentToken(authResult);
this.TokenStorage.SaveRecentToken(cacheInfo, resource);
return authResult;
}
return cacheInfo;
}
public async Task<AuthenticationResult> GetTokenBySubscription(string subscriptionId)
public async Task<TokenCacheInfo> GetTokenBySpn(string tenantId, string appId, string appKey)
{
var tenantCache = this.TenantStorage.GetCache();
var pairs = tenantCache.Where(p => p.Value.subscriptions.Any(subscription => subscriptionId == subscription.subscriptionId)).ToArray();
if (pairs.Length == 0)
{
return await GetRecentToken();
}
this.TokenStorage.ClearCache();
this.TenantStorage.ClearCache();
return await GetTokenByTenant(pairs[0].Key);
}
public async Task<AuthenticationResult> GetTokenBySpn(string tenantId, string appId, string appKey)
{
var tokenCache = new Dictionary<TokenCacheKey, string>();
var authResult = GetAuthorizationResultByAppKey(tokenCache, tenantId, appId, appKey);
var tokenCache = new CustomTokenCache();
var cacheInfo = GetAuthorizationResultBySpn(tokenCache, tenantId, appId, appKey, Constants.CSMResource);
var tenantCache = new Dictionary<string, TenantCacheInfo>();
var info = new TenantCacheInfo
@ -130,23 +116,21 @@ namespace ARMClient.Authentication.AADAuthentication
tenantId = tenantId
};
//try
//{
// var aadToken = GetAuthorizationResultByAppKey(tokenCache, tenantId, appId, appKey, Constants.AADGraphUrls[(int)AzureEnvironments]);
// var details = await GetTenantDetail(aadToken, tenantId);
// info.displayName = details.displayName;
// info.domain = details.verifiedDomains.First(d => d.@default).name;
// Trace.WriteLine(String.Format("App: {0}, Tenant: {1} ({2})", appId, tenantId, details.verifiedDomains.First(d => d.@default).name));
//}
//catch (Exception ex)
//{
// Trace.WriteLine(String.Format("App: {0}, Tenant: {1} {2}", appId, tenantId, ex.Message));
//}
try
{
var aadToken = GetAuthorizationResultBySpn(tokenCache, tenantId, appId, appKey, Constants.AADGraphUrls[(int)AzureEnvironments]);
var details = await GetTenantDetail(aadToken, tenantId);
info.displayName = details.displayName;
info.domain = details.verifiedDomains.First(d => d.@default).name;
Utils.Trace.WriteLine(String.Format("App: {0}, Tenant: {1} ({2})", appId, tenantId, details.verifiedDomains.First(d => d.@default).name));
}
catch (Exception)
{
Utils.Trace.WriteLine(String.Format("App: {0}, Tenant: {1}", appId, tenantId));
}
Trace.WriteLine(String.Format("App: {0}, Tenant: {1}", appId, tenantId));
var subscriptions = await GetSubscriptions(authResult);
Trace.WriteLine(String.Format("\tThere are {0} subscriptions", subscriptions.Length));
var subscriptions = await GetSubscriptions(cacheInfo);
Utils.Trace.WriteLine(String.Format("\tThere are {0} subscriptions", subscriptions.Length));
info.subscriptions = subscriptions.Select(subscription => new SubscriptionCacheInfo
{
@ -156,73 +140,94 @@ namespace ARMClient.Authentication.AADAuthentication
foreach (var subscription in subscriptions)
{
Trace.WriteLine(String.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
Utils.Trace.WriteLine(String.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
}
tenantCache[tenantId] = info;
this.TokenStorage.SaveRecentToken(authResult);
this.TokenStorage.SaveRecentToken(cacheInfo, Constants.CSMResource);
this.TokenStorage.SaveCache(tokenCache);
this.TenantStorage.SaveCache(tenantCache);
return authResult;
return cacheInfo;
}
public async Task<AuthenticationResult> GetRecentToken()
public async Task<TokenCacheInfo> GetTokenByUpn(string tenantId, string username, string password)
{
AuthenticationResult recentToken = this.TokenStorage.GetRecentToken();
if (recentToken != null && recentToken.ExpiresOn <= DateTime.UtcNow)
this.TokenStorage.ClearCache();
this.TenantStorage.ClearCache();
var tokenCache = new CustomTokenCache();
var cacheInfo = GetAuthorizationResultByUpn(tokenCache, tenantId, username, password, Constants.CSMResource);
var tenantCache = new Dictionary<string, TenantCacheInfo>();
var info = new TenantCacheInfo
{
tenantId = tenantId
};
try
{
var aadToken = GetAuthorizationResultByUpn(tokenCache, tenantId, username, password, Constants.AADGraphUrls[(int)AzureEnvironments]);
var details = await GetTenantDetail(aadToken, tenantId);
info.displayName = details.displayName;
info.domain = details.verifiedDomains.First(d => d.@default).name;
Utils.Trace.WriteLine(String.Format("User: {0}, Tenant: {1} ({2})", username, tenantId, details.verifiedDomains.First(d => d.@default).name));
}
catch (Exception)
{
Utils.Trace.WriteLine(String.Format("User: {0}, Tenant: {1}", username, tenantId));
}
var subscriptions = await GetSubscriptions(cacheInfo);
Utils.Trace.WriteLine(String.Format("\tThere are {0} subscriptions", subscriptions.Length));
info.subscriptions = subscriptions.Select(subscription => new SubscriptionCacheInfo
{
subscriptionId = subscription.subscriptionId,
displayName = subscription.displayName
}).ToArray();
foreach (var subscription in subscriptions)
{
Utils.Trace.WriteLine(String.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
}
tenantCache[tenantId] = info;
this.TokenStorage.SaveRecentToken(cacheInfo, Constants.CSMResource);
this.TokenStorage.SaveCache(tokenCache);
this.TenantStorage.SaveCache(tenantCache);
return cacheInfo;
}
protected async Task<TokenCacheInfo> GetRecentToken(string resource)
{
TokenCacheInfo cacheInfo = this.TokenStorage.GetRecentToken(resource);
if (cacheInfo != null && cacheInfo.ExpiresOn <= DateTimeOffset.UtcNow)
{
var tokenCache = this.TokenStorage.GetCache();
recentToken = await RefreshToken(tokenCache, recentToken);
cacheInfo = await RefreshToken(tokenCache, cacheInfo);
this.TokenStorage.SaveCache(tokenCache);
this.TokenStorage.SaveRecentToken(recentToken);
this.TokenStorage.SaveRecentToken(cacheInfo, resource);
}
return recentToken;
return cacheInfo;
}
protected async Task<AuthenticationResult> RefreshToken(Dictionary<TokenCacheKey, string> tokenCache, AuthenticationResult authResult)
protected async Task<TokenCacheInfo> RefreshToken(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
{
if (!String.IsNullOrEmpty(authResult.RefreshToken))
if (!String.IsNullOrEmpty(cacheInfo.RefreshToken))
{
authResult = await GetAuthorizationResult(tokenCache, authResult.TenantId, authResult.UserInfo.UserId);
return await GetAuthorizationResultByRefreshToken(tokenCache, cacheInfo);
}
else if (tokenCache.Count == 1)
else if (!String.IsNullOrEmpty(cacheInfo.AppId) && !String.IsNullOrEmpty(cacheInfo.AppKey))
{
var key = tokenCache.Keys.First();
string tenantId, appId, appKey;
GetApplicationInfo(key, out tenantId, out appId, out appKey);
if (!String.IsNullOrEmpty(tenantId) && !String.IsNullOrEmpty(appId) && !String.IsNullOrEmpty(appKey))
{
tokenCache.Clear();
authResult = GetAuthorizationResultByAppKey(tokenCache, tenantId, appId, appKey);
}
return GetAuthorizationResultBySpn(tokenCache, cacheInfo.TenantId, cacheInfo.AppId, cacheInfo.AppKey, cacheInfo.Resource);
}
return authResult;
}
private void SaveApplicationInfo(TokenCacheKey key, string tenantId, string appId, string appKey)
{
key.TenantId = tenantId;
key.ClientId = appId;
key.UserId = appKey;
}
private void GetApplicationInfo(TokenCacheKey key, out string tenantId, out string appId, out string appKey)
{
tenantId = key.TenantId;
appId = key.ClientId;
appKey = key.UserId;
}
public async Task<string> GetAuthorizationHeader(string subscriptionId)
{
return (await(string.IsNullOrEmpty(subscriptionId)
? GetRecentToken()
: GetTokenBySubscription(subscriptionId: subscriptionId)).ConfigureAwait(false)).CreateAuthorizationHeader();
throw new NotImplementedException();
}
public bool IsCacheValid()
@ -241,47 +246,72 @@ namespace ARMClient.Authentication.AADAuthentication
{
var tokenCache = this.TokenStorage.GetCache();
var tenantCache = this.TenantStorage.GetCache();
if (tokenCache.Count > 0)
foreach (var cacheItem in tokenCache.GetValues(Constants.CSMResource))
{
foreach (var item in tokenCache.Where(k => String.Equals(k.Key.Resource, Constants.CSMResource, StringComparison.OrdinalIgnoreCase)))
var tenantId = cacheItem.TenantId;
if (Constants.InfrastructureTenantIds.Contains(tenantId))
{
var key = item.Key;
var value = item.Value;
var authResult = AuthenticationResult.Deserialize(Encoding.UTF8.GetString(Convert.FromBase64String(value)));
var tenantId = authResult.TenantId ?? key.TenantId;
if (Constants.InfrastructureTenantIds.Contains(tenantId))
{
continue;
}
var details = tenantCache[tenantId];
if (authResult.UserInfo != null)
{
var user = authResult.UserInfo.UserId;
yield return string.Format("User: {0}, Tenant: {1} ({2})", user, tenantId, details.domain);
}
else
{
var appId = key.ClientId;
yield return string.Format("App: {0}, Tenant: {1}", appId, tenantId);
}
var subscriptions = details.subscriptions;
yield return string.Format("\tThere are {0} subscriptions", subscriptions.Length);
foreach (var subscription in subscriptions)
{
yield return string.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName);
}
yield return string.Empty;
continue;
}
var details = tenantCache[tenantId];
if (!String.IsNullOrEmpty(cacheItem.DisplayableId))
{
yield return string.Format("User: {0}, Tenant: {1} ({2})", cacheItem.DisplayableId, tenantId, details.domain);
}
else if (!String.IsNullOrEmpty(cacheItem.AppId))
{
yield return string.Format(String.IsNullOrEmpty(details.domain) ? "App: {0}, Tenant: {1}" : "App: {0}, Tenant: {1} ({2})", cacheItem.AppId, tenantId, details.domain);
}
else
{
throw new NotImplementedException();
}
var subscriptions = details.subscriptions;
yield return string.Format("\tThere are {0} subscriptions", subscriptions.Length);
foreach (var subscription in subscriptions)
{
yield return string.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName);
}
yield return string.Empty;
}
}
protected Task<AuthenticationResult> GetAuthorizationResult(Dictionary<TokenCacheKey, string> tokenCache, string tenantId, string user = null, string resource = Constants.CSMResource)
protected async Task<TokenCacheInfo> GetAuthorizationResultByRefreshToken(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
{
var tcs = new TaskCompletionSource<AuthenticationResult>();
var azureEnvironment = this.AzureEnvironments;
var authority = String.Format("{0}/{1}", Constants.AADLoginUrls[(int)azureEnvironment], cacheInfo.TenantId);
var context = new AuthenticationContext(
authority: authority,
validateAuthority: true,
tokenCache: tokenCache);
AuthenticationResult result = await context.AcquireTokenByRefreshTokenAsync(
refreshToken: cacheInfo.RefreshToken,
clientId: Constants.AADClientId,
resource: cacheInfo.Resource);
var ret = new TokenCacheInfo(cacheInfo.Resource, result);
ret.TenantId = cacheInfo.TenantId;
ret.DisplayableId = cacheInfo.DisplayableId;
tokenCache.Add(ret);
return ret;
}
protected Task<TokenCacheInfo> GetAuthorizationResult(CustomTokenCache tokenCache, string tenantId, string user = null, string resource = Constants.CSMResource)
{
var tcs = new TaskCompletionSource<TokenCacheInfo>();
TokenCacheInfo found;
if (tokenCache.TryGetValue(tenantId, resource, out found))
{
tcs.SetResult(found);
return tcs.Task;
}
var thread = new Thread(() =>
{
try
@ -291,7 +321,7 @@ namespace ARMClient.Authentication.AADAuthentication
var context = new AuthenticationContext(
authority: authority,
validateAuthority: true,
tokenCacheStore: tokenCache);
tokenCache: tokenCache);
AuthenticationResult result = null;
if (!string.IsNullOrEmpty(user))
@ -299,8 +329,7 @@ namespace ARMClient.Authentication.AADAuthentication
result = context.AcquireToken(
resource: resource,
clientId: Constants.AADClientId,
redirectUri: new Uri(Constants.AADRedirectUri),
userId: null);
redirectUri: new Uri(Constants.AADRedirectUri));
}
else
{
@ -311,7 +340,9 @@ namespace ARMClient.Authentication.AADAuthentication
promptBehavior: PromptBehavior.Always);
}
tcs.TrySetResult(result);
var cacheInfo = new TokenCacheInfo(resource, result);
tokenCache.Add(cacheInfo);
tcs.TrySetResult(cacheInfo);
}
catch (Exception ex)
{
@ -326,28 +357,43 @@ namespace ARMClient.Authentication.AADAuthentication
return tcs.Task;
}
protected AuthenticationResult GetAuthorizationResultByAppKey(Dictionary<TokenCacheKey, string> tokenCache, string tenantId, string appId, string appKey, string resource = Constants.CSMResource)
protected TokenCacheInfo GetAuthorizationResultBySpn(CustomTokenCache tokenCache, string tenantId, string appId, string appKey, string resource)
{
var azureEnvironment = this.AzureEnvironments;
var authority = String.Format("{0}/{1}", Constants.AADLoginUrls[(int)azureEnvironment], tenantId);
var context = new AuthenticationContext(
authority: authority,
validateAuthority: true,
tokenCacheStore: tokenCache);
tokenCache: tokenCache);
var credential = new ClientCredential(appId, appKey);
var authResult = context.AcquireToken(resource, credential);
var result = context.AcquireToken(resource, credential);
// this will only get us one token, we save AppId and AppKey info in TokenCacheKey
var key = tokenCache.Keys.First(k => String.Equals(k.Resource, resource, StringComparison.OrdinalIgnoreCase));
SaveApplicationInfo(key, tenantId, appId, appKey);
return authResult;
var cacheInfo = new TokenCacheInfo(tenantId, appId, appKey, resource, result);
tokenCache.Add(cacheInfo);
return cacheInfo;
}
protected async Task<Dictionary<string, TenantCacheInfo>> GetTokenForTenants(Dictionary<TokenCacheKey, string> tokenCache, AuthenticationResult authResult)
protected TokenCacheInfo GetAuthorizationResultByUpn(CustomTokenCache tokenCache, string tenantId, string username, string password, string resource)
{
var tenantIds = await GetTenantIds(authResult);
Trace.WriteLine(string.Format("User {0} belongs to {1} tenants", authResult.UserInfo.UserId, tenantIds.Length));
var azureEnvironment = this.AzureEnvironments;
var authority = String.Format("{0}/{1}", Constants.AADLoginUrls[(int)azureEnvironment], tenantId);
var context = new AuthenticationContext(
authority: authority,
validateAuthority: true,
tokenCache: tokenCache);
var credential = new UserCredential(username, password);
var result = context.AcquireToken(resource, Constants.AADClientId, credential);
var cacheInfo = new TokenCacheInfo(resource, result);
tokenCache.Add(cacheInfo);
return cacheInfo;
}
protected async Task<Dictionary<string, TenantCacheInfo>> GetTokenForTenants(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
{
var recentInfo = cacheInfo;
var tenantIds = await GetTenantIds(cacheInfo);
Utils.Trace.WriteLine(string.Format("User {0} belongs to {1} tenants", cacheInfo.DisplayableId, tenantIds.Length));
var tenantCache = this.TenantStorage.GetCache();
foreach (var tenantId in tenantIds)
@ -359,35 +405,35 @@ namespace ARMClient.Authentication.AADAuthentication
domain = "unknown"
};
AuthenticationResult result = null;
TokenCacheInfo result = null;
try
{
result = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: authResult.UserInfo.UserId);
result = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: cacheInfo.DisplayableId);
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("User: {0}, Tenant: {1} {2}", authResult.UserInfo.UserId, tenantId, ex.Message));
Trace.WriteLine(string.Empty);
Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1} {2}", cacheInfo.DisplayableId, tenantId, ex.Message));
Utils.Trace.WriteLine(string.Empty);
continue;
}
try
{
var aadToken = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: authResult.UserInfo.UserId, resource: Constants.AADGraphUrls[(int)AzureEnvironments]);
var aadToken = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: cacheInfo.DisplayableId, resource: Constants.AADGraphUrls[(int)AzureEnvironments]);
var details = await GetTenantDetail(aadToken, tenantId);
info.displayName = details.displayName;
info.domain = details.verifiedDomains.First(d => d.@default).name;
Trace.WriteLine(string.Format("User: {0}, Tenant: {1} ({2})", result.UserInfo.UserId, tenantId, details.verifiedDomains.First(d => d.@default).name));
Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1} ({2})", result.DisplayableId, tenantId, details.verifiedDomains.First(d => d.@default).name));
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("User: {0}, Tenant: {1} {2}", result.UserInfo.UserId, tenantId, ex.Message));
Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1} {2}", result.DisplayableId, tenantId, ex.Message));
}
try
{
var subscriptions = await GetSubscriptions(result);
Trace.WriteLine(string.Format("\tThere are {0} subscriptions", subscriptions.Length));
Utils.Trace.WriteLine(string.Format("\tThere are {0} subscriptions", subscriptions.Length));
info.subscriptions = subscriptions.Select(subscription => new SubscriptionCacheInfo
{
@ -397,30 +443,32 @@ namespace ARMClient.Authentication.AADAuthentication
if (info.subscriptions.Length > 0)
{
this.TokenStorage.SaveRecentToken(result);
recentInfo = result;
}
foreach (var subscription in subscriptions)
{
Trace.WriteLine(string.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
Utils.Trace.WriteLine(string.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
}
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("\t{0}!", ex.Message));
Utils.Trace.WriteLine(string.Format("\t{0}!", ex.Message));
}
tenantCache[tenantId] = info;
Trace.WriteLine(string.Empty);
Utils.Trace.WriteLine(string.Empty);
}
this.TokenStorage.SaveRecentToken(recentInfo, Constants.CSMResource);
return tenantCache;
}
private async Task<string[]> GetTenantIds(AuthenticationResult authResult)
private async Task<string[]> GetTenantIds(TokenCacheInfo cacheInfo)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", authResult.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
var azureEnvironment = this.AzureEnvironments;
@ -438,7 +486,7 @@ namespace ARMClient.Authentication.AADAuthentication
}
}
private async Task<TenantDetails> GetTenantDetail(AuthenticationResult authResult, string tenantId)
private async Task<TenantDetails> GetTenantDetail(TokenCacheInfo cacheInfo, string tenantId)
{
if (Constants.InfrastructureTenantIds.Contains(tenantId))
{
@ -459,7 +507,7 @@ namespace ARMClient.Authentication.AADAuthentication
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", authResult.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
var azureEnvironment = this.AzureEnvironments;
@ -487,11 +535,11 @@ namespace ARMClient.Authentication.AADAuthentication
}
}
private async Task<SubscriptionInfo[]> GetSubscriptions(AuthenticationResult authResult)
private async Task<SubscriptionInfo[]> GetSubscriptions(TokenCacheInfo cacheInfo)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", authResult.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
var azureEnvironment = this.AzureEnvironments;

Просмотреть файл

@ -30,11 +30,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms, Version=2.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@ -67,6 +69,8 @@
<Compile Include="Contracts\TenantCacheInfo.cs" />
<Compile Include="Contracts\TenantDetails.cs" />
<Compile Include="Contracts\TenantInfo.cs" />
<Compile Include="Contracts\CustomTokenCache.cs" />
<Compile Include="Contracts\TokenCacheInfo.cs" />
<Compile Include="Contracts\VerifiedDomain.cs" />
<Compile Include="EnvironmentStorage\FileEnvironmentStorage.cs" />
<Compile Include="EnvironmentStorage\IEnvironmentStorage.cs" />
@ -80,6 +84,7 @@
<Compile Include="TokenStorage\ITokenStorage.cs" />
<Compile Include="TokenStorage\MemoryTokenStorage.cs" />
<Compile Include="Utilities\ProtectedFile.cs" />
<Compile Include="Utilities\Utils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

Просмотреть файл

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ARMClient.Authentication.Contracts
{
public class CustomTokenCache : TokenCache
{
private Dictionary<string, TokenCacheInfo> _caches;
public CustomTokenCache(string state = null)
{
if (state == null)
{
_caches = new Dictionary<string, TokenCacheInfo>();
}
else
{
_caches = JsonConvert.DeserializeObject<Dictionary<string, TokenCacheInfo>>(state);
}
}
public IEnumerable<TokenCacheInfo> GetValues(string resource)
{
return _caches.Values.Where(c => c.Resource == resource);
}
public string GetState()
{
return JObject.FromObject(_caches).ToString();
}
public bool TryGetValue(string tenantId, string resource, out TokenCacheInfo cacheInfo)
{
return _caches.TryGetValue(GetKey(tenantId, resource), out cacheInfo);
}
public TokenCacheInfo Get(string tenantId, string resource)
{
return _caches[GetKey(tenantId, resource)];
}
public void Add(TokenCacheInfo cacheInfo)
{
_caches[GetKey(cacheInfo.TenantId, cacheInfo.Resource)] = cacheInfo;
}
private string GetKey(string tenantId, string resource)
{
return String.Format("{0}::{1}", tenantId, resource);
}
}
}

Просмотреть файл

@ -0,0 +1,44 @@
using System;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace ARMClient.Authentication.Contracts
{
public class TokenCacheInfo
{
public TokenCacheInfo()
{
}
public TokenCacheInfo(string tenantId, string appId, string appKey, string resource, AuthenticationResult result)
: this(resource, result)
{
AppId = appId;
AppKey = appKey;
TenantId = tenantId;
}
public TokenCacheInfo(string resource, AuthenticationResult result)
{
AccessToken = result.AccessToken;
DisplayableId = result.UserInfo == null ? null : result.UserInfo.DisplayableId;
ExpiresOn = result.ExpiresOn;
RefreshToken = result.RefreshToken;
Resource = resource;
TenantId = result.TenantId;
}
public string AppId { get; set; }
public string AppKey { get; set; }
public string AccessToken { get; set; }
public string DisplayableId { get; set; }
public DateTimeOffset ExpiresOn { get; set; }
public string RefreshToken { get; set; }
public string Resource { get; set; }
public string TenantId { get; set; }
public string CreateAuthorizationHeader()
{
return String.Format("Bearer {0}", AccessToken);
}
}
}

Просмотреть файл

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ARMClient.Authentication.Contracts;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace ARMClient.Authentication
{
@ -9,11 +9,9 @@ namespace ARMClient.Authentication
{
AzureEnvironments AzureEnvironments { get; set; }
Task AcquireTokens();
Task<AuthenticationResult> GetTokenByTenant(string tenantId);
Task<AuthenticationResult> GetTokenBySubscription(string subscriptionId);
Task<AuthenticationResult> GetTokenBySpn(string tenantId, string appId, string appKey);
Task<AuthenticationResult> GetRecentToken();
Task<string> GetAuthorizationHeader(string subscriptionId);
Task<TokenCacheInfo> GetToken(string id, string resource);
Task<TokenCacheInfo> GetTokenBySpn(string tenantId, string appId, string appKey);
Task<TokenCacheInfo> GetTokenByUpn(string tenantId, string username, string password);
bool IsCacheValid();
void ClearTokenCache();
IEnumerable<string> DumpTokenCache();

Просмотреть файл

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ARMClient.Authentication.Contracts;
using ARMClient.Authentication.Utilities;
@ -32,14 +31,13 @@ namespace ARMClient.Authentication.TenantStorage
public bool IsCacheValid()
{
var cache = GetCache();
return cache != null && cache.Count > 0;
var file = ProtectedFile.GetCacheFile(_fileName);
return File.Exists(file);
}
public void ClearCache()
{
var filePath = ProtectedFile.GetCacheFile(_fileName);
if (File.Exists(filePath))
foreach (var filePath in Directory.GetFiles(Path.GetDirectoryName(ProtectedFile.GetCacheFile(_fileName)), "cache_tenants*", SearchOption.TopDirectoryOnly))
{
File.Delete(filePath);
}

Просмотреть файл

@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using ARMClient.Authentication.Contracts;
using ARMClient.Authentication.Utilities;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -13,47 +10,54 @@ namespace ARMClient.Authentication.TokenStorage
internal class FileTokenStorage : ITokenStorage
{
private const string _cacheFileName = "cache_tokens.dat";
private const string _recentFileName = "recent_token.dat";
private const string _recentARMFileName = "recent_token_arm.dat";
private const string _recentAADFileName = "recent_token_aad.dat";
public Dictionary<TokenCacheKey, string> GetCache()
public CustomTokenCache GetCache()
{
var file = ProtectedFile.GetCacheFile(_cacheFileName);
if (!File.Exists(file))
{
return new Dictionary<TokenCacheKey, string>();
return new CustomTokenCache();
}
var dict = JsonConvert.DeserializeObject<Dictionary<string, TokenCacheKey>>(ProtectedFile.ReadAllText(file));
return dict.ToDictionary(p => p.Value, p => p.Key);
var state = ProtectedFile.ReadAllText(file);
return new CustomTokenCache(state);
}
public void SaveCache(Dictionary<TokenCacheKey, string> tokens)
public void SaveCache(CustomTokenCache cache)
{
var dict = tokens.ToDictionary(p => p.Value, p => p.Key);
var json = JObject.FromObject(dict);
ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(_cacheFileName), json.ToString());
var state = cache.GetState();
ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(_cacheFileName), state);
}
public AuthenticationResult GetRecentToken()
public TokenCacheInfo GetRecentToken(string resource)
{
return AuthenticationResult.Deserialize(ProtectedFile.ReadAllText(ProtectedFile.GetCacheFile(_recentFileName)));
var file = ProtectedFile.GetCacheFile(resource == Constants.CSMResource ? _recentARMFileName : _recentAADFileName);
if (!File.Exists(file))
{
return null;
}
return JsonConvert.DeserializeObject<TokenCacheInfo>(ProtectedFile.ReadAllText(file));
}
public void SaveRecentToken(AuthenticationResult authResult)
public void SaveRecentToken(TokenCacheInfo cacheInfo, string resource)
{
ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(_recentFileName), authResult.Serialize());
var file = ProtectedFile.GetCacheFile(resource == Constants.CSMResource ? _recentARMFileName : _recentAADFileName);
var json = JObject.FromObject(cacheInfo);
ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(file), json.ToString());
}
public bool IsCacheValid()
{
var cache = GetCache();
return cache != null && cache.Count > 0;
var file = ProtectedFile.GetCacheFile(_cacheFileName);
return File.Exists(file);
}
public void ClearCache()
{
var filePaths = new[] { ProtectedFile.GetCacheFile(_cacheFileName), ProtectedFile.GetCacheFile(_recentFileName) };
foreach (var filePath in filePaths.Where(File.Exists))
foreach (var filePath in Directory.GetFiles(ProtectedFile.GetCachePath(), "*token*", SearchOption.TopDirectoryOnly))
{
File.Delete(filePath);
}

Просмотреть файл

@ -1,14 +1,17 @@
using System.Collections.Generic;
using ARMClient.Authentication.Contracts;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace ARMClient.Authentication.TokenStorage
{
public interface ITokenStorage
{
Dictionary<TokenCacheKey, string> GetCache();
void SaveCache(Dictionary<TokenCacheKey, string> tokens);
AuthenticationResult GetRecentToken();
void SaveRecentToken(AuthenticationResult authResult);
CustomTokenCache GetCache();
void SaveCache(CustomTokenCache tokenCache);
TokenCacheInfo GetRecentToken(string resource);
void SaveRecentToken(TokenCacheInfo cacheInfo, string resource);
bool IsCacheValid();
void ClearCache();
}

Просмотреть файл

@ -1,31 +1,32 @@
using System;
using System.Collections.Generic;
using ARMClient.Authentication.Contracts;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace ARMClient.Authentication.TokenStorage
{
internal class MemoryTokenStorage : ITokenStorage
{
private Dictionary<TokenCacheKey, string> _cache;
private AuthenticationResult _recentToken;
public Dictionary<TokenCacheKey, string> GetCache()
private CustomTokenCache _cache;
private TokenCacheInfo _recentToken;
public CustomTokenCache GetCache()
{
return this._cache ?? new Dictionary<TokenCacheKey, string>();
return this._cache ?? new CustomTokenCache();
}
public void SaveCache(Dictionary<TokenCacheKey, string> cache)
public void SaveCache(CustomTokenCache cache)
{
this._cache = cache;
}
public AuthenticationResult GetRecentToken()
public TokenCacheInfo GetRecentToken(string resource)
{
return this._recentToken;
}
public void SaveRecentToken(AuthenticationResult authResult)
public void SaveRecentToken(TokenCacheInfo cacheInfo, string resource)
{
this._recentToken = authResult;
this._recentToken = cacheInfo;
}
public bool IsCacheValid()

Просмотреть файл

@ -7,9 +7,14 @@ namespace ARMClient.Authentication.Utilities
{
internal static class ProtectedFile
{
public static string GetCachePath()
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".arm");
}
public static string GetCacheFile(string file)
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".arm");
var path = GetCachePath();
Directory.CreateDirectory(path);
return Path.Combine(path, file);
}

Просмотреть файл

@ -0,0 +1,35 @@
using System;
using System.Diagnostics;
namespace ARMClient.Authentication.Utilities
{
public static class Utils
{
static TraceListener _traceListener;
public static TraceListener Trace
{
get { return _traceListener ?? DefaultTraceListener.Default; }
}
public static void SetTraceListener(TraceListener listener)
{
_traceListener = listener;
}
class DefaultTraceListener : TraceListener
{
public readonly static TraceListener Default = new DefaultTraceListener();
public override void Write(string message)
{
System.Diagnostics.Trace.Write(message);
}
public override void WriteLine(string message)
{
System.Diagnostics.Trace.WriteLine(message);
}
}
}
}

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="1.0.5" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.14.201151115" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
</packages>

Просмотреть файл

@ -33,11 +33,12 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>

Просмотреть файл

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ARMClient
{

Просмотреть файл

@ -35,6 +35,9 @@ namespace ARMClient
{
Console.ForegroundColor = headerNameColor;
Console.WriteLine("{0} {1} HTTP/{2}", request.Method, request.RequestUri.PathAndQuery, request.Version);
Console.Write("Host: ");
Console.ForegroundColor = headerValueColor;
Console.WriteLine(request.RequestUri.Host);
}
finally
{

Просмотреть файл

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@ -11,7 +10,7 @@ using System.Windows.Forms;
using ARMClient.Authentication;
using ARMClient.Authentication.AADAuthentication;
using ARMClient.Authentication.Contracts;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using ARMClient.Authentication.Utilities;
using Newtonsoft.Json.Linq;
namespace ARMClient
@ -21,7 +20,7 @@ namespace ARMClient
[STAThread]
static int Main(string[] args)
{
Trace.Listeners.Add(new ConsoleTraceListener());
Utils.SetTraceListener(new ConsoleTraceListener());
try
{
var persistentAuthHelper = new PersistentAuthHelper();
@ -65,20 +64,15 @@ namespace ARMClient
EnsureTokenCache(persistentAuthHelper);
AuthenticationResult authResult;
if (tenantId != null)
{
EnsureGuidFormat(tenantId);
authResult = persistentAuthHelper.GetTokenByTenant(tenantId).Result;
}
else
{
authResult = persistentAuthHelper.GetRecentToken().Result;
}
var bearer = authResult.CreateAuthorizationHeader();
TokenCacheInfo cacheInfo = persistentAuthHelper.GetToken(tenantId, Constants.CSMResource).Result;
var bearer = cacheInfo.CreateAuthorizationHeader();
Clipboard.SetText(bearer);
DumpClaims(authResult.AccessToken);
DumpClaims(cacheInfo.AccessToken);
Console.WriteLine();
Console.WriteLine("Token copied to clipboard successfully.");
return 0;
@ -91,13 +85,33 @@ namespace ARMClient
var appId = _parameters.Get(2, keyName: "appId");
EnsureGuidFormat(appId);
var appKey = _parameters.Get(3, keyName: "appKey");
var env = _parameters.Get(1, requires: false);
var appKey = _parameters.Get(3, keyName: "appKey", requires: false);
if (appKey == null)
{
appKey = PromptForPassword("appKey");
}
_parameters.ThrowIfUnknown();
persistentAuthHelper.AzureEnvironments = env == null ? AzureEnvironments.Prod :
(AzureEnvironments)Enum.Parse(typeof(AzureEnvironments), args[1], ignoreCase: true);
var authResult = persistentAuthHelper.GetTokenBySpn(tenantId, appId, appKey).Result;
persistentAuthHelper.AzureEnvironments = AzureEnvironments.Prod;
var cacheInfo = persistentAuthHelper.GetTokenBySpn(tenantId, appId, appKey).Result;
return 0;
}
else if (String.Equals(verb, "upn", StringComparison.OrdinalIgnoreCase))
{
var tenantId = _parameters.Get(1, keyName: "tenant");
EnsureGuidFormat(tenantId);
var username = _parameters.Get(2, keyName: "username");
var password = _parameters.Get(3, keyName: "password", requires: false);
if (password == null)
{
password = PromptForPassword("password");
}
_parameters.ThrowIfUnknown();
persistentAuthHelper.AzureEnvironments = AzureEnvironments.Prod;
var cacheInfo = persistentAuthHelper.GetTokenByUpn(tenantId, username, password).Result;
return 0;
}
else if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase)
@ -107,38 +121,24 @@ namespace ARMClient
{
var path = _parameters.Get(1, keyName: "url");
var verbose = _parameters.Get("-verbose", requires: false) != null;
var baseUri = new Uri(ARMClient.Authentication.Constants.CSMUrls[(int)AzureEnvironments.Prod]);
var uri = new Uri(baseUri, path);
if (!verbose)
{
Trace.Listeners.Clear();
}
var uri = EnsureAbsoluteUri(path, persistentAuthHelper);
if (!persistentAuthHelper.IsCacheValid())
{
persistentAuthHelper.AzureEnvironments = GetAzureEnvironments(uri);
persistentAuthHelper.AcquireTokens().Wait();
}
var env = persistentAuthHelper.AzureEnvironments;
baseUri = new Uri(ARMClient.Authentication.Constants.CSMUrls[(int)env]);
uri = new Uri(baseUri, path);
var content = ParseHttpContent(verb, _parameters);
_parameters.ThrowIfUnknown();
var subscriptionId = GetSubscription(uri);
AuthenticationResult authResult;
if (String.IsNullOrEmpty(subscriptionId))
{
authResult = persistentAuthHelper.GetRecentToken().Result;
}
else
{
authResult = persistentAuthHelper.GetTokenBySubscription(subscriptionId).Result;
}
return HttpInvoke(uri, authResult, verb, verbose, content).Result;
var subscriptionId = GetTenantOrSubscription(uri);
TokenCacheInfo cacheInfo = persistentAuthHelper.GetToken(subscriptionId, null).Result;
return HttpInvoke(uri, cacheInfo, verb, verbose, content).Result;
}
else
{
@ -156,6 +156,68 @@ namespace ARMClient
}
}
static string PromptForPassword(string title)
{
string pass = "";
Console.Write("Enter {0}: ", title);
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
// Backspace Should Not Work
if (key.Key != ConsoleKey.Backspace)
{
pass += key.KeyChar;
Console.Write("*");
}
else
{
pass = pass.Remove(pass.Length - 1);
Console.Write("\b \b");
}
}
// Stops Receving Keys Once Enter is Pressed
while (key.Key != ConsoleKey.Enter);
pass = pass.Remove(pass.Length - 1);
Console.Write("\b \b");
Console.WriteLine("--" + pass + "--");
return pass;
}
static Uri EnsureAbsoluteUri(string path, PersistentAuthHelper persistentAuthHelper)
{
Uri ret;
if (Uri.TryCreate(path, UriKind.Absolute, out ret))
{
return ret;
}
var env = persistentAuthHelper.IsCacheValid() ? persistentAuthHelper.AzureEnvironments : AzureEnvironments.Prod;
var parts = path.Split(new[] { '/', '?' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length <= 0
|| String.Equals(parts[0], "tenants", StringComparison.OrdinalIgnoreCase)
|| String.Equals(parts[0], "subscriptions", StringComparison.OrdinalIgnoreCase)
|| String.Equals(parts[0], "providers", StringComparison.OrdinalIgnoreCase))
{
return new Uri(new Uri(ARMClient.Authentication.Constants.CSMUrls[(int)env]), path);
}
Guid guid;
if (Guid.TryParse(parts[0], out guid))
{
if (path.Length > 1 && String.Equals(parts[1], "services", StringComparison.OrdinalIgnoreCase))
{
return new Uri(new Uri(ARMClient.Authentication.Constants.RdfeUrls[(int)env]), path);
}
}
return new Uri(new Uri(ARMClient.Authentication.Constants.AADGraphUrls[(int)env]), path);
}
static void EnsureGuidFormat(string parameter)
{
Guid result;
@ -223,7 +285,11 @@ namespace ARMClient
Console.WriteLine();
Console.WriteLine("Get token by ServicePrincipalName");
Console.WriteLine(" ARMClient.exe spn [tenant] [appId] [appKey]");
Console.WriteLine(" ARMClient.exe spn [tenant] [appId] (appKey)");
Console.WriteLine();
Console.WriteLine("Get token by ServicePrincipalName");
Console.WriteLine(" ARMClient.exe upn [tenant] [username] (password)");
Console.WriteLine();
Console.WriteLine("List token cache");
@ -263,11 +329,11 @@ namespace ARMClient
return null;
}
static async Task<int> HttpInvoke(Uri uri, AuthenticationResult authResult, string verb, bool verbose, HttpContent content)
static async Task<int> HttpInvoke(Uri uri, TokenCacheInfo cacheInfo, string verb, bool verbose, HttpContent content)
{
using (var client = new HttpClient(new HttpLoggingHandler(new HttpClientHandler(), verbose)))
{
client.DefaultRequestHeaders.Add("Authorization", authResult.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
@ -276,6 +342,8 @@ namespace ARMClient
client.DefaultRequestHeaders.Add("x-ms-version", "2013-10-01");
}
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
HttpResponseMessage response = null;
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))
{
@ -374,17 +442,17 @@ namespace ARMClient
return Constants.AADGraphUrls.Any(url => url.IndexOf(host, StringComparison.OrdinalIgnoreCase) > 0);
}
static string GetSubscription(Uri uri)
static string GetTenantOrSubscription(Uri uri)
{
try
{
var paths = uri.AbsolutePath.Split(new[] { '/', '?' }, StringSplitOptions.RemoveEmptyEntries);
if (IsGraphApi(uri))
{
return null;
return Guid.Parse(paths[0]).ToString();
}
var paths = uri.AbsolutePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if (paths.Length >= 2 && paths[0] == "subscriptions")
if (paths.Length >= 2 && String.Equals(paths[0], "subscriptions", StringComparison.OrdinalIgnoreCase))
{
return Guid.Parse(paths[1]).ToString();
}

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="1.0.5" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.14.201151115" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
</packages>

Просмотреть файл

@ -33,12 +33,13 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms">
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.1.0.5\lib\net40\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms, Version=2.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="1.0.5" targetFramework="net451" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.14.201151115" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
</packages>

Просмотреть файл

@ -17,7 +17,7 @@ namespace ARMClient.Library
{
public class ARMClient : DynamicObject
{
private string _url = "https://management.azure.com";
private string _url = null;
private string _authorizationHeader;
private readonly string _apiVersion;
private readonly IAuthHelper _authHelper;
@ -29,24 +29,19 @@ namespace ARMClient.Library
return new ARMClient(apiVersion, authHelper, azureEnvironment, url);
}
public static dynamic GetDynamicClient(string apiVersion, string authorizationHeader, string url = null)
{
return new ARMClient(apiVersion, authorizationHeader, url);
}
private ARMClient(string apiVersion, IAuthHelper authHelper = null,
AzureEnvironments azureEnvironment = AzureEnvironments.Prod, string url = null)
{
this._apiVersion = apiVersion;
this._authHelper = authHelper ?? new AuthHelper(azureEnvironment);
this._azureEnvironment = azureEnvironment;
this._url = url ?? "https://management.azure.com";
this._url = url ?? Constants.CSMUrls[(int)azureEnvironment];
}
private ARMClient(string apiVersion, string authorizationHeader, string url = null)
private ARMClient(string apiVersion, string authorizationHeader, string url)
{
this._authorizationHeader = authorizationHeader;
this._url = url ?? "https://management.azure.com";
this._url = url;
}
public async Task InitializeToken(string subscriptionId = null)
@ -62,7 +57,8 @@ namespace ARMClient.Library
await this._authHelper.AcquireTokens().ConfigureAwait(false);
}
this._authorizationHeader = await this._authHelper.GetAuthorizationHeader(subscriptionId).ConfigureAwait(false);
TokenCacheInfo cacheInfo = await this._authHelper.GetToken(subscriptionId, Constants.CSMResource).ConfigureAwait(false);
this._authorizationHeader = cacheInfo.CreateAuthorizationHeader();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
@ -157,8 +153,8 @@ namespace ARMClient.Library
private Task<HttpResponseMessage> HttpInvoke(string httpVerb, object[] args)
{
this._url = string.Format("{0}?api-version={1}", this._url, this._apiVersion);
return HttpInvoke(new Uri(this._url), httpVerb, args.Length > 0 ? args[0].ToString() : string.Empty);
var uri = string.Format("{0}?api-version={1}", this._url, this._apiVersion);
return HttpInvoke(new Uri(uri), httpVerb, args.Length > 0 ? args[0].ToString() : string.Empty);
}
private async Task<HttpResponseMessage> HttpInvoke(Uri uri, string verb, string payload)
@ -168,6 +164,7 @@ namespace ARMClient.Library
client.DefaultRequestHeaders.Add("Authorization", this._authorizationHeader);
client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);
client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());
HttpResponseMessage response = null;
if (String.Equals(verb, "get", StringComparison.OrdinalIgnoreCase))