/// <summary> /// Creates a new authentication broker based for the specified resource. /// <para/> /// Returns `<see langword="true"/>` if an authority could be determined; otherwise `<see langword="false"/>`. /// </summary> /// <param name="targetUri">The resource for which authentication is being requested.</param> /// <param name="scope">The scope of the access being requested.</param> /// <param name="personalAccessTokenStore">Storage container for personal access token secrets.</param> public static async Task <BaseAuthentication> GetAuthentication( Microsoft.Alm.Authentication.RuntimeContext context, TargetUri targetUri, TokenScope scope, ICredentialStore personalAccessTokenStore) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (targetUri is null) { throw new ArgumentNullException(nameof(targetUri)); } if (scope is null) { throw new ArgumentNullException(nameof(scope)); } if (personalAccessTokenStore is null) { throw new ArgumentNullException(nameof(personalAccessTokenStore)); } BaseAuthentication authentication = null; var result = await DetectAuthority(context, targetUri); if (!result.HasValue) { return(null); } // Query for the tenant's identity Guid tenantId = result.Value; // empty identity is MSA, anything else is AAD if (tenantId == Guid.Empty) { context.Trace.WriteLine("MSA authority detected."); authentication = new MsaAuthentication(context, scope, personalAccessTokenStore); } else { context.Trace.WriteLine($"AAD authority for tenant '{tenantId.ToString("N")}' detected."); authentication = new AadAuthentication(context, tenantId, scope, personalAccessTokenStore); (authentication as AadAuthentication).TenantId = tenantId; } return(authentication); }
public Adal(Alm.RuntimeContext context) : base(context) { _cache = new AdalTokenCache(context); }
public Network(RuntimeContext context) : base(context) { }
public BasicAuthentication(RuntimeContext context, ICredentialStore credentialStore) : this(context, credentialStore, NtlmSupport.Auto, null, null) { }
public Settings(RuntimeContext context) : base(context) { }
private SecretCache(RuntimeContext context) : base(context) { _cache = new Dictionary <string, Secret>(KeyComparer); }
public SecretCache(RuntimeContext context, string @namespace) : this(context, @namespace, null) { }
protected BaseAuthentication(RuntimeContext context) : base(context) { }
private static async Task <Dictionary <string, Guid> > DeserializeTenantCache(RuntimeContext context) { var encoding = new UTF8Encoding(false); var path = GetCachePath(context); string data = null; Dictionary <string, Guid> cache = new Dictionary <string, Guid>(StringComparer.OrdinalIgnoreCase); Exception exception = null; // Attempt up to five times to read from the cache for (int i = 0; i < 5; i += 1) { try { // Just open the file from disk, the tenant identities are not secret and // therefore safely left as unencrypted plain text. using (var stream = context.Storage.FileOpen(path, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read)) using (var inflate = new GZipStream(stream, CompressionMode.Decompress)) using (var reader = new StreamReader(inflate, encoding)) { data = await reader.ReadToEndAsync(); break; } } catch when(i < 5) { // Sleep the thread, and wait before trying again using progressive back off System.Threading.Thread.Sleep(i + 1 * 100); }
public static async Task <Guid?> DetectAuthority(RuntimeContext context, TargetUri targetUri) { const string VstsBaseUrlHost = "visualstudio.com"; const string VstsResourceTenantHeader = "X-VSS-ResourceTenant"; BaseSecureStore.ValidateTargetUri(targetUri); var tenantId = Guid.Empty; if (targetUri.Host.EndsWith(VstsBaseUrlHost, StringComparison.OrdinalIgnoreCase)) { context.Trace.WriteLine($"'{targetUri}' is subdomain of '{VstsBaseUrlHost}', checking AAD vs MSA."); string tenant = null; if (StringComparer.OrdinalIgnoreCase.Equals(targetUri.Scheme, Uri.UriSchemeHttp) || StringComparer.OrdinalIgnoreCase.Equals(targetUri.Scheme, Uri.UriSchemeHttps)) { // Query the cache first. string tenantUrl = targetUri.ToString(); // Read the cache from disk. var cache = await DeserializeTenantCache(context); // Check the cache for an existing value. if (cache.TryGetValue(tenantUrl, out tenantId)) { return(tenantId); } var options = new NetworkRequestOptions(false) { Flags = NetworkRequestOptionFlags.UseProxy, Timeout = TimeSpan.FromMilliseconds(Global.RequestTimeout), }; try { using (var response = await context.Network.HttpGetAsync(targetUri, options)) { if (response.IsSuccessStatusCode) { if (response.Headers.TryGetValues(VstsResourceTenantHeader, out IEnumerable <string> values)) { tenant = System.Linq.Enumerable.First(values); if (!string.IsNullOrWhiteSpace(tenant) && Guid.TryParse(tenant, out tenantId)) { // Update the cache. cache[tenantUrl] = tenantId; // Write the cache to disk. await SerializeTenantCache(context, cache); // Success, notify the caller return(tenantId); } } } else { context.Trace.WriteLine($"unable to get response from '{targetUri}', server responded with '{(int)response.StatusCode} {response.StatusCode}'."); } } } catch (HttpRequestException exception) { context.Trace.WriteLine($"unable to get response from '{targetUri}' due to '{exception.Message}'."); } } else { context.Trace.WriteLine($"detected non-https based protocol: '{targetUri.Scheme}'."); } } // Fallback to basic authentication. return(null); }