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

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

            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 #10
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);

            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 #11
0
        /// <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));
        }
Beispiel #12
0
        /// <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));
        }
Beispiel #13
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 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));
        }
Beispiel #14
0
        /// <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);
                        }
                    }
                }
        }
Beispiel #16
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>
        /// <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);
        }
Beispiel #17
0
        /// <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);
        }
Beispiel #18
0
        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);
        }
Beispiel #20
0
        /// <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);
        }
Beispiel #23
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 #24
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);
        }
        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);
        }
Beispiel #29
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>
 /// 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);
 }