ValidateTargetUri() private method

private ValidateTargetUri ( TargetUri targetUri ) : void
targetUri TargetUri
return void
Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <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);

            // 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 (_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);
        }
Beispiel #3
0
        /// <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);

            Trace.WriteLine("SecretCache::ReadToken");

            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);
        }
Beispiel #4
0
        /// <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);

            Trace.WriteLine("SecretCache::ReadCredentials");

            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);
        }
Beispiel #5
0
        /// <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));
            }

            BaseAuthentication authentication = null;

            Guid tenantId;

            if (DetectAuthority(targetUri, out tenantId))
            {
                // empty Guid is MSA, anything else is AAD
                if (tenantId == Guid.Empty)
                {
                    Git.Trace.WriteLine("MSA authority detected.");
                    authentication = new VstsMsaAuthentication(scope, personalAccessTokenStore);
                }
                else
                {
                    Git.Trace.WriteLine($"AAD authority for tenant '{tenantId}' detected.");
                    authentication = new VstsAadAuthentication(tenantId, scope, personalAccessTokenStore);
                    (authentication as VstsAadAuthentication).TenantId = tenantId;
                }
            }

            return(authentication);
        }
Beispiel #6
0
        /// <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);
        }
        /// <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);

            Trace.WriteLine("VstsAadAuthentication::InteractiveLogon");

            try
            {
                Token token;
                if ((token = await this.VstsAuthority.InteractiveAcquireToken(targetUri, this.ClientId, this.Resource, new Uri(RedirectUrl), null)) != null)
                {
                    Trace.WriteLine("   token acquisition succeeded.");

                    return(await this.GeneratePersonalAccessToken(targetUri, token, requestCompactToken));
                }
            }
            catch (AdalException)
            {
                Trace.WriteLine("   token acquisition failed.");
            }

            Trace.WriteLine("   interactive logon failed");
            return(null);
        }
        /// <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));
        }
        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));
        }
Beispiel #11
0
        /// <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>
        /// 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);
        }
Beispiel #13
0
        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)
                    {
                        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>
 /// 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);
 }
Beispiel #15
0
        /// <summary>
        /// Validates that a `<see cref="Credential"/>` 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="credentials">`<see cref="Credential"/>` expected to grant access to the VSTS service.</param>
        public async Task <bool> ValidateCredentials(TargetUri targetUri, Credential credentials)
        {
            BaseSecureStore.ValidateTargetUri(targetUri);
            BaseSecureStore.ValidateCredential(credentials);

            try
            {
                // Create an request to the VSTS deployment data end-point.
                HttpWebRequest request = GetConnectionDataRequest(targetUri, credentials);

                Git.Trace.WriteLine($"validating credentials against '{request.RequestUri}'.");

                // 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)
            {
                // Avoid invalidation credentials based on what is likely a networking problem.
                switch (webException.Status)
                {
                case WebExceptionStatus.ConnectFailure:
                case WebExceptionStatus.ConnectionClosed:
                case WebExceptionStatus.NameResolutionFailure:
                case WebExceptionStatus.ProxyNameResolutionFailure:
                case WebExceptionStatus.ReceiveFailure:
                case WebExceptionStatus.RequestCanceled:
                case WebExceptionStatus.RequestProhibitedByCachePolicy:
                case WebExceptionStatus.RequestProhibitedByProxy:
                case WebExceptionStatus.SecureChannelFailure:
                case WebExceptionStatus.SendFailure:
                case WebExceptionStatus.TrustFailure:
                {
                    Git.Trace.WriteLine($"unable to validate credentials due to '{webException.Status}'.");

                    return(true);
                }
                }

                // Even if the service responded, if the issue isn't a 400 class response then
                // the credentials were likely not rejected.
                if (webException.Response is HttpWebResponse response)
                {
                    int statusCode = (int)response.StatusCode;

                    if (statusCode < 400 && statusCode >= 500)
                    {
                        Git.Trace.WriteLine($"server returned: ({statusCode}).");

                        return(true);
                    }
                }

                Git.Trace.WriteLine($"server returned: '{webException.Message}.");
            }
            catch
            {
                Git.Trace.WriteLine("! unexpected error");
            }

            Git.Trace.WriteLine($"credential validation for '{targetUri}' failed.");
            return(false);
        }
Beispiel #16
0
        /// <summary>
        /// Generates a personal access token for use with Visual Studio Online.
        /// </summary>
        /// <param name="targetUri">
        /// The uniform resource indicator of the resource access tokens are being requested for.
        /// </param>
        /// <param name="accessToken"></param>
        /// <param name="tokenScope"></param>
        /// <param name="requireCompactToken"></param>
        /// <returns></returns>
        public async Task <Token> GeneratePersonalAccessToken(TargetUri targetUri, Token accessToken, VstsTokenScope tokenScope, bool requireCompactToken)
        {
            const string AccessTokenHeader = "Bearer";

            BaseSecureStore.ValidateTargetUri(targetUri);
            BaseSecureStore.ValidateToken(accessToken);
            if (ReferenceEquals(tokenScope, null))
            {
                throw new ArgumentNullException(nameof(tokenScope));
            }

            Trace.WriteLine("VstsAzureAuthority::GeneratePersonalAccessToken");

            try
            {
                // create a `HttpClient` with a minimum number of redirects, default creds, and a reasonable timeout (access token generation seems to hang occasionally)
                using (HttpClientHandler handler = new HttpClientHandler()
                {
                    MaxAutomaticRedirections = 2,
                    UseDefaultCredentials = true
                })
                    using (HttpClient httpClient = new HttpClient(handler)
                    {
                        Timeout = TimeSpan.FromMilliseconds(RequestTimeout)
                    })
                    {
                        httpClient.DefaultRequestHeaders.Add("User-Agent", Global.UserAgent);

                        switch (accessToken.Type)
                        {
                        case TokenType.Access:
                            Trace.WriteLine("   using Azure access token to acquire personal access token");

                            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(AccessTokenHeader, accessToken.Value);
                            break;

                        case TokenType.Federated:
                            Trace.WriteLine("   using federated authentication token to acquire personal access token");

                            httpClient.DefaultRequestHeaders.Add("Cookie", accessToken.Value);
                            break;

                        default:
                            return(null);
                        }

                        if (await PopulateTokenTargetId(targetUri, accessToken))
                        {
                            Uri requestUri;
                            if (TryCreateRequestUri(targetUri, requireCompactToken, out requestUri))
                            {
                                Trace.WriteLine("   request url is " + requestUri);

                                using (StringContent content = GetAccessTokenRequestBody(targetUri, accessToken, tokenScope))
                                    using (HttpResponseMessage response = await httpClient.PostAsync(requestUri, content))
                                    {
                                        if (response.StatusCode == HttpStatusCode.OK)
                                        {
                                            string responseText = await response.Content.ReadAsStringAsync();

                                            if (!String.IsNullOrWhiteSpace(responseText))
                                            {
                                                // find the 'token : <value>' portion of the result content, if any
                                                Match tokenMatch = null;
                                                if ((tokenMatch = Regex.Match(responseText, @"\s*""token""\s*:\s*""([^\""]+)""\s*", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase)).Success)
                                                {
                                                    string tokenValue = tokenMatch.Groups[1].Value;
                                                    Token  token      = new Token(tokenValue, TokenType.Personal);

                                                    Trace.WriteLine("   personal access token acquisition succeeded.");

                                                    return(token);
                                                }
                                            }
                                        }
                                    }
                            }
                        }
                    }
            }
            catch
            {
                Trace.WriteLine("   an error occurred.");
            }

            Trace.WriteLine("   personal access token acquisition failed.");

            return(null);
        }
Beispiel #17
0
        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);
        }
        /// <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 async Task <bool> DeleteCredentials(TargetUri targetUri)
        {
            BaseSecureStore.ValidateTargetUri(targetUri);

            return(await _credentialStore.DeleteCredentials(targetUri));
        }
        /// <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 async Task <Credential> GetCredentials(TargetUri targetUri)
        {
            BaseSecureStore.ValidateTargetUri(targetUri);

            return(await _credentialStore.ReadCredentials(targetUri));
        }