예제 #1
0
 public void SaveRecentToken(TokenCacheInfo cacheInfo, string resource)
 {
     var file = ProtectedFile.GetCacheFile(GetRecentTokenFileName(resource));
     var json = JObject.FromObject(cacheInfo);
     ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(file), json.ToString());
 }
예제 #2
0
 public bool TryGetValue(string tenantId, string resource, out TokenCacheInfo cacheInfo)
 {
     return _caches.TryGetValue(GetKey(tenantId, resource), out cacheInfo);
 }
예제 #3
0
        private async Task<TenantDetails> GetTenantDetail(TokenCacheInfo cacheInfo, string tenantId)
        {
            if (Constants.InfrastructureTenantIds.Contains(tenantId))
            {
                return new TenantDetails
                {
                    objectId = tenantId,
                    displayName = "Infrastructure",
                    verifiedDomains = new[]
                    {
                        new VerifiedDomain
                        {
                            name = "live.com",
                            @default = true
                        }
                    }
                };
            }

            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
                client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);

                var azureEnvironment = this.AzureEnvironments;
                var url = string.Format("{0}/{1}/tenantDetails?api-version={2}", Constants.AADGraphUrls[(int)azureEnvironment], tenantId, Constants.AADGraphApiVersion);
                using (var response = await client.GetAsync(url))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        var result = await response.Content.ReadAsAsync<ResultOf<TenantDetails>>();
                        return result.value[0];
                    }

                    var content = await response.Content.ReadAsStringAsync();
                    if (content.StartsWith("{"))
                    {
                        var error = (JObject)JObject.Parse(content)["odata.error"];
                        if (error != null)
                        {
                            throw new InvalidOperationException(String.Format("GetTenantDetail {0}, {1}", response.StatusCode, error["message"].Value<string>("value")));
                        }
                    }

                    throw new InvalidOperationException(String.Format("GetTenantDetail {0}, {1}", response.StatusCode, await response.Content.ReadAsStringAsync()));
                }
            }
        }
예제 #4
0
        private async Task<SubscriptionInfo[]> GetSubscriptions(TokenCacheInfo cacheInfo)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
                client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);

                var azureEnvironment = this.AzureEnvironments;
                var url = string.Format("{0}/subscriptions?api-version={1}", Constants.CSMUrls[(int)azureEnvironment], Constants.CSMApiVersion);
                using (var response = await client.GetAsync(url))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        var result = await response.Content.ReadAsAsync<ResultOf<SubscriptionInfo>>();
                        return result.value;
                    }

                    var content = await response.Content.ReadAsStringAsync();
                    if (content.StartsWith("{"))
                    {
                        var error = (JObject)JObject.Parse(content)["error"];
                        if (error != null)
                        {
                            throw new InvalidOperationException(String.Format("GetSubscriptions {0}, {1}", response.StatusCode, error.Value<string>("message")));
                        }
                    }

                    throw new InvalidOperationException(String.Format("GetSubscriptions {0}, {1}", response.StatusCode, await response.Content.ReadAsStringAsync()));
                }
            }
        }
예제 #5
0
        protected async Task<Dictionary<string, TenantCacheInfo>> GetTokenForTenants(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo,
            string appId = null, string appKey = null, string username = null, string password = null)
        {
            var recentInfo = cacheInfo;
            var tenantIds = await GetTenantIds(cacheInfo);
            if (!tenantIds.Contains(cacheInfo.TenantId))
            {
                var list = tenantIds.ToList();
                list.Insert(0, cacheInfo.TenantId);
                tenantIds = list.ToArray();
            }

            var tenantCache = this.TenantStorage.GetCache();
            foreach (var tenantId in tenantIds)
            {
                var info = new TenantCacheInfo
                {
                    tenantId = tenantId,
                    displayName = "unknown",
                    domain = (tenantIds.Length == 1 || tenantId != cacheInfo.TenantId) ?  cacheInfo.TenantId : "unknown"
                };

                TokenCacheInfo result = null;
                try
                {
                    if (!String.IsNullOrEmpty(appId) && !String.IsNullOrEmpty(appKey))
                    {
                        result = GetAuthorizationResultBySpn(tokenCache, tenantId: tenantId, appId: appId, appKey: appKey, resource: Constants.CSMResources[(int)AzureEnvironments]);
                    }
                    else if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password))
                    {
                        result = GetAuthorizationResultByUpn(tokenCache, tenantId: tenantId, username: username, password: password, resource: Constants.CSMResources[(int)AzureEnvironments]);
                    }
                    else
                    {
                        result = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: cacheInfo.DisplayableId);
                    }
                }
                catch (Exception ex)
                {
                    Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1} {2}", cacheInfo.DisplayableId, tenantId, ex.Message));
                    Utils.Trace.WriteLine(string.Empty);
                    continue;
                }

                try
                {
                    TokenCacheInfo aadToken = null;
                    if (!String.IsNullOrEmpty(appId) && appKey == "_certificate_")
                    {
                        Utils.Trace.WriteLine(string.Format("AppId: {0}, Tenant: {1}", appId, tenantId));
                    }
                    else if (!String.IsNullOrEmpty(appId) && !String.IsNullOrEmpty(appKey))
                    {
                        aadToken = GetAuthorizationResultBySpn(tokenCache, tenantId: tenantId, appId: appId, appKey: appKey, resource: Constants.AADGraphUrls[(int)AzureEnvironments]);
                    }
                    else if (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password))
                    {
                        aadToken = GetAuthorizationResultByUpn(tokenCache, tenantId: tenantId, username: username, password: password, resource: Constants.AADGraphUrls[(int)AzureEnvironments]);
                    }
                    else
                    {
                        aadToken = await GetAuthorizationResult(tokenCache, tenantId: tenantId, user: cacheInfo.DisplayableId, resource: Constants.AADGraphUrls[(int)AzureEnvironments]);
                    }

                    if (aadToken != null)
                    {
                        var details = await GetTenantDetail(aadToken, tenantId);
                        info.displayName = details.displayName;
                        info.domain = details.verifiedDomains.First(d => d.@default).name;

                        if (!String.IsNullOrEmpty(appId) && !String.IsNullOrEmpty(appKey))
                        {
                            Utils.Trace.WriteLine(string.Format("AppId: {0}, Tenant: {1} ({2})", appId, tenantId, info.domain));
                        }
                        else
                        {
                            Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1} ({2})", result.DisplayableId, tenantId, info.domain));
                        }
                    }
                }
                catch (Exception)
                {
                    if (!String.IsNullOrEmpty(appId) && !String.IsNullOrEmpty(appKey))
                    {
                        Utils.Trace.WriteLine(string.Format("AppId: {0}, Tenant: {1}", appId, tenantId));
                    }
                    else
                    {
                        Utils.Trace.WriteLine(string.Format("User: {0}, Tenant: {1}", result.DisplayableId, tenantId));
                    }
                }

                try
                {
                    var subscriptions = await GetSubscriptions(result);
                    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();

                    if (recentInfo != null && info.subscriptions.Length > 0)
                    {
                        recentInfo = result;
                    }

                    foreach (var subscription in subscriptions)
                    {
                        Utils.Trace.WriteLine(string.Format("\tSubscription {0} ({1})", subscription.subscriptionId, subscription.displayName));
                    }
                }
                catch (Exception ex)
                {
                    Utils.Trace.WriteLine(string.Format("\t{0}!", ex.Message));
                }

                tenantCache[tenantId] = info;
                if (!String.IsNullOrEmpty(info.domain) && info.domain != "unknown")
                {
                    tenantCache[info.domain] = info;
                }

                Utils.Trace.WriteLine(string.Empty);
            }

            this.TokenStorage.SaveRecentToken(recentInfo, Constants.CSMResources[(int)AzureEnvironments]);

            return tenantCache;
        }
예제 #6
0
 public bool TryGetValue(string tenantId, string resource, out TokenCacheInfo cacheInfo)
 {
     return(_caches.TryGetValue(GetKey(tenantId, resource), out cacheInfo));
 }
예제 #7
0
        protected TokenCacheInfo GetAuthorizationResultBySpn(CustomTokenCache tokenCache, string tenantId, string appId, X509Certificate2 certificate, string resource)
        {
            TokenCacheInfo found;
            if (tokenCache.TryGetValue(tenantId, resource, out found))
            {
                return found;
            }

            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 ClientAssertionCertificate(appId, certificate);
            var result = context.AcquireToken(resource, credential);

            var cacheInfo = new TokenCacheInfo(tenantId, appId, "_certificate_", resource, result);
            tokenCache.Add(cacheInfo);
            return cacheInfo;
        }
예제 #8
0
        public static async Task<JObject> HttpGet(Uri uri, TokenCacheInfo cacheInfo)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
                client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
                client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);

                if (Utils.IsRdfe(uri))
                {
                    client.DefaultRequestHeaders.Add("x-ms-version", "2013-10-01");
                }

                client.DefaultRequestHeaders.Add("x-ms-request-id", Guid.NewGuid().ToString());

                using (var response = await client.GetAsync(uri))
                {
                    var content = await response.Content.ReadAsStringAsync();
                    if (!response.IsSuccessStatusCode)
                    {
                        Trace.WriteLine("Status:  " + response.StatusCode);
                        Trace.WriteLine("Content: " + content);
                    }

                    response.EnsureSuccessStatusCode();
                    return JObject.Parse(content);
                }
            }
        }
예제 #9
0
        protected async Task<TokenCacheInfo> GetAuthorizationResultByRefreshToken(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
        {
            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;
        }
예제 #10
0
        protected Task<TokenCacheInfo> GetAuthorizationResult(CustomTokenCache tokenCache, string tenantId, string user = null, string resource = null)
        {
            var tcs = new TaskCompletionSource<TokenCacheInfo>();

            resource = resource ?? Constants.CSMResources[(int)AzureEnvironments];

            TokenCacheInfo found;
            if (tokenCache.TryGetValue(tenantId, resource, out found))
            {
                tcs.SetResult(found);
                return tcs.Task;
            }

            var thread = new Thread(() =>
            {
                try
                {
                    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);

                    AuthenticationResult result = null;
                    if (!string.IsNullOrEmpty(user))
                    {
                        result = context.AcquireToken(
                            resource: resource,
                            clientId: Constants.AADClientId,
                            redirectUri: new Uri(Constants.AADRedirectUri),
                            promptBehavior: PromptBehavior.Never,
                            userId: new UserIdentifier(user, UserIdentifierType.OptionalDisplayableId));
                    }
                    else
                    {
                        result = context.AcquireToken(
                            resource: resource,
                            clientId: Constants.AADClientId,
                            redirectUri: new Uri(Constants.AADRedirectUri),
                            promptBehavior: PromptBehavior.Always);
                    }

                    var cacheInfo = new TokenCacheInfo(resource, result);
                    tokenCache.Add(cacheInfo);
                    tcs.TrySetResult(cacheInfo);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            });

            thread.SetApartmentState(ApartmentState.STA);
            thread.Name = "AcquireTokenThread";
            thread.Start();

            return tcs.Task;
        }
예제 #11
0
        protected async Task<TokenCacheInfo> RefreshToken(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
        {
            if (!String.IsNullOrEmpty(cacheInfo.RefreshToken))
            {
                try
                {
                    return await GetAuthorizationResultByRefreshToken(tokenCache, cacheInfo);
                }
                catch (AdalServiceException ex)
                {
                    if (ex.Message.IndexOf("The provided access grant is expired or revoked") > 0)
                    {
                        AcquireTokens().Wait();
                        cacheInfo = GetToken(cacheInfo.TenantId).Result;
                        tokenCache.Clone(this.TokenStorage.GetCache());
                        return cacheInfo;
                    }

                    throw;
                }
            }
            else if (!String.IsNullOrEmpty(cacheInfo.AppId) && cacheInfo.AppKey == "_certificate_")
            {
                throw new InvalidOperationException("Unable to refresh expired token!  Try login with certificate again.");
            }
            else if (!String.IsNullOrEmpty(cacheInfo.AppId) && !String.IsNullOrEmpty(cacheInfo.AppKey))
            {
                return GetAuthorizationResultBySpn(tokenCache, cacheInfo.TenantId, cacheInfo.AppId, cacheInfo.AppKey, cacheInfo.Resource);
            }

            throw new NotImplementedException();
        }
예제 #12
0
        protected async Task<TokenCacheInfo> RefreshToken(CustomTokenCache tokenCache, TokenCacheInfo cacheInfo)
        {
            if (!String.IsNullOrEmpty(cacheInfo.RefreshToken))
            {
                return await GetAuthorizationResultByRefreshToken(tokenCache, cacheInfo);
            }
            else if (!String.IsNullOrEmpty(cacheInfo.AppId) && cacheInfo.AppKey == "_certificate_")
            {
                throw new InvalidOperationException("Unable to refresh expired token!  Try login with certificate again.");
            }
            else if (!String.IsNullOrEmpty(cacheInfo.AppId) && !String.IsNullOrEmpty(cacheInfo.AppKey))
            {
                return GetAuthorizationResultBySpn(tokenCache, cacheInfo.TenantId, cacheInfo.AppId, cacheInfo.AppKey, cacheInfo.Resource);
            }

            throw new NotImplementedException();
        }
예제 #13
0
 public void Add(TokenCacheInfo cacheInfo)
 {
     _caches[GetKey(cacheInfo.TenantId, cacheInfo.Resource)] = cacheInfo;
 }
예제 #14
0
 public void Add(TokenCacheInfo cacheInfo)
 {
     _caches[GetKey(cacheInfo.TenantId, cacheInfo.Resource)] = cacheInfo;
 }
예제 #15
0
        protected TokenCacheInfo GetAuthorizationResultByUpn(CustomTokenCache tokenCache, string tenantId, string username, string password, string resource)
        {
            TokenCacheInfo found;
            if (tokenCache.TryGetValue(tenantId, resource, out found))
            {
                return found;
            }

            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;
        }
예제 #16
0
 public void SaveRecentToken(TokenCacheInfo cacheInfo, string resource)
 {
     var file = ProtectedFile.GetCacheFile(resource == Constants.CSMResource ? _recentARMFileName : _recentAADFileName);
     var json = JObject.FromObject(cacheInfo);
     ProtectedFile.WriteAllText(ProtectedFile.GetCacheFile(file), json.ToString());
 }
예제 #17
0
        private async Task<string[]> GetTenantIds(TokenCacheInfo cacheInfo)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
                client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);

                var azureEnvironment = this.AzureEnvironments;
                var url = string.Format("{0}/tenants?api-version={1}", Constants.CSMUrls[(int)azureEnvironment], Constants.CSMApiVersion);
                using (var response = await client.GetAsync(url))
                {
                    if (response.IsSuccessStatusCode)
                    {
                        var result = await response.Content.ReadAsAsync<ResultOf<TenantInfo>>();
                        return result.value.Select(tenant => tenant.tenantId).ToArray();
                    }

                    throw new InvalidOperationException(await response.Content.ReadAsStringAsync());
                }
            }
        }
예제 #18
0
 static async Task<int> HttpInvoke(Uri uri, TokenCacheInfo cacheInfo, string verb, bool verbose, HttpContent content)
 {
     var logginerHandler = new HttpLoggingHandler(new HttpClientHandler(), verbose);
     return await Utils.HttpInvoke(uri, cacheInfo, verb, logginerHandler, content);
 }
예제 #19
0
 public void SaveRecentToken(TokenCacheInfo cacheInfo, string resource)
 {
     this._recentToken = cacheInfo;
 }
예제 #20
-1
        public static async Task<int> HttpInvoke(Uri uri, TokenCacheInfo cacheInfo, string verb, DelegatingHandler handler, HttpContent content)
        {
            using (var client = new HttpClient(handler))
            {
                client.DefaultRequestHeaders.Add("Authorization", cacheInfo.CreateAuthorizationHeader());
                client.DefaultRequestHeaders.Add("User-Agent", Constants.UserAgent.Value);
                client.DefaultRequestHeaders.Add("Accept", Constants.JsonContentType);

                if (Utils.IsRdfe(uri))
                {
                    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))
                {
                    response = await client.GetAsync(uri);
                }
                else if (String.Equals(verb, "delete", StringComparison.OrdinalIgnoreCase))
                {
                    response = await client.DeleteAsync(uri);
                }
                else if (String.Equals(verb, "post", StringComparison.OrdinalIgnoreCase))
                {
                    response = await client.PostAsync(uri, content);
                }
                else if (String.Equals(verb, "put", StringComparison.OrdinalIgnoreCase))
                {
                    response = await client.PutAsync(uri, content);
                }
                else if (String.Equals(verb, "patch", StringComparison.OrdinalIgnoreCase))
                {
                    using (var message = new HttpRequestMessage(new HttpMethod("PATCH"), uri))
                    {
                        message.Content = content;
                        response = await client.SendAsync(message).ConfigureAwait(false);
                    }
                }
                else
                {
                    throw new InvalidOperationException(String.Format("Invalid http verb {0}!", verb));
                }

                using (response)
                {
                    if (response.IsSuccessStatusCode)
                    {
                        return 0;
                    }

                    return (-1) * (int)response.StatusCode;
                }
            }
        }