/// <summary> /// Writes a token to the cache. /// </summary> /// <param name="targetUri">The key which to index the token by.</param> /// <param name="token">The token to write to the cache.</param> public void WriteToken(TargetUri targetUri, Token token) { BaseSecureStore.ValidateTargetUri(targetUri); Token.Validate(token); string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName)) { _cache[targetName] = token; } else { _cache.Add(targetName, token); } } }
/// <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( RuntimeContext context, TargetUri targetUri, VstsTokenScope scope, ICredentialStore personalAccessTokenStore) { BaseSecureStore.ValidateTargetUri(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 VstsMsaAuthentication(context, scope, personalAccessTokenStore); } else { context.Trace.WriteLine($"AAD authority for tenant '{tenantId}' detected."); authentication = new VstsAadAuthentication(context, tenantId, scope, personalAccessTokenStore); (authentication as VstsAadAuthentication).TenantId = tenantId; } return(authentication); }
public static async Task <AuthenticationHeaderValue[]> GetHeaderValues(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); if (targetUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.Ordinal) || targetUri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.Ordinal)) { try { // Try the query uri string queryUrl = targetUri.QueryUri.ToString(); // Try the actual uri string actualUrl = targetUri.ActualUri.ToString(); using (var httpClientHandler = targetUri.HttpClientHandler) { // Send off the HTTP requests and wait for them to complete var results = await Task.WhenAll(RequestAuthenticate(queryUrl, httpClientHandler), RequestAuthenticate(actualUrl, httpClientHandler)); // If any of then returned true, then we're looking at a TFS server HashSet <AuthenticationHeaderValue> set = new HashSet <AuthenticationHeaderValue>(); // combine the results into a unique set foreach (var result in results) { foreach (var item in result) { set.Add(item); } } return(set.ToArray()); } } catch (Exception exception) { Git.Trace.WriteLine("error testing targetUri for NTML: " + exception.Message); } } return(NullResult); }
/// <summary> /// Writes credentials for a target URI to the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being stored</param> /// <param name="credentials">The credentials to be stored</param> public void WriteCredentials(TargetUri targetUri, Credential credentials) { BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateCredential(credentials); string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName)) { _cache[targetName] = credentials; } else { _cache.Add(targetName, credentials); } } }
/// <summary> /// Generates a "personal access token" or service specific, usage resticted access token. /// </summary> /// <param name="targetUri"> /// The target resource for which to acquire the personal access token for. /// </param> /// <param name="accessToken"> /// Azure Directory access token with privileges to grant access to the target resource. /// </param> /// <param name="options"> /// Set of options related to generation of personal access tokens. /// </param> /// <returns><see langword="true"/> if successful; <see langword="false"/> otherwise.</returns> protected async Task <Credential> GeneratePersonalAccessToken( TargetUri targetUri, Token accessToken, PersonalAccessTokenOptions options) { BaseSecureStore.ValidateTargetUri(targetUri); if (ReferenceEquals(accessToken, null)) { throw new ArgumentNullException(nameof(accessToken)); } VstsTokenScope requestedScope = TokenScope; if (options.TokenScope != null) { // Take the intersection of the auhority scope and the requested scope requestedScope &= options.TokenScope; // If the result of the intersection is none, then fail if (string.IsNullOrWhiteSpace(requestedScope.Value)) { throw new InvalidOperationException("Invalid scope requested. Reqeuested scope would result in no access privileges."); } } Credential credential = null; Token personalAccessToken; if ((personalAccessToken = await VstsAuthority.GeneratePersonalAccessToken(targetUri, accessToken, requestedScope, options.RequireCompactToken, options.TokenDuration)) != null) { credential = (Credential)personalAccessToken; Git.Trace.WriteLine($"personal access token created for '{targetUri}'."); PersonalAccessTokenStore.WriteCredentials(targetUri, credential); } return(credential); }
/// <summary> /// Acquires credentials via the registered callbacks. /// </summary> /// <param name="targetUri"> /// The uniform resource indicator used to uniquely identify the credentials. /// </param> /// <returns>If successful a <see cref="Credential"/> object from the authentication object, /// authority or storage; otherwise <see langword="null"/>.</returns> public async Task <Credential> AcquireCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); if (_ntlmSupport != NtlmSupport.Never) { // get the WWW-Authenticate headers (if any) if (_httpAuthenticateOptions == null) { _httpAuthenticateOptions = await WwwAuthenticateHelper.GetHeaderValues(targetUri); } // if the headers contain NTML as an option, then fall back to NTLM if (_httpAuthenticateOptions.Any(x => WwwAuthenticateHelper.IsNtlm(x))) { Git.Trace.WriteLine($"'{targetUri}' supports NTLM, sending NTLM credentials instead"); return(NtlmCredentials); } } Credential credentials = null; if (_ntlmSupport != NtlmSupport.Always && _acquireCredentials != null) { Git.Trace.WriteLine($"prompting user for credentials for '{targetUri}'."); credentials = _acquireCredentials(targetUri); if (_acquireResult != null) { AcquireCredentialResult result = (credentials == null) ? AcquireCredentialResult.Failed : AcquireCredentialResult.Suceeded; _acquireResult(targetUri, result); } } return(credentials); }
/// <summary> /// Attempts to generate a new personal access token (credentials) via use of a stored /// Azure refresh token, identified by the target resource. /// </summary> /// <param name="targetUri">The 'key' by which to identify the refresh token.</param> /// <param name="requireCompactToken">Generates a compact token if <see langword="true"/>; /// generates a self describing token if <see langword="false"/>.</param> /// <returns><see langword="true"/> if successful; <see langword="false"/> otherwise.</returns> public async Task <bool> RefreshCredentials(TargetUri targetUri, bool requireCompactToken) { BaseSecureStore.ValidateTargetUri(targetUri); Trace.WriteLine("BaseVstsAuthentication::RefreshCredentials"); try { TokenPair tokens = null; Token refreshToken = null; // attempt to read from the local store if (this.AdaRefreshTokenStore.ReadToken(targetUri, out refreshToken)) { if ((tokens = await this.VstsAuthority.AcquireTokenByRefreshTokenAsync(targetUri, this.ClientId, this.Resource, refreshToken)) != null) { Trace.WriteLine(" Azure token found in primary cache."); this.TenantId = tokens.AccessToken.TargetIdentity; return(await this.GeneratePersonalAccessToken(targetUri, tokens.AccessToken, requireCompactToken)); } } Token federatedAuthToken; // attempt to utilize any fedauth tokens captured by the IDE if (this.VstsIdeTokenCache.ReadToken(targetUri, out federatedAuthToken)) { Trace.WriteLine(" federated auth token found in IDE cache."); return(await this.GeneratePersonalAccessToken(targetUri, federatedAuthToken, requireCompactToken)); } } catch (Exception exception) { Debug.WriteLine(exception); } Trace.WriteLine(" failed to refresh credentials."); return(false); }
/// <summary> /// Writes credentials for a target URI to the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being stored</param> /// <param name="credentials">The credentials to be stored</param> public void WriteCredentials(Uri targetUri, Credential credentials) { BaseSecureStore.ValidateTargetUri(targetUri); Credential.Validate(credentials); Trace.WriteLine("SecretCache::WriteCredentials"); string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName)) { _cache[targetName] = credentials; } else { _cache.Add(targetName, credentials); } } }
/// <summary> /// Reads credentials for a target URI from the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being read</param> /// <returns>A <see cref="Credential"/> from the store; <see langword="null"/> if failure.</returns> public Credential ReadCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); Credential credentials = null; string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName) && _cache[targetName] is Credential) { credentials = _cache[targetName] as Credential; } else { credentials = null; } } return(credentials); }
/// <summary> /// Gets a token from the cache. /// </summary> /// <param name="targetUri">The key which to find the token.</param> /// <returns>A <see cref="Token"/> if successful; otherwise <see langword="null"/>.</returns> public Token ReadToken(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); Token token = null; string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName) && _cache[targetName] is Token) { token = _cache[targetName] as Token; } else { token = null; } } return(token); }
/// <summary> /// Writes a token to the cache. /// </summary> /// <param name="targetUri">The key which to index the token by.</param> /// <param name="token">The token to write to the cache.</param> public Task <bool> WriteToken(TargetUri targetUri, Token token) { BaseSecureStore.ValidateTargetUri(targetUri); Token.Validate(token); string targetName = GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName)) { _cache[targetName] = token; } else { _cache.Add(targetName, token); } } return(Task.FromResult(true)); }
/// <summary> /// Writes credentials for a target URI to the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being stored</param> /// <param name="credentials">The credentials to be stored</param> public Task <bool> WriteCredentials(TargetUri targetUri, Credential credentials) { BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateCredential(credentials); string targetName = GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName)) { _cache[targetName] = credentials; } else { _cache.Add(targetName, credentials); } } return(Task.FromResult(true)); }
/// <summary> /// Reads credentials for a target URI from the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being read</param> /// <returns>A <see cref="Credential"/> from the store; <see langword="null"/> if failure.</returns> public Task <Credential> ReadCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); Credential credentials = null; string targetName = GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName) && _cache[targetName] is Credential) { credentials = _cache[targetName] as Credential; } else { credentials = null; } } return(Task.FromResult(credentials)); }
/// <summary> /// <para>Validates that <see cref="Token"/> are valid to grant access to the Visual Studio /// Online service represented by the <paramref name="targetUri"/> parameter.</para> /// </summary> /// <param name="targetUri">Uniform resource identifier for a VSTS service.</param> /// <param name="token"> /// <see cref="Token"/> expected to grant access to the VSTS service. /// </param> /// <returns>True if successful; otherwise false.</returns> public async Task <bool> ValidateToken(TargetUri targetUri, Token token) { BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateToken(token); Trace.WriteLine("VstsAzureAuthority::ValidateToken"); // personal access tokens are effectively credentials, treat them as such if (token.Type == TokenType.Personal) { return(await this.ValidateCredentials(targetUri, (Credential)token)); } try { // create an request to the VSTS deployment data end-point HttpWebRequest request = GetConnectionDataRequest(targetUri, token); Trace.WriteLine(" validating token against " + request.Host); // send the request and wait for the response using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse) { // we're looking for 'OK 200' here, anything else is failure Trace.WriteLine(" server returned: " + response.StatusCode); return(response.StatusCode == HttpStatusCode.OK); } } catch (WebException webException) { Trace.WriteLine(" server returned: " + webException.Message); } catch { Trace.WriteLine(" unexpected error"); } Trace.WriteLine(" token validation failed"); return(false); }
public async Task <bool> ValidateCredentials(TargetUri targetUri, Credential credentials) { const string ValidationUrl = "https://api.github.com/user/subscriptions"; BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateCredential(credentials); Trace.WriteLine(" GitHubAuthority::ValidateCredentials"); string authString = String.Format("{0}:{1}", credentials.Username, credentials.Password); byte[] authBytes = Encoding.UTF8.GetBytes(authString); string authEncode = Convert.ToBase64String(authBytes); // craft the request header for the GitHub v3 API w/ credentials using (HttpClientHandler handler = targetUri.HttpClientHandler) using (HttpClient httpClient = new HttpClient(handler) { Timeout = TimeSpan.FromMilliseconds(RequestTimeout) }) { httpClient.DefaultRequestHeaders.Add("User-Agent", Global.UserAgent); httpClient.DefaultRequestHeaders.Add("Accept", GitHubApiAcceptsHeaderValue); httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + authEncode); using (HttpResponseMessage response = await httpClient.GetAsync(ValidationUrl)) { if (response.IsSuccessStatusCode) { Trace.WriteLine(" credential validation succeeded"); return(true); } else { Trace.WriteLine(" credential validation failed"); return(false); } } } }
/// <summary> /// Reads credentials for a target URI from the credential store /// </summary> /// <param name="targetUri">The URI of the target for which credentials are being read</param> /// <param name="credentials">The credentials from the store; <see langword="null"/> if failure</param> /// <returns><see langword="true"/> if success; <see langword="false"/> if failure</returns> public bool ReadCredentials(TargetUri targetUri, out Credential credentials) { BaseSecureStore.ValidateTargetUri(targetUri); Trace.WriteLine("SecretCache::ReadCredentials"); string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName) && _cache[targetName] is Credential) { credentials = _cache[targetName] as Credential; } else { credentials = null; } } return(credentials != null); }
/// <summary> /// Gets a token from the cache. /// </summary> /// <param name="targetUri">The key which to find the token.</param> /// <param name="token">The token if successful; otherwise <see langword="null"/>.</param> /// <returns><see langword="true"/> if successful; <see langword="false"/> otherwise.</returns> public bool ReadToken(TargetUri targetUri, out Token token) { BaseSecureStore.ValidateTargetUri(targetUri); Trace.WriteLine("SecretCache::ReadToken"); string targetName = this.GetTargetName(targetUri); lock (_cache) { if (_cache.ContainsKey(targetName) && _cache[targetName] is Token) { token = _cache[targetName] as Token; } else { token = null; } } return(token != null); }
public async Task <Credential> NoninteractiveLogon(TargetUri targetUri, bool requestCompactToken) { BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await VstsAuthority.NoninteractiveAcquireToken(targetUri, ClientId, Resource, new Uri(RedirectUrl))) != null) { Trace.WriteLine($"token acquisition for '{targetUri}' succeeded"); return(await GeneratePersonalAccessToken(targetUri, token, requestCompactToken)); } } catch (AdalException) { Trace.WriteLine($"failed to acquire for '{targetUri}' token from VstsAuthority."); } Trace.WriteLine($"non-interactive logon for '{targetUri}' failed"); return(null); }
/// <summary> /// Gets a <see cref="Credential"/> from the storage used by the authentication object. /// <para/> /// Returns a `<see cref="Credential"/>` if successful; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri">The uniform resource indicator used to uniquely identify the credentials.</param> public override Credential GetCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); Credential credentials = null; try { if ((credentials = PersonalAccessTokenStore.ReadCredentials(targetUri)) != null) { Git.Trace.WriteLine($"credentials for '{targetUri}' found."); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception); Git.Trace.WriteLine($"failed to read credentials from the secure store: {exception.GetType().Name}."); } return(credentials); }
/// <summary> /// Opens an interactive logon prompt to acquire an authentication token from the Microsoft Live authentication and identity service. /// <para/> /// Returns a `<see cref="Credential"/>` for packing into a basic authentication header; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri"> /// The uniform resource indicator of the resource access tokens are being requested for. /// </param> /// <param name="options"></param> public async Task <Credential> InteractiveLogon(TargetUri targetUri, PersonalAccessTokenOptions options) { BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await VstsAuthority.InteractiveAcquireToken(targetUri, ClientId, Resource, new Uri(RedirectUrl), QueryParameters)) != null) { Trace.WriteLine($"token '{targetUri}' successfully acquired."); return(await GeneratePersonalAccessToken(targetUri, token, options)); } } catch (AdalException exception) { Debug.Write(exception); } Trace.WriteLine($"failed to acquire token for '{targetUri}'."); return(null); }
/// <summary> /// Creates a new authentication broker based for the specified resource. /// </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> /// <param name="adaRefreshTokenStore">Storage container for Azure access token secrets.</param> /// <param name="authentication"> /// An implementation of <see cref="BaseAuthentication"/> if one was detected; /// <see langword="null"/> otherwise. /// </param> /// <returns> /// <see langword="true"/> if an authority could be determined; <see langword="false"/> otherwise. /// </returns> public static BaseAuthentication GetAuthentication( TargetUri targetUri, VstsTokenScope scope, ICredentialStore personalAccessTokenStore) { BaseSecureStore.ValidateTargetUri(targetUri); if (ReferenceEquals(scope, null)) { throw new ArgumentNullException(nameof(scope)); } if (ReferenceEquals(personalAccessTokenStore, null)) { throw new ArgumentNullException(nameof(personalAccessTokenStore)); } Trace.WriteLine("BaseVstsAuthentication::DetectAuthority"); BaseAuthentication authentication = null; Guid tenantId; if (DetectAuthority(targetUri, out tenantId)) { // empty Guid is MSA, anything else is AAD if (tenantId == Guid.Empty) { Trace.WriteLine(" MSA authority detected"); authentication = new VstsMsaAuthentication(scope, personalAccessTokenStore); } else { Trace.WriteLine(" AAD authority for tenant '" + tenantId + "' detected"); authentication = new VstsAadAuthentication(tenantId, scope, personalAccessTokenStore); (authentication as VstsAadAuthentication).TenantId = tenantId; } } return(authentication); }
/// <summary> /// <para>Creates an interactive logon session, using ADAL secure browser GUI, which /// enables users to authenticate with the Azure tenant and acquire the necessary access /// tokens to exchange for a VSTS personal access token.</para> /// <para>Tokens acquired are stored in the secure secret stores provided during /// initialization.</para> /// </summary> /// <param name="targetUri">The unique identifier for the resource for which access is to /// be acquired.</param> /// <param name="requestCompactToken"> /// <para>Requests a compact format personal access token; otherwise requests a standard /// personal access token.</para> /// <para>Compact tokens are necessary for clients which have restrictions on the size of /// the basic authentication header which they can create (example: Git).</para> /// </param> /// <returns>A <see cref="Credential"/> for packing into a basic authentication header; /// otherwise <see langword="null"/>.</returns> public async Task <Credential> InteractiveLogon(TargetUri targetUri, bool requestCompactToken) { BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await this.VstsAuthority.InteractiveAcquireToken(targetUri, this.ClientId, this.Resource, new Uri(RedirectUrl), null)) != null) { Git.Trace.WriteLine($"token acquisition for '{targetUri}' succeeded."); return(await this.GeneratePersonalAccessToken(targetUri, token, requestCompactToken)); } } catch (AdalException) { Git.Trace.WriteLine($"token acquisition for '{targetUri}' failed."); } Git.Trace.WriteLine($"interactive logon for '{targetUri}' failed"); return(null); }
/// <summary> /// Validates that a `<see cref="Token"/>` is valid to grant access to the VSTS resource referenced by `<paramref name="targetUri"/>`. /// <para/> /// Returns `<see langword="true"/>` if successful; otherwise `<see langword="false"/>`. /// </summary> /// <param name="targetUri">URI of the VSTS resource.</param> /// <param name="token">`<see cref="Token"/>` expected to grant access to the VSTS resource.</param> public async Task <bool> ValidateToken(TargetUri targetUri, Token token) { BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateToken(token); // Personal access tokens are effectively credentials, treat them as such. if (token.Type == TokenType.Personal) { return(await ValidateCredentials(targetUri, (Credential)token)); } try { // Create an request to the VSTS deployment data end-point. HttpWebRequest request = GetConnectionDataRequest(targetUri, token); Git.Trace.WriteLine($"validating token against '{request.Host}'."); // Send the request and wait for the response. using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse) { // We're looking for 'OK 200' here, anything else is failure. Git.Trace.WriteLine($"server returned: '{response.StatusCode}'."); return(response.StatusCode == HttpStatusCode.OK); } } catch (WebException webException) { Git.Trace.WriteLine($"! server returned: '{webException.Message}'."); } catch { Git.Trace.WriteLine("! unexpected error"); } Git.Trace.WriteLine($"token validation for '{targetUri}' failed."); return(false); }
/// <summary> /// Generates a "personal access token" or service specific, usage restricted access token. /// <para/> /// Returns `<see langword="true"/>` if successful; `<see langword="false"/>` otherwise. /// </summary> /// <param name="targetUri">The target resource for which to acquire the personal access token for.</param> /// <param name="accessToken">Azure Directory access token with privileges to grant access to the target resource.</param> /// <param name="requestCompactToken">Generates a compact token if `<see langword="true"/>`; generates a self describing token if `<see langword="false"/>`.</param> protected async Task <Credential> GeneratePersonalAccessToken( TargetUri targetUri, Token accessToken, bool requestCompactToken) { BaseSecureStore.ValidateTargetUri(targetUri); if (accessToken is null) { throw new ArgumentNullException(nameof(accessToken)); } Credential credential = null; Token personalAccessToken; if ((personalAccessToken = await VstsAuthority.GeneratePersonalAccessToken(targetUri, accessToken, TokenScope, requestCompactToken)) != null) { credential = (Credential)personalAccessToken; Trace.WriteLine($"personal access token created for '{targetUri}'."); try { await PersonalAccessTokenStore.WriteCredentials(targetUri, credential); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception); Trace.WriteLine($"failed to write credentials to the secure store."); Trace.WriteException(exception); } } return(credential); }
/// <summary> /// Opens an interactive logon prompt to acquire acquire an authentication token from the /// Microsoft Live authentication and identity service. /// </summary> /// <param name="targetUri"> /// The uniform resource indicator of the resource access tokens are being requested for. /// </param> /// <param name="requireCompactToken"> /// True if a compact access token is required; false if a standard token is acceptable. /// </param> /// <returns>A <see cref="Credential"/> for packing into a basic authentication header; /// otherwise <see langword="null"/>.</returns> public async Task <Credential> InteractiveLogon(TargetUri targetUri, bool requireCompactToken) { const string QueryParameters = "domain_hint=live.com&display=popup&site_id=501454&nux=1"; BaseSecureStore.ValidateTargetUri(targetUri); try { Token token; if ((token = await this.VstsAuthority.InteractiveAcquireToken(targetUri, this.ClientId, this.Resource, new Uri(RedirectUrl), QueryParameters)) != null) { Git.Trace.WriteLine($"token '{targetUri}' successfully acquired."); return(await this.GeneratePersonalAccessToken(targetUri, token, requireCompactToken)); } } catch (AdalException exception) { Debug.Write(exception); } Git.Trace.WriteLine($"failed to acquire token for '{targetUri}'."); return(null); }
public static async Task <KeyValuePair <bool, Guid> > DetectAuthority(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)) { Git.Trace.WriteLine($"'{targetUri}' is subdomain of '{VstsBaseUrlHost}', checking AAD vs MSA."); string tenant = null; WebResponse response; if (StringComparer.OrdinalIgnoreCase.Equals(targetUri.Scheme, "http") || StringComparer.OrdinalIgnoreCase.Equals(targetUri.Scheme, "https")) { // Query the cache first string tenantUrl = targetUri.ToString(); // Read the cache from disk var cache = await DeserializeTenantCache(); // Check the cache for an existing value if (cache.TryGetValue(tenantUrl, out tenantId)) { return(new KeyValuePair <bool, Guid>(true, tenantId)); } try { // Build a request that we expect to fail, do not allow redirect to sign in url var request = WebRequest.CreateHttp(targetUri); request.UserAgent = Global.UserAgent; request.Method = "HEAD"; request.AllowAutoRedirect = false; // Get the response from the server response = await request.GetResponseAsync(); } catch (WebException exception) { Git.Trace.WriteLine($"unable to get response from '{targetUri}' due to '{exception.Status}'."); // Given the number proxy related failures we see, emit a message about the failure potentially // being related to a proxy or gateway misconfiguration. switch (exception.Status) { case WebExceptionStatus.ConnectFailure: case WebExceptionStatus.PipelineFailure: case WebExceptionStatus.ProtocolError: case WebExceptionStatus.ReceiveFailure: case WebExceptionStatus.SecureChannelFailure: case WebExceptionStatus.SendFailure: case WebExceptionStatus.ServerProtocolViolation: case WebExceptionStatus.TrustFailure: { Git.Trace.WriteLine($"is there a proxy or gateway incorrectly configured?"); } break; } response = exception.Response; } // If the response exists and we have headers, parse them if (response != null && response.SupportsHeaders) { // Find the VSTS resource tenant entry tenant = response.Headers[VstsResourceTenantHeader]; if (!string.IsNullOrWhiteSpace(tenant) && Guid.TryParse(tenant, out tenantId)) { // Update the cache. cache[tenantUrl] = tenantId; // Write the cache to disk. await SerializeTenantCache(cache); // Success, notify the caller return(new KeyValuePair <bool, Guid>(true, tenantId)); } } } else { Git.Trace.WriteLine($"detected non-https based protocol: {targetUri.Scheme}."); } } // if all else fails, fallback to basic authentication return(new KeyValuePair <bool, Guid>(false, tenantId)); }
/// <summary> /// Gets `<see cref="Credential"/>` from the storage used by the authentication object. /// <para/> /// Returns a `<see cref="Credential"/>` if successful; otherwise `<see langword="null"/>`. /// </summary> /// <param name="targetUri">The uniform resource indicator used to uniquely identify the credentials.</param> public override Credential GetCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); return(_credentialStore.ReadCredentials(targetUri)); }
/// <summary> /// Deletes `<see cref="Credential"/>` from the storage used by the authentication object. /// </summary> /// <param name="targetUri">The uniform resource indicator used to uniquely identify the credentials.</param> public override void DeleteCredentials(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); _credentialStore.DeleteCredentials(targetUri); }
/// <summary> /// Formats a TargetName string based on the TargetUri base on the format started by git-credential-winstore /// </summary> /// <param name="targetUri">Uri of the target</param> /// <returns>Properly formatted TargetName string</returns> private string GetTargetName(TargetUri targetUri) { BaseSecureStore.ValidateTargetUri(targetUri); return(_getTargetName(targetUri, _namespace)); }
/// <summary> /// Sets credentials for future use with this authentication object. /// </summary> /// <remarks>Not supported.</remarks> /// <param name="targetUri"> /// The uniform resource indicator of the resource access tokens are being set for. /// </param> /// <param name="credentials">The credentials being set.</param> public override void SetCredentials(TargetUri targetUri, Credential credentials) { BaseSecureStore.ValidateTargetUri(targetUri); BaseSecureStore.ValidateCredential(credentials); }