/// <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 bool GetAuthentication(
            Uri targetUri,
            VsoTokenScope scope,
            ICredentialStore personalAccessTokenStore,
            ITokenStore adaRefreshTokenStore,
            out BaseAuthentication authentication)
        {
            Trace.WriteLine("BaseVsoAuthentication::DetectAuthority");

            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 VsoMsaAuthentication(scope, personalAccessTokenStore, adaRefreshTokenStore);
                }
                else
                {
                    Trace.WriteLine("   AAD authority for tenant '" + tenantId + "' detected");
                    authentication = new VsoAadAuthentication(tenantId, scope, personalAccessTokenStore, adaRefreshTokenStore);
                    (authentication as VsoAadAuthentication).TenantId = tenantId;
                }
            }
            else
            {
                authentication = null;
            }

            return(authentication != null);
        }
 /// <summary>
 /// Invoked by a derived classes implementation. Allows custom back-end implementations to be used.
 /// </summary>
 /// <param name="tokenScope">The desired scope of the acquired personal access token(s).</param>
 /// <param name="personalAccessTokenStore">The secret store for acquired personal access token(s).</param>
 /// <param name="adaRefreshTokenStore">The secret store for acquired Azure refresh token(s).</param>
 protected BaseVsoAuthentication(
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : this(tokenScope, personalAccessTokenStore)
 {
     this.AdaRefreshTokenStore = adaRefreshTokenStore ?? this.AdaRefreshTokenStore;
     this.VsoAdalTokenCache = new VsoAdalTokenCache();
     this.VsoIdeTokenCache = new TokenRegistry();
 }
 /// <summary>
 /// Invoked by a derived classes implementation. Allows custom back-end implementations to be used.
 /// </summary>
 /// <param name="tokenScope">The desired scope of the acquired personal access token(s).</param>
 /// <param name="personalAccessTokenStore">The secret store for acquired personal access token(s).</param>
 /// <param name="adaRefreshTokenStore">The secret store for acquired Azure refresh token(s).</param>
 protected BaseVsoAuthentication(
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : this(tokenScope, personalAccessTokenStore)
 {
     this.AdaRefreshTokenStore = adaRefreshTokenStore ?? this.AdaRefreshTokenStore;
     this.VsoAdalTokenCache    = new VsoAdalTokenCache();
     this.VsoIdeTokenCache     = new TokenRegistry();
 }
 public VsoMsaAuthentication(
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : base(tokenScope,
            personalAccessTokenStore,
            adaRefreshTokenStore)
 {
     this.VsoAuthority = new VsoAzureAuthority(DefaultAuthorityHost);
 }
Ejemplo n.º 5
0
 public VsoMsaAuthentication(
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : base(tokenScope,
            personalAccessTokenStore,
            adaRefreshTokenStore)
 {
     this.VsoAuthority = new VsoAzureAuthority(DefaultAuthorityHost);
 }
        private BaseVsoAuthentication(VsoTokenScope tokenScope, ICredentialStore personalAccessTokenStore)
        {
            if (tokenScope == null)
                throw new ArgumentNullException("scope", "The `scope` parameter is null or invalid.");
            if (personalAccessTokenStore == null)
                throw new ArgumentNullException("personalAccessTokenStore", "The `personalAccessTokenStore` paramter is null or invalid.");

            AdalTrace.TraceSource.Switch.Level = SourceLevels.Off;
            AdalTrace.LegacyTraceSwitch.Level = TraceLevel.Off;

            this.ClientId = DefaultClientId;
            this.Resource = DefaultResource;
            this.TokenScope = tokenScope;
            this.PersonalAccessTokenStore = personalAccessTokenStore;
            this.AdaRefreshTokenStore = new SecretStore(AdalRefreshPrefx);
            this.VsoAuthority = new VsoAzureAuthority();
        }
Ejemplo n.º 7
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="tenantId">
 /// <para>The unique identifier for the responsible Azure tenant.</para>
 /// <para>Use <see cref="BaseVsoAuthentication.GetAuthentication"/>
 /// to detect the tenant identity and create the authentication object.</para>
 /// </param>
 /// <param name="tokenScope">The scope of all access tokens acquired by the authority.</param>
 /// <param name="personalAccessTokenStore">The secure secret store for storing any personal
 /// access tokens acquired.</param>
 /// <param name="adaRefreshTokenStore">The secure secret store for storing any Azure tokens
 /// acquired.</param>
 public VsoAadAuthentication(
     Guid tenantId,
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : base(tokenScope,
            personalAccessTokenStore,
            adaRefreshTokenStore)
 {
     if (tenantId == Guid.Empty)
     {
         this.VsoAuthority = new VsoAzureAuthority(AzureAuthority.DefaultAuthorityHostUrl);
     }
     else
     {
         // create an authority host url in the format of https://login.microsoft.com/12345678-9ABC-DEF0-1234-56789ABCDEF0
         string authorityHost = AzureAuthority.GetAuthorityUrl(tenantId);
         this.VsoAuthority = new VsoAzureAuthority(authorityHost);
     }
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="tenantId">
 /// <para>The unique identifier for the responsible Azure tenant.</para>
 /// <para>Use <see cref="BaseVsoAuthentication.GetAuthentication"/>
 /// to detect the tenant identity and create the authentication object.</para>
 /// </param>
 /// <param name="tokenScope">The scope of all access tokens acquired by the authority.</param>
 /// <param name="personalAccessTokenStore">The secure secret store for storing any personal 
 /// access tokens acquired.</param>
 /// <param name="adaRefreshTokenStore">The secure secret store for storing any Azure tokens 
 /// acquired.</param>
 public VsoAadAuthentication(
     Guid tenantId,
     VsoTokenScope tokenScope,
     ICredentialStore personalAccessTokenStore,
     ITokenStore adaRefreshTokenStore = null)
     : base(tokenScope,
            personalAccessTokenStore,
            adaRefreshTokenStore)
 {
     if (tenantId == Guid.Empty)
     {
         this.VsoAuthority = new VsoAzureAuthority(AzureAuthority.DefaultAuthorityHostUrl);
     }
     else
     {
         // create an authority host url in the format of https://login.microsoft.com/12345678-9ABC-DEF0-1234-56789ABCDEF0
         string authorityHost = AzureAuthority.GetAuthorityUrl(tenantId);
         this.VsoAuthority = new VsoAzureAuthority(authorityHost);
     }
 }
        private BaseVsoAuthentication(VsoTokenScope tokenScope, ICredentialStore personalAccessTokenStore)
        {
            if (tokenScope == null)
            {
                throw new ArgumentNullException("scope", "The `scope` parameter is null or invalid.");
            }
            if (personalAccessTokenStore == null)
            {
                throw new ArgumentNullException("personalAccessTokenStore", "The `personalAccessTokenStore` paramter is null or invalid.");
            }

            AdalTrace.TraceSource.Switch.Level = SourceLevels.Off;
            AdalTrace.LegacyTraceSwitch.Level  = TraceLevel.Off;

            this.ClientId   = DefaultClientId;
            this.Resource   = DefaultResource;
            this.TokenScope = tokenScope;
            this.PersonalAccessTokenStore = personalAccessTokenStore;
            this.AdaRefreshTokenStore     = new SecretStore(AdalRefreshPrefx);
            this.VsoAuthority             = new VsoAzureAuthority();
        }
Ejemplo n.º 10
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(Uri targetUri, Token accessToken, VsoTokenScope tokenScope, bool requireCompactToken)
        {
            const string TokenAuthHost     = "app.vssps.visualstudio.com";
            const string SessionTokenUrl   = "https://" + TokenAuthHost + "/_apis/token/sessiontokens?api-version=1.0";
            const string CompactTokenUrl   = SessionTokenUrl + "&tokentype=compact";
            const string AccessTokenHeader = "Bearer";

            Debug.Assert(targetUri != null, "The targetUri parameter is null");
            Debug.Assert(accessToken != null && !String.IsNullOrWhiteSpace(accessToken.Value) && (accessToken.Type == TokenType.Access || accessToken.Type == TokenType.Federated), "The accessToken parameter is null or invalid");
            Debug.Assert(tokenScope != null);

            Trace.WriteLine("VsoAzureAuthority::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.GetUserAgent());

                        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))
                        {
                            string requestUrl = requireCompactToken ? CompactTokenUrl : SessionTokenUrl;

                            using (StringContent content = GetAccessTokenRequestBody(targetUri, accessToken, tokenScope))
                                using (HttpResponseMessage response = await httpClient.PostAsync(requestUrl, 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 aquisition succeeded.");

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

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

            return(null);
        }
Ejemplo n.º 11
0
        private StringContent GetAccessTokenRequestBody(Uri targetUri, Token accessToken, VsoTokenScope tokenScope)
        {
            const string ContentJsonFormat   = "{{ \"scope\" : \"{0}\", \"targetAccounts\" : [\"{1}\"], \"displayName\" : \"Git: {2} on {3}\" }}";
            const string HttpJsonContentType = "application/json";

            Debug.Assert(accessToken != null && (accessToken.Type == TokenType.Access || accessToken.Type == TokenType.Federated), "The accessToken parameter is null or invalid");
            Debug.Assert(tokenScope != null, "The tokenScope parameter is null");

            Trace.WriteLine("   creating access token scoped to '" + tokenScope + "' for '" + accessToken.TargetIdentity + "'");

            string        jsonContent = String.Format(ContentJsonFormat, tokenScope, accessToken.TargetIdentity, targetUri, Environment.MachineName);
            StringContent content     = new StringContent(jsonContent, Encoding.UTF8, HttpJsonContentType);

            return(content);
        }
        /// <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 bool GetAuthentication(
            Uri targetUri,
            VsoTokenScope scope,
            ICredentialStore personalAccessTokenStore,
            ITokenStore adaRefreshTokenStore,
            out BaseAuthentication authentication)
        {
            Trace.WriteLine("BaseVsoAuthentication::DetectAuthority");

            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 VsoMsaAuthentication(scope, personalAccessTokenStore, adaRefreshTokenStore);
                }
                else
                {
                    Trace.WriteLine("   AAD authority for tenant '" + tenantId + "' detected");
                    authentication = new VsoAadAuthentication(tenantId, scope, personalAccessTokenStore, adaRefreshTokenStore);
                    (authentication as VsoAadAuthentication).TenantId = tenantId;
                }
            }
            else
            {
                authentication = null;
            }

            return authentication != null;
        }
        /// <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(Uri targetUri, Token accessToken, VsoTokenScope tokenScope, bool requireCompactToken)
        {
            const string TokenAuthHost = "app.vssps.visualstudio.com";
            const string SessionTokenUrl = "https://" + TokenAuthHost + "/_apis/token/sessiontokens?api-version=1.0";
            const string CompactTokenUrl = SessionTokenUrl + "&tokentype=compact";
            const string AccessTokenHeader = "Bearer";

            Debug.Assert(targetUri != null, "The targetUri parameter is null");
            Debug.Assert(accessToken != null && !String.IsNullOrWhiteSpace(accessToken.Value) && (accessToken.Type == TokenType.Access || accessToken.Type == TokenType.Federated), "The accessToken parameter is null or invalid");
            Debug.Assert(tokenScope != null);

            Trace.WriteLine("VsoAzureAuthority::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.GetUserAgent());

                    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))
                    {
                        string requestUrl = requireCompactToken ? CompactTokenUrl : SessionTokenUrl;

                        using (StringContent content = GetAccessTokenRequestBody(targetUri, accessToken, tokenScope))
                        using (HttpResponseMessage response = await httpClient.PostAsync(requestUrl, 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 aquisition succeeded.");

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

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

            return null;
        }
        private StringContent GetAccessTokenRequestBody(Uri targetUri, Token accessToken, VsoTokenScope tokenScope)
        {
            const string ContentJsonFormat = "{{ \"scope\" : \"{0}\", \"targetAccounts\" : [\"{1}\"], \"displayName\" : \"Git: {2} on {3}\" }}";
            const string HttpJsonContentType = "application/json";

            Debug.Assert(accessToken != null && (accessToken.Type == TokenType.Access || accessToken.Type == TokenType.Federated), "The accessToken parameter is null or invalid");
            Debug.Assert(tokenScope != null, "The tokenScope parameter is null");

            Trace.WriteLine("   creating access token scoped to '" + tokenScope + "' for '" + accessToken.TargetIdentity + "'");

            string jsonContent = String.Format(ContentJsonFormat, tokenScope, accessToken.TargetIdentity, targetUri, Environment.MachineName);
            StringContent content = new StringContent(jsonContent, Encoding.UTF8, HttpJsonContentType);

            return content;
        }