Ejemplo n.º 1
0
        private async Task <MsalTokenResponse> SendHttpAndClearTelemetryAsync(string tokenEndpoint, Core.ICoreLogger logger)
        {
            UriBuilder builder = new UriBuilder(tokenEndpoint);

            builder.AppendQueryParameters(_requestParams.ExtraQueryParameters);
            Uri tokenEndpointWithQueryParams = builder.Uri;

            try
            {
                logger.Verbose("[Token Client] Fetching MsalTokenResponse .... ");
                MsalTokenResponse msalTokenResponse =
                    await _oAuth2Client
                    .GetTokenAsync(tokenEndpointWithQueryParams,
                                   _requestParams.RequestContext, true, _requestParams.OnBeforeTokenRequestHandler)
                    .ConfigureAwait(false);

                // Clear failed telemetry data as we've just sent it
                _serviceBundle.HttpTelemetryManager.ResetPreviousUnsentData();

                return(msalTokenResponse);
            }
            catch (MsalServiceException ex)
            {
                if (!ex.IsAadUnavailable())
                {
                    // Clear failed telemetry data as we've just sent it ...
                    // even if we received an error from the server,
                    // telemetry would have been recorded
                    _serviceBundle.HttpTelemetryManager.ResetPreviousUnsentData();
                }

                if (ex.StatusCode == (int)HttpStatusCode.Unauthorized)
                {
                    string responseHeader = string.Empty;
                    var    isChallenge    = _serviceBundle.DeviceAuthManager.TryCreateDeviceAuthChallengeResponse(
                        ex.Headers,
                        new Uri(tokenEndpoint), // do not add query params to PKeyAuth https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/2359
                        out responseHeader);
                    if (isChallenge)
                    {
                        //Injecting PKeyAuth response here and replaying request to attempt device auth
                        _oAuth2Client.AddHeader("Authorization", responseHeader);

                        return(await _oAuth2Client.GetTokenAsync(
                                   tokenEndpointWithQueryParams,
                                   _requestParams.RequestContext,
                                   false, _requestParams.OnBeforeTokenRequestHandler).ConfigureAwait(false));
                    }
                }

                throw;
            }
            finally
            {
                _requestInProgress = false;
            }
        }
Ejemplo n.º 2
0
        private async Task <MsalTokenResponse> SendHttpAndClearTelemetryAsync(string tokenEndpoint)
        {
            UriBuilder builder = new UriBuilder(tokenEndpoint);

            try
            {
                builder.AppendQueryParameters(_requestParams.ExtraQueryParameters);

                MsalTokenResponse msalTokenResponse =
                    await _oAuth2Client
                    .GetTokenAsync(builder.Uri,
                                   _requestParams.RequestContext)
                    .ConfigureAwait(false);

                // Clear failed telemetry data as we've just sent it
                _serviceBundle.HttpTelemetryManager.ResetPreviousUnsentData();

                return(msalTokenResponse);
            }
            catch (MsalServiceException ex)
            {
                if (!ex.IsAadUnavailable())
                {
                    // Clear failed telemetry data as we've just sent it ...
                    // even if we received an error from the server,
                    // telemetry would have been recorded
                    _serviceBundle.HttpTelemetryManager.ResetPreviousUnsentData();
                }

                if (ex.StatusCode == (int)HttpStatusCode.Unauthorized)
                {
                    string responseHeader = string.Empty;
                    var    isChallenge    = _serviceBundle.DeviceAuthManager.TryCreateDeviceAuthChallengeResponseAsync(ex.Headers, builder.Uri, out responseHeader);
                    if (isChallenge)
                    {
                        //Injecting PKeyAuth response here and replaying request to attempt device auth
                        _oAuth2Client.AddHeader("Authorization", responseHeader);

                        return(await _oAuth2Client.GetTokenAsync(builder.Uri, _requestParams.RequestContext, false).ConfigureAwait(false));
                    }
                }

                throw;
            }
            finally
            {
                _requestInProgress = false;
            }
        }
Ejemplo n.º 3
0
        private static MsalServiceException ExtractErrorsFromTheResponse(HttpResponse response, ref bool shouldLogAsError)
        {
            // In cases where the end-point is not found (404) response.body will be empty.
            if (string.IsNullOrWhiteSpace(response.Body))
            {
                return(null);
            }

            MsalTokenResponse msalTokenResponse = null;

            try
            {
                msalTokenResponse = JsonHelper.DeserializeFromJson <MsalTokenResponse>(response.Body);
            }
            catch (JsonException)
            {
                //Throttled responses for client credential flows do not have a parsable response.
                if ((int)response.StatusCode == 429)
                {
                    return(MsalServiceExceptionFactory.FromThrottledAuthenticationResponse(response));
                }

                throw;
            }

            if (msalTokenResponse?.Error == null)
            {
                return(null);
            }

            // For device code flow, AuthorizationPending can occur a lot while waiting
            // for the user to auth via browser and this causes a lot of error noise in the logs.
            // So suppress this particular case to an Info so we still see the data but don't
            // log it as an error since it's expected behavior while waiting for the user.
            if (string.Compare(msalTokenResponse.Error, OAuth2Error.AuthorizationPending,
                               StringComparison.OrdinalIgnoreCase) == 0)
            {
                shouldLogAsError = false;
            }

            return(MsalServiceExceptionFactory.FromHttpResponse(
                       msalTokenResponse.Error,
                       msalTokenResponse.ErrorDescription,
                       response));
        }
        private async Task <MsalTokenResponse> SendHttpMessageAsync(string tokenEndpoint)
        {
            UriBuilder builder = new UriBuilder(tokenEndpoint);

            builder.AppendQueryParameters(_requestParams.ExtraQueryParameters);
            MsalTokenResponse msalTokenResponse =
                await _oAuth2Client
                .GetTokenAsync(builder.Uri,
                               _requestParams.RequestContext)
                .ConfigureAwait(false);

            if (string.IsNullOrEmpty(msalTokenResponse.Scope))
            {
                msalTokenResponse.Scope = _requestParams.Scope.AsSingleString();
                _requestParams.RequestContext.Logger.Info("ScopeSet was missing from the token response, so using developer provided scopes in the result. ");
            }

            return(msalTokenResponse);
        }
        internal static MsalTokenResponse CreateFromAppProviderResponse(TokenProviderResult tokenProviderResponse)
        {
            ValidateTokenProviderResult(tokenProviderResponse);

            var response = new MsalTokenResponse
            {
                AccessToken  = tokenProviderResponse.AccessToken,
                RefreshToken = null,
                IdToken      = null,
                TokenType    = BrokerResponseConst.Bearer,
                ExpiresIn    = tokenProviderResponse.ExpiresInSeconds,
                ClientInfo   = null,
                TokenSource  = TokenSource.IdentityProvider,
                TenantId     = null //Leaving as null so MSAL can use the original request Tid. This is ok for confidential client scenarios
            };

            response.RefreshIn = tokenProviderResponse.RefreshInSeconds;

            return(response);
        }
        /// <remarks>
        /// This method does not belong here - it is more tied to the Android code. However, that code is
        /// not unit testable, and this one is.
        /// The values of the JSON response are based on
        /// https://github.com/AzureAD/microsoft-authentication-library-common-for-android/blob/dev/common/src/main/java/com/microsoft/identity/common/internal/broker/BrokerResult.java
        /// </remarks>
        internal static MsalTokenResponse CreateFromAndroidBrokerResponse(string jsonResponse, string correlationId)
        {
            JObject authResult = JObject.Parse(jsonResponse);
            var     errorCode  = authResult[BrokerResponseConst.BrokerErrorCode]?.ToString();

            if (!string.IsNullOrEmpty(errorCode))
            {
                return(new MsalTokenResponse
                {
                    Error = errorCode,
                    ErrorDescription = authResult[BrokerResponseConst.BrokerErrorMessage]?.ToString(),
                    AuthorityUrl = authResult[BrokerResponseConst.Authority]?.ToString(),
                    TenantId = authResult[BrokerResponseConst.TenantId]?.ToString(),
                    Upn = authResult[BrokerResponseConst.UserName]?.ToString(),
                    AccountUserId = authResult[BrokerResponseConst.LocalAccountId]?.ToString(),
                });
            }

            MsalTokenResponse msalTokenResponse = new MsalTokenResponse()
            {
                AccessToken       = authResult[BrokerResponseConst.AccessToken].ToString(),
                IdToken           = authResult[BrokerResponseConst.IdToken].ToString(),
                CorrelationId     = correlationId,                                            // Android response does not expose Correlation ID
                Scope             = authResult[BrokerResponseConst.AndroidScopes].ToString(), // sadly for iOS this is "scope" and for Android "scopes"
                ExpiresIn         = DateTimeHelpers.GetDurationFromNowInSeconds(authResult[BrokerResponseConst.ExpiresOn].ToString()),
                ExtendedExpiresIn = DateTimeHelpers.GetDurationFromNowInSeconds(authResult[BrokerResponseConst.ExtendedExpiresOn].ToString()),
                ClientInfo        = authResult[BrokerResponseConst.ClientInfo].ToString(),
                TokenType         = authResult[BrokerResponseConst.TokenType]?.ToString() ?? "Bearer",
                TokenSource       = TokenSource.Broker,
                AuthorityUrl      = authResult[BrokerResponseConst.Authority]?.ToString(),
                TenantId          = authResult[BrokerResponseConst.TenantId]?.ToString(),
                Upn           = authResult[BrokerResponseConst.UserName]?.ToString(),
                AccountUserId = authResult[BrokerResponseConst.LocalAccountId]?.ToString(),
            };

            return(msalTokenResponse);
        }
        public async Task <MsalTokenResponse> SendTokenRequestAsync(
            IDictionary <string, string> additionalBodyParameters,
            string scopeOverride                = null,
            string tokenEndpointOverride        = null,
            CancellationToken cancellationToken = default)
        {
            string tokenEndpoint = tokenEndpointOverride ?? _requestParams.Endpoints.TokenEndpoint;
            string scopes        = !string.IsNullOrEmpty(scopeOverride) ? scopeOverride : GetDefaultScopes(_requestParams.Scope);

            AddBodyParamsAndHeaders(additionalBodyParameters, scopes);

            MsalTokenResponse response = await SendHttpAndClearTelemetryAsync(tokenEndpoint)
                                         .ConfigureAwait(false);


            if (string.IsNullOrEmpty(response.Scope))
            {
                response.Scope = _requestParams.Scope.AsSingleString();
                _requestParams.RequestContext.Logger.Info(
                    "ScopeSet was missing from the token response, so using developer provided scopes in the result. ");
            }

            if (!string.IsNullOrEmpty(response.TokenType) &&
                !string.Equals(
                    response.TokenType,
                    _requestParams.AuthenticationScheme.AccessTokenType,
                    StringComparison.OrdinalIgnoreCase))
            {
                throw new MsalClientException(
                          MsalError.TokenTypeMismatch,
                          MsalErrorMessage.TokenTypeMismatch(
                              _requestParams.AuthenticationScheme.AccessTokenType,
                              response.TokenType));
            }

            return(response);
        }
        public async Task <MsalTokenResponse> SendTokenRequestAsync(
            IDictionary <string, string> additionalBodyParameters,
            string scopeOverride                = null,
            string tokenEndpointOverride        = null,
            CancellationToken cancellationToken = default)
        {
            string tokenEndpoint = tokenEndpointOverride ?? _requestParams.Endpoints.TokenEndpoint;
            string scopes        = !string.IsNullOrEmpty(scopeOverride) ? scopeOverride: GetDefaultScopes(_requestParams.Scope);

            _oAuth2Client.AddBodyParameter(OAuth2Parameter.ClientId, _requestParams.ClientId);
            _oAuth2Client.AddBodyParameter(OAuth2Parameter.ClientInfo, "1");


#if DESKTOP || NETSTANDARD1_3 || NET_CORE
            if (_requestParams.ClientCredential != null)
            {
                Dictionary <string, string> ccBodyParameters = ClientCredentialHelper.CreateClientCredentialBodyParameters(
                    _requestParams.RequestContext.Logger,
                    _serviceBundle.PlatformProxy.CryptographyManager,
                    _requestParams.ClientCredential,
                    _requestParams.ClientId,
                    _requestParams.Endpoints,
                    _requestParams.SendX5C);

                foreach (var entry in ccBodyParameters)
                {
                    _oAuth2Client.AddBodyParameter(entry.Key, entry.Value);
                }
            }
#endif

            _oAuth2Client.AddBodyParameter(OAuth2Parameter.Scope, scopes);
            _oAuth2Client.AddBodyParameter(OAuth2Parameter.Claims, _requestParams.ClaimsAndClientCapabilities);

            foreach (var kvp in additionalBodyParameters)
            {
                _oAuth2Client.AddBodyParameter(kvp.Key, kvp.Value);
            }

            foreach (var kvp in _requestParams.AuthenticationScheme.GetTokenRequestParams())
            {
                _oAuth2Client.AddBodyParameter(kvp.Key, kvp.Value);
            }

            MsalTokenResponse response = await SendHttpMessageAsync(tokenEndpoint)
                                         .ConfigureAwait(false);

            if (!string.Equals(
                    response.TokenType,
                    _requestParams.AuthenticationScheme.AccessTokenType,
                    StringComparison.OrdinalIgnoreCase))
            {
                throw new MsalClientException(
                          MsalError.TokenTypeMismatch,
                          MsalErrorMessage.TokenTypeMismatch(
                              _requestParams.AuthenticationScheme.AccessTokenType,
                              response.TokenType));
            }

            return(response);
        }