Example #1
0
        internal static async Task <MobileConnectStatus> RequestToken(IAuthentication authentication, DiscoveryResponse discoveryResponse, Uri redirectedUrl, string expectedState, string expectedNonce, MobileConnectConfig config)
        {
            RequestTokenResponse response;

            if (string.IsNullOrEmpty(expectedState))
            {
                return(MobileConnectStatus.Error("required_arg_missing", "ExpectedState argument was not supplied, this is needed to prevent Cross-Site Request Forgery", null));
            }

            if (string.IsNullOrEmpty(expectedNonce))
            {
                return(MobileConnectStatus.Error("required_arg_missing", "expectedNonce argument was not supplied, this is needed to prevent Replay Attacks", null));
            }

            var actualState = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "state");

            if (expectedState != actualState)
            {
                return(MobileConnectStatus.Error("invalid_state", "State values do not match, this could suggest an attempted Cross-Site Request Forgery", null));
            }

            try
            {
                var code            = HttpUtils.ExtractQueryValue(redirectedUrl.Query, "code");
                var clientId        = discoveryResponse?.ResponseData?.response?.client_id ?? config.ClientId;
                var clientSecret    = discoveryResponse?.ResponseData?.response?.client_secret ?? config.ClientSecret;
                var requestTokenUrl = discoveryResponse?.OperatorUrls?.RequestTokenUrl;
                response = await authentication.RequestTokenAsync(clientId, clientSecret, requestTokenUrl, config.RedirectUrl, code);

                if (response.ErrorResponse != null)
                {
                    return(MobileConnectStatus.Error(response.ErrorResponse.Error, response.ErrorResponse.ErrorDescription, null, response));
                }

                if (!Validation.IsExpectedNonce(response.ResponseData.IdToken, expectedNonce))
                {
                    return(MobileConnectStatus.Error("invalid_nonce", "Nonce values do not match, this could suggest an attempted Replay Attack", null));
                }
            }
            catch (MobileConnectInvalidArgumentException e)
            {
                return(MobileConnectStatus.Error("invalid_argument", string.Format("An argument was found to be invalid during the process. The argument was {0}.", e.Argument), e));
            }
            catch (MobileConnectEndpointHttpException e)
            {
                return(MobileConnectStatus.Error("http_failure", "An HTTP failure occured while calling the operator token endpoint, the endpoint may be inaccessible", e));
            }
            catch (Exception e)
            {
                return(MobileConnectStatus.Error("unknown_error", "A failure occured while requesting a token", e));
            }

            return(MobileConnectStatus.Complete(response));
        }
        internal static async Task <MobileConnectStatus> RefreshToken(IAuthenticationService authentication, string refreshToken, DiscoveryResponse discoveryResponse, MobileConnectConfig config)
        {
            Validate.RejectNull(discoveryResponse, "discoveryResponse");
            Validate.RejectNullOrEmpty(refreshToken, "refreshToken");

            if (!IsUsableDiscoveryResponse(discoveryResponse))
            {
                return(MobileConnectStatus.StartDiscovery());
            }

            string refreshTokenUrl = discoveryResponse.OperatorUrls.RefreshTokenUrl ?? discoveryResponse.OperatorUrls.RequestTokenUrl;

            var notSupported = IsSupported(refreshTokenUrl, "Refresh", discoveryResponse.ProviderMetadata?.Issuer);

            if (notSupported != null)
            {
                return(notSupported);
            }

            string clientId     = discoveryResponse.ResponseData.response.client_id ?? config.ClientId;
            string clientSecret = discoveryResponse.ResponseData.response.client_secret ?? config.ClientSecret;

            try
            {
                RequestTokenResponse requestTokenResponse = await authentication.RefreshTokenAsync(clientId, clientSecret, refreshTokenUrl, refreshToken);

                ErrorResponse errorResponse = requestTokenResponse.ErrorResponse;
                if (errorResponse != null)
                {
                    Log.Error(() => $"Responding with responseType={MobileConnectResponseType.Error} for refreshToken for authentication service responded with error={errorResponse.Error}");
                    return(MobileConnectStatus.Error(errorResponse));
                }
                else
                {
                    Log.Info(() => $"Refresh token success");
                    return(MobileConnectStatus.Complete(requestTokenResponse));
                }
            }
            catch (Exception e)
            {
                Log.Error(() => $"RefreshToken failed", e);
                return(MobileConnectStatus.Error(ErrorCodes.Unknown, "Refresh token error", e));
            }
        }
        private static MobileConnectStatus HandleTokenResponse(IAuthenticationService authentication, RequestTokenResponse response, string clientId, string issuer, string expectedNonce,
                                                               string version, JWKeyset jwks, MobileConnectRequestOptions options)
        {
            if (response.ErrorResponse != null)
            {
                return(MobileConnectStatus.Error(response.ErrorResponse.Error, response.ErrorResponse.ErrorDescription, null, response));
            }

            response.ValidationResult = authentication.ValidateTokenResponse(response, clientId, issuer, expectedNonce, options?.MaxAge, jwks, version);
            var validationOptions = options?.TokenValidationOptions ?? new TokenValidationOptions();

            if (!validationOptions.AcceptedValidationResults.HasFlag(response.ValidationResult))
            {
                Log.Error(() => $"A generated tokenResponse was invalid issuer={issuer} version={version} result={response.ValidationResult}");
                return(MobileConnectStatus.Error(ErrorCodes.InvalidToken, $"The token was found to be invalid with the validation result {response.ValidationResult}", null, response));
            }
            else if (response.ValidationResult != TokenValidationResult.Valid)
            {
                Log.Warning(() => $"A generated tokenResponse was invalid but accepted issuer={issuer} version={version} result={response.ValidationResult}");
            }

            return(MobileConnectStatus.Complete(response));
        }