예제 #1
0
        /// <summary>
        /// Gets a list of token provider executables to call to get token.
        /// </summary>
        /// <param name="visualStudioTokenProviderFile">Visual Studio Token provider file</param>
        /// <param name="resource"></param>
        /// <param name="tenant"></param>
        /// <returns></returns>
        private List <ProcessStartInfo> GetProcessStartInfos(VisualStudioTokenProviderFile visualStudioTokenProviderFile,
                                                             string resource, string tenant = default)
        {
            var processStartInfos = new List <ProcessStartInfo>();

            foreach (var tokenProvider in visualStudioTokenProviderFile.TokenProviders)
            {
                // If file does not exist, the version of Visual Studio that set the token provider may be uninstalled.
                if (File.Exists(tokenProvider.Path))
                {
                    var arguments = $"{ResourceArgumentName} {resource} ";

                    if (tenant != default)
                    {
                        arguments += $"{TenantArgumentName} {tenant} ";
                    }

                    // Add the arguments set in the token provider file.
                    if (tokenProvider.Arguments?.Count > 0)
                    {
                        arguments += string.Join(" ", tokenProvider.Arguments);
                    }

                    var startInfo = new ProcessStartInfo
                    {
                        FileName  = tokenProvider.Path,
                        Arguments = arguments
                    };

                    processStartInfos.Add(startInfo);
                }
            }

            return(processStartInfos);
        }
예제 #2
0
 internal VisualStudioAccessTokenProvider(
     IProcessManager processManager,
     VisualStudioTokenProviderFile visualStudioTokenProviderFile = null)
 {
     _visualStudioTokenProviderFile = visualStudioTokenProviderFile;
     _processManager = processManager;
     PrincipalUsed   = new Principal {
         Type = "User"
     };
 }
예제 #3
0
        /// <summary>
        /// Gets the token provider file from user's local appdata folder.
        /// </summary>
        /// <returns></returns>
        private VisualStudioTokenProviderFile GetTokenProviderFile()
        {
            if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(LocalAppDataPathEnv)))
            {
                throw new Exception(NoAppDataEnvironmentVariableError);
            }

            var tokenProviderPath = Path.Combine(Environment.GetEnvironmentVariable(LocalAppDataPathEnv),
                                                 TokenProviderFilePath);

            if (!File.Exists(tokenProviderPath))
            {
                throw new Exception($"{TokenProviderFileNotFound} \"{tokenProviderPath}\"");
            }

            return(VisualStudioTokenProviderFile.Parse(File.ReadAllText(tokenProviderPath)));
        }
예제 #4
0
        public async Task <AuthenticationToken> GetAuthResultAsync(string resource, string authority)
        {
            try
            {
                // Validate resource, since it gets sent as a command line argument to Visual Studio token provider.
                ValidationHelper.ValidateResource(resource);

                _visualStudioTokenProviderFile = _visualStudioTokenProviderFile ?? GetTokenProviderFile();

                // Get process start infos based on Visual Studio token providers
                var processStartInfos = GetProcessStartInfos(_visualStudioTokenProviderFile, resource, UriHelper.GetTenantByAuthority(authority));

                // To hold reason why token could not be acquired per token provider tried.
                var exceptionDictionary = new Dictionary <string, string>();

                foreach (var startInfo in processStartInfos)
                {
                    try
                    {
                        // For each of them, try to get token
                        var response = await _processManager
                                       .ExecuteAsync(new Process { StartInfo = startInfo })
                                       .ConfigureAwait(false);

                        var tokenResponse = TokenResponse.Parse(response);

                        var accessToken = AccessToken.Parse(tokenResponse.AccessToken);

                        PrincipalUsed.IsAuthenticated = true;

                        if (accessToken != null)
                        {
                            // Set principal used based on the claims in the access token.
                            PrincipalUsed.UserPrincipalName =
                                !string.IsNullOrEmpty(accessToken.Upn) ? accessToken.Upn : accessToken.Email;

                            PrincipalUsed.TenantId = accessToken.TenantId;
                        }

                        var authResult = Models.AppAuthenticationResult.Create(tokenResponse, TokenResponse.DateFormat.DateTimeString);

                        var authenticationToken = new AuthenticationToken
                        {
                            AccessToken  = authResult.AccessToken,
                            TokenType    = authResult.TokenType,
                            Resource     = authResult.Resource,
                            ExpiresOn    = tokenResponse.ExpiresOn,
                            ExpiresIn    = accessToken.ExpiryTime.ToString(),
                            ExtExpiresIn = accessToken.ExpiryTime.ToString(),
                            RefreshToken = tokenResponse.AccessToken,
                        };

                        return(authenticationToken);
                    }
                    catch (Exception exp)
                    {
                        // If token cannot be acquired using a token provider, try the next one
                        exceptionDictionary[Path.GetFileName(startInfo.FileName)] = exp.Message;
                    }
                }

                // Could not acquire access token, throw exception
                var message = string.Empty;

                // Include exception details for each token provider that was tried
                foreach (var key in exceptionDictionary.Keys)
                {
                    message += Environment.NewLine +
                               $"Exception for Visual Studio token provider {key} : {exceptionDictionary[key]} ";
                }

                // Throw exception if none of the token providers worked
                throw new Exception(message);
            }
            catch (Exception exp)
            {
                throw new Exception(
                          $"{nameof(VisualStudioAccessTokenProvider)} not able to obtain the token for {ConnectionString} , {resource} , {authority}, {exp.Message}");
            }
        }