Beispiel #1
0
        /// <summary>
        /// Utility method for converting an ADAL <see cref="MsiAuthResult"/> into an <see cref="SdkAuthResult"/>.
        /// </summary>
        /// <param name="authenticationResult">The <see cref="MsiAuthResult"/></param>
        /// <returns>An <see cref="SdkAuthResult"/>.</returns>
        private static SdkAuthResult ToSdkAuthResult(this MsiAuthResult authenticationResult)
        {
            // Use a temporary variable to manipulate the access token
            string accessToken = authenticationResult.AccessToken;

            // Pad the access token with '=' until it's length is divisible by 4
            accessToken += Enumerable.Repeat('=', 4 - (accessToken.Length % 4));

            // Replace invalid characters
            accessToken = accessToken
                          .Replace('-', '+')
                          .Replace('_', '/');

            // Convert from base64 to a string
            string decodedAccessToken = Encoding.ASCII.GetString(Convert.FromBase64String(accessToken));

            // Convert to an object so we can extract values
            JToken deserializedAccessToken = JToken.Parse(decodedAccessToken);

            // Extract the user data
            string uniqueUserId = deserializedAccessToken["unique_name"]?.Value <string>();
            string tenantId     = deserializedAccessToken["tid"]?.Value <string>();

            // TODO: Validate access token by checking its signature

            // Build and return the result
            return(new SdkAuthResult(
                       accessTokenType: authenticationResult.AccessTokenType,
                       accessToken: authenticationResult.AccessToken,
                       userId: null,
                       expiresOn: authenticationResult.ExpiresOn,
                       psUserDisplayableInformation: new
            {
                UPN = uniqueUserId,
                TenantId = tenantId,
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Refreshes the access token using MSI auth if required, otherwise returns the most recent still-valid refresh token.
        /// </summary>
        /// <returns>A valid access token.</returns>
        /// <exception cref="MsiAuthException">If the login attempt fails</exception>
        internal static SdkAuthResult RefreshMsiAuth()
        {
            // Get the environment parameters
            EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters;

            // Create auth context that we will use to connect to the AAD endpoint
            AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl);

            SdkAuthResult authResult = AuthUtils.LatestMsiAuthResult;

            if (authResult == null || authResult.IsExpired)
            {
                // Create the HTTP client
                using (HttpClient client = new HttpClient())
                {
                    // Add the "Metadata:true" header
                    client.DefaultRequestHeaders.Add("Metadata", "true");

                    // Make the request for the desired resource
                    HttpResponseMessage response = client
                                                   .GetAsync($"{AuthUtils.ManagedServiceIdentityEndpoint}?resource={environmentParameters.ResourceId}")
                                                   .GetAwaiter().GetResult();

                    // Make sure we successfully retrieved the result
                    if (!response.IsSuccessStatusCode)
                    {
                        // Extract the error code and error message from the failure response
                        string errorCode;
                        string errorMessage;
                        try
                        {
                            // Get the content of the failure response
                            string errorJsonString = response.Content.ReadAsStringAsync()
                                                     .GetAwaiter().GetResult();
                            JToken errorJson = JToken.Parse(errorJsonString)["error"]?.Value <JToken>();

                            // Extract error code and error message
                            errorCode    = errorJson["code"].Value <string>() ?? string.Empty;
                            errorMessage = errorJson["message"].Value <string>() ?? string.Empty;
                        }
                        catch (Exception ex)
                        {
                            throw new MsiAuthException("Unable to authenticate using MSI", ex);
                        }

                        // Build the exception message
                        string exceptionMessage;
                        if (!string.IsNullOrWhiteSpace(errorMessage))
                        {
                            exceptionMessage = errorMessage;
                        }
                        else
                        {
                            exceptionMessage = "Unknown MSI authentication error";
                        }

                        if (!string.IsNullOrWhiteSpace(errorCode))
                        {
                            exceptionMessage = $"{errorCode}: {exceptionMessage}";
                        }

                        // Throw the exception
                        throw new MsiAuthException(exceptionMessage);
                    }

                    // Convert the response from JSON into an object
                    MsiAuthResult msiResult = JsonConvert.DeserializeObject <MsiAuthResult>(response.Content.ReadAsStringAsync()
                                                                                            .GetAwaiter().GetResult());

                    // Convert the MSI auth result to our own type
                    authResult = msiResult.ToSdkAuthResult();
                }
            }

            return(authResult);
        }