Esempio n. 1
0
        public async Task <int> GetAsync()
        {
            var tokenExchangeRequest = new TokenExchangeRequest(17076, "bf9a1dbc8f516d9d9293eb29db56bfc9165b670d", "0bcaba6ad698d5787622c3e06ea0531c19c663b5");
            var result = await _stravaManager.ExchangeTokenAsync(tokenExchangeRequest);

            return(1);
        }
Esempio n. 2
0
        public void TokenExchangeRequestInitsWithNoArgs()
        {
            var tokenExchangeRequest = new TokenExchangeRequest();

            Assert.NotNull(tokenExchangeRequest);
            Assert.IsType <TokenExchangeRequest>(tokenExchangeRequest);
        }
Esempio n. 3
0
        public async Task <TokenExchangeResponse> ExchangeTokenAsync(TokenExchangeRequest request)
        {
            var result = await _stravaHttpClient.PostStravaRequest <TokenExchangeResponse>(request);

            await TestStravaSharp(result.Athlete.id, result.access_token);

            return(result);
        }
        public void AddGraphTypeFields(QueryCore queryCore)
        {
            queryCore.FieldAsync <ListGraphType <TokenExchangeResponseType> >(name: "tokenExchange",
                                                                              description: $"Given a proper list of OAuth2 Tokens, returns an authorization payload for downstream authorized calls.",
                                                                              arguments: new QueryArguments(new QueryArgument <NonNullGraphType <TokenExchangeInput> > {
                Name = "input"
            }),
                                                                              resolve: async context =>
            {
                try
                {
                    var graphQLUserContext = context.UserContext as GraphQLUserContext;


                    _summaryLogger.Add("query", "bind");
                    var input = context.GetArgument <BindInputModel>("input");

                    if (input.Tokens == null || input.Tokens.Count == 0)
                    {
                        throw new Exception("no tokens present in the request!");
                    }
                    var requestedFields = (from item in context.SubFields
                                           select item.Key).ToList();

                    var summaryLog = string.Join(";", _summaryLogger.Select(x => x.Key + "=" + x.Value).ToArray());


                    _summaryLogger.Add("requestedFields", string.Join(" ", requestedFields));

                    var tokens = (from item in input.Tokens
                                  let c = new TokenWithScheme()
                    {
                        Token = item.Token,
                        TokenScheme = item.TokenScheme
                    }
                                  select c).ToList();

                    var tokenExchangeRequest = new TokenExchangeRequest()
                    {
                        Tokens = tokens,
                        Extras = input.Extras
                    };
                    var tokenExchangeResponse = await _tokenExchangeHandlerRouter.ProcessExchangeAsync(input.Exchange, tokenExchangeRequest);

                    return(tokenExchangeResponse);
                }
                catch (Exception e)
                {
                    _summaryLogger.Add("exception", e.Message);
                    context.Errors.Add(new ExecutionError("Unable to process request", e));
                }

                return(null);
            },
                                                                              deprecationReason: null);
        }
Esempio n. 5
0
        public void TokenExchangeRequestInits()
        {
            var uri   = "http://example.com";
            var token = "token";

            var tokenExchangeRequest = new TokenExchangeRequest(uri, token);

            Assert.NotNull(tokenExchangeRequest);
            Assert.IsType <TokenExchangeRequest>(tokenExchangeRequest);
            Assert.Equal(uri, tokenExchangeRequest.Uri);
            Assert.Equal(token, tokenExchangeRequest.Token);
        }
        public async Task ExchangeTokenAsyncWithNullConnectionNameShouldThrow()
        {
            var credentials = new TestCredentials();

            var userToken = new UserTokenClientImpl(AppId, credentials, OauthEndpoint, null, null);

            var tokenExchange = new TokenExchangeRequest();

            await Assert.ThrowsAsync <ArgumentNullException>(async() =>
            {
                await userToken.ExchangeTokenAsync(UserId, null, ChannelId, tokenExchange, CancellationToken.None);
            });
        }
Esempio n. 7
0
        public async Task <Client> InitializeStravaClientAsync(TokenExchangeRequest request)
        {
            if (_stravaClient != null)
            {
                return(_stravaClient);
            }
            var result = await _stravaHttpClient.PostStravaRequest <TokenExchangeResponse>(request);

            _authenticatedAthleteId = result.Athlete.id;
            var stravaAuthenticator = new StravaAuthenticator(result.access_token);

            _stravaClient = new Client(stravaAuthenticator);
            return(_stravaClient);
        }
        public Task <List <KeyValuePair <string, string> > > ProcessAsync(ref TokenExchangeRequest tokenExchangeRequest)
        {
            var header  = new JwtHeader();
            var handler = new JwtSecurityTokenHandler();

            foreach (var tokenWithScheme in tokenExchangeRequest.Tokens)
            {
                var token = handler.ReadJwtToken(tokenWithScheme.Token);
                var unsignedSecurityToken = new JwtSecurityToken(header, token.Payload);
                tokenWithScheme.Token = handler.WriteToken(unsignedSecurityToken);
            }

            return(Task.FromResult(new List <KeyValuePair <string, string> >()));
        }
        public async Task ExchangeTokenAsyncOfDisposedTokenShouldThrow()
        {
            var credentials = new TestCredentials();

            var userToken = new UserTokenClientImpl(AppId, credentials, OauthEndpoint, null, null);

            var tokenExchange = new TokenExchangeRequest();

            userToken.Dispose();

            await Assert.ThrowsAsync <ObjectDisposedException>(async() =>
            {
                await userToken.ExchangeTokenAsync(UserId, ConnectionName, ChannelId, tokenExchange, CancellationToken.None);
            });
        }
Esempio n. 10
0
        public async Task CreateTokenAsync_WhenUserWithNotValidPassword_ReturnsIncorrectCredentials()
        {
            var request = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "*****@*****.**"
            };

            var httpResponse = await PostAsync(AuthControllerRoutes.TokenExchange, request);

            httpResponse.EnsureSuccessStatusCode();
            var response = await httpResponse.BodyAs <AuthResponse>();

            response.Message.Should().Be($"Incorrect Credentials for user {request.Email}.");
        }
Esempio n. 11
0
        public async Task CreateTokenAsync_WhenUserIsLockedOut_ReturnsAccountLockOut()
        {
            var request = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "*****@*****.**"
            };

            var httpResponse = await PostAsync(AuthControllerRoutes.TokenExchange, request);

            httpResponse.EnsureSuccessStatusCode();
            var response = await httpResponse.BodyAs <AuthResponse>();

            response.Message.Should().Be($"This account has been locked.");
        }
Esempio n. 12
0
        public async Task CreateTokenAsync_WhenEmailNotConfirmed_ReturnsNoAccountsRegisteredWithCurrentEmail()
        {
            var request = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "*****@*****.**"
            };

            var httpResponse = await PostAsync(AuthControllerRoutes.TokenExchange, request);

            httpResponse.EnsureSuccessStatusCode();
            var response = await httpResponse.BodyAs <AuthResponse>();

            response.Message.Should().Be($"Current email {request.Email} is not confirmed.");
        }
Esempio n. 13
0
        public async Task CreateTokenAsync_WhenCodeNotValid_ReturnsNoAccountsRegisteredWithCurrentEmail()
        {
            var request = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "*****@*****.**"
            };

            var httpResponse = await PostAsync(AuthControllerRoutes.TokenExchange, request);

            httpResponse.EnsureSuccessStatusCode();
            var response = await httpResponse.BodyAs <AuthResponse>();

            response.Message.Should().Be($"No Accounts Registered with {request.Email}.");
        }
        public async Task LoginAsync_WhenUserNotFound_ShouldReturnAuthResponseWithMessage()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync((User)null);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            response.Message.Should().Be($"No Accounts Registered with {tokenExchangeRequest.Email}.");
        }
Esempio n. 15
0
        public async Task <AuthResponse> LoginAsync(TokenExchangeRequest request)
        {
            var user = await _userManager.FindByEmailAsync(request.Email);

            if (user == null)
            {
                return(new AuthResponse()
                {
                    Message = $"No Accounts Registered with {request.Email}.",
                });
            }
            // Only allow login if email is confirmed
            if (!user.EmailConfirmed)
            {
                return(new AuthResponse()
                {
                    Message = $"Current email {request.Email} is not confirmed.",
                });
            }
            // Used as user lock
            if (user.LockoutEnd != null && user.LockoutEnd >= DateTimeOffset.UtcNow)
            {
                return(new AuthResponse()
                {
                    Message = $"This account has been locked.",
                });
            }

            if (!await _userManager.CheckPasswordAsync(user, request.Password))
            {
                return(new AuthResponse()
                {
                    Message = $"Incorrect Credentials for user {user.Email}.",
                });
            }

            var jwtSecurityToken = await _jwtFactory.GenerateEncodedAccessToken(user);

            var activeRefreshToken = user.RefreshTokens.FirstOrDefault(e => e.IsActive);

            if (activeRefreshToken != null)
            {
                return(new AuthResponse()
                {
                    RefreshToken = activeRefreshToken !.Token,
                    ExpiredAt = (activeRefreshToken.Expires - DateTimeOffset.UtcNow).Seconds,
                    Token = jwtSecurityToken.Token,
                });
        public async Task LoginAsync_WhenUserEmailNotConfirmed_ShouldReturnAuthResponseWithMessage()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };
            var user = Fixture.Build <User>().With(w => w.EmailConfirmed, false).Create();

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync(user);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            response.Message.Should().Be($"Current email {tokenExchangeRequest.Email} is not confirmed.");
        }
        public async Task <int> GetAsync()
        {
            try
            {
                var auth = _settingsRepository.CurrentSettings.DefaultStravaClientAuth;
                var tokenExchangeRequest = new TokenExchangeRequest(auth.ClientId, auth.ClientSecret, auth.Code);
                var result = await _stravaManager.ExchangeTokenAsync(tokenExchangeRequest);

                return(1);
            }
            catch (Exception exc)
            {
                _logger.Error(exc, "Error while getting load athlete data.");
                return(0);
            }
        }
Esempio n. 18
0
        public async Task <List <TokenExchangeResponse> > ProcessExchangeAsync(TokenExchangeRequest tokenExchangeRequest)
        {
            if (await _pipelineTokenExchangeHandlerRouter.PipelineTokenExchangeHandlerExistsAsync(_pipelineExchangeRecord
                                                                                                  .FinalExchange))
            {
                Dictionary <string, List <KeyValuePair <string, string> > > mapOpaqueKeyValuePairs =
                    new Dictionary <string, List <KeyValuePair <string, string> > >();
                if (_pipelineExchangeRecord.Preprocessors != null)
                {
                    foreach (var preProcessor in _pipelineExchangeRecord.Preprocessors)
                    {
                        var preProcessorHandler = _tokenExchangeHandlerPreProcessorStore.Get(preProcessor);
                        if (preProcessor == null)
                        {
                            var message = $"The preprocessor:{preProcessor} does not exist!";
                            _logger.LogCritical(message);
                            throw new Exception(message);
                        }

                        _logger.LogInformation($"The preprocessor:{preProcessor} was found!");
                        var opaqueKeyValuePairs = await preProcessorHandler.ProcessAsync(ref tokenExchangeRequest);

                        if (opaqueKeyValuePairs.Any())
                        {
                            mapOpaqueKeyValuePairs.Add(preProcessor, opaqueKeyValuePairs);
                        }
                    }
                }

                _logger.LogInformation($"Forwarding request to finalExchange:{_pipelineExchangeRecord.FinalExchange}!");
                var result = await _pipelineTokenExchangeHandlerRouter.ProcessFinalPipelineExchangeAsync(
                    _pipelineExchangeRecord.FinalExchange,
                    tokenExchangeRequest,
                    mapOpaqueKeyValuePairs);

                _summaryLogger.Add($"pipelineExchange_{_pipelineExchangeRecord.ExchangeName}", "OK");
                return(result);
            }
            else
            {
                var message = $"The finalExchange:{_pipelineExchangeRecord.FinalExchange} does not exist!";
                _logger.LogCritical(message);
                _summaryLogger.Add($"pipelineExchange_{_pipelineExchangeRecord.ExchangeName}", "FATAL");
                throw new Exception(message);
            }
        }
        public Task <List <KeyValuePair <string, string> > > ProcessAsync(ref TokenExchangeRequest tokenExchangeRequest)
        {
            var header  = new JwtHeader();
            var handler = new JwtSecurityTokenHandler();

            foreach (var tokenWithScheme in tokenExchangeRequest.Tokens)
            {
                var principal = _tokenValidator.ValidateTokenAsync(new TokenDescriptor
                {
                    TokenScheme = tokenWithScheme.TokenScheme,
                    Token       = tokenWithScheme.Token
                }).GetAwaiter().GetResult();

                var token = handler.ReadJwtToken(tokenWithScheme.Token);
                var unsignedSecurityToken = new JwtSecurityToken(header, token.Payload);
                tokenWithScheme.Token = handler.WriteToken(unsignedSecurityToken);
            }
            return(Task.FromResult(new List <KeyValuePair <string, string> >()));
        }
        public async Task LoginAsync_WhenUserIsLockedOut_ShouldReturnAuthResponseWithMessage()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };
            var user = Fixture.Build <User>().
                       With(w => w.EmailConfirmed, true).
                       With(w => w.LockoutEnd, DateTimeOffset.MaxValue).
                       Create();

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync(user);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            response.Message.Should().Be($"This account has been locked.");
        }
Esempio n. 21
0
        public async Task <IActionResult> RefreshTokenExchange([FromBody] RefreshExchangeForm form)
        {
            if (!ModelState.IsValid ||
                string.IsNullOrWhiteSpace(form.UserId) ||
                string.IsNullOrWhiteSpace(form.EncodedToken))
            {
                return(BadRequest(ModelState));
            }

            // Convert to Core request.
            var request = new TokenExchangeRequest
            {
                EncodedRefreshToken = form.EncodedToken, UserId = form.UserId
            };

            // submit a request to Core:
            var port    = new BasicPresenter <LoginResponse>();
            var success = await _refreshTokenExchange.Handle(request, port);

            return((success) ? new OkObjectResult(port.Response) : BadRequest());
        }
        public async Task LoginAsync_WhenCheckPasswordAsyncFailed_ShouldReturnAuthResponseWithMessage()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };
            var user = Fixture.Build <User>().
                       With(w => w.EmailConfirmed, true).
                       With(w => w.LockoutEnd, DateTimeOffset.MinValue).
                       Create();

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync(user);
            _mockUserManager.Setup(e => e.CheckPasswordAsync(user, tokenExchangeRequest.Password))
            .ReturnsAsync(false);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            response.Message.Should().Be($"Incorrect Credentials for user {user.Email}.");
        }
        public async Task LoginAsync_WhenUserWithRefreshTokenNotActiveAndUSerUpdatedSuccessfully_ShouldGenerateNewRefreshToken()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };
            var liStOfTokens = Fixture.Build <RefreshToken>()
                               .With(e => e.Expires, DateTimeOffset.MaxValue)
                               .With(e => e.Revoked)
                               .CreateMany().ToList();
            var user = Fixture.Build <User>().
                       With(w => w.EmailConfirmed, true).
                       With(w => w.LockoutEnd, DateTimeOffset.MinValue).
                       With(e => e.RefreshTokens, liStOfTokens).
                       Create();

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync(user);
            _mockUserManager.Setup(e => e.CheckPasswordAsync(user, tokenExchangeRequest.Password))
            .ReturnsAsync(true);
            var token = new JwtAccessToken();

            _mockFactory.Setup(e => e.GenerateEncodedAccessToken(user))
            .ReturnsAsync(token);
            var refreshToken = new RefreshToken();

            _mockFactory.Setup(e => e.GenerateRefreshToken(32))
            .Returns(refreshToken);
            _mockUserManager.Setup(e => e.UpdateAsync(user))
            .ReturnsAsync(IdentityResult.Success);
            _mockRefreshTokenRepository.Setup(e => e.FilterOneAsync(It.IsAny <Expression <Func <RefreshToken, bool> > >()))
            .ReturnsAsync((RefreshToken)null);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            response.RefreshToken.Should().BeEquivalentTo(refreshToken.Token);
            response.Token.Should().BeEquivalentTo(token.Token);
            response.ExpiredAt.Should().Be((refreshToken.Expires - DateTimeOffset.UtcNow).Seconds);
        }
        public async Task LoginAsync_WhenUserWithActiveRefreshTokenPassed_ShouldReturnAuthResponse()
        {
            var tokenExchangeRequest = new TokenExchangeRequest()
            {
                Password = "******",
                Email    = "email",
            };
            var liStOfTokens = Fixture.Build <RefreshToken>()
                               .With(e => e.Expires, DateTimeOffset.MaxValue)
                               .With(e => e.Revoked, (DateTimeOffset?)null)
                               .CreateMany().ToList();
            var user = Fixture.Build <User>().
                       With(w => w.EmailConfirmed, true).
                       With(w => w.LockoutEnd, DateTimeOffset.MinValue).
                       With(e => e.RefreshTokens, liStOfTokens).
                       Create();
            var activeToken = liStOfTokens.FirstOrDefault(e => e.IsActive);

            _mockUserManager.Setup(e => e.FindByEmailAsync(tokenExchangeRequest.Email))
            .ReturnsAsync(user);
            _mockUserManager.Setup(e => e.CheckPasswordAsync(user, tokenExchangeRequest.Password))
            .ReturnsAsync(true);
            var token = new JwtAccessToken();

            _mockFactory.Setup(e => e.GenerateEncodedAccessToken(user))
            .ReturnsAsync(token);
            _mockRefreshTokenRepository.Setup(e => e.FilterOneAsync(It.IsAny <Expression <Func <RefreshToken, bool> > >()))
            .ReturnsAsync(activeToken);

            var response = await sut.LoginAsync(tokenExchangeRequest);

            Debug.Assert(activeToken != null, nameof(activeToken) + " != null");
            response.RefreshToken.Should().BeEquivalentTo(activeToken.Token);
            response.Token.Should().BeEquivalentTo(token.Token);
            response.ExpiredAt.Should().Be((activeToken.Expires - DateTimeOffset.UtcNow).Seconds);
        }
Esempio n. 25
0
        public async Task <List <TokenExchangeResponse> > ProcessExchangeAsync(TokenExchangeRequest tokenExchangeRequest)
        {
            if (tokenExchangeRequest.Extras == null || tokenExchangeRequest.Extras.Count == 0)
            {
                throw new Exception($"{Name}: We require that extras be populated!");
            }

            // for this demo, lets assume all the extras are roles.
            var response = new List <TokenExchangeResponse>();

            for (int i = 0; i < 2; i++)
            {
                var tokenExchangeResponse = new TokenExchangeResponse()
                {
                    accessToken = new AccessTokenResponse()
                    {
                        hint          = "Alien Response",
                        access_token  = $"Alien_access_token_{Guid.NewGuid().ToString()}",
                        refresh_token = $"Alien_refresh_token_{Guid.NewGuid().ToString()}",
                        expires_in    = 1234 + i,
                        token_type    = $"Alien_{Guid.NewGuid().ToString()}",
                        authority     = $"{_httpContextAssessor.HttpContext.Request.Scheme}://{_httpContextAssessor.HttpContext.Request.Host}/Alien",
                        HttpHeaders   = new List <HttpHeader>
                        {
                            new HttpHeader()
                            {
                                Name = "x-authScheme", Value = "Alien"
                            }
                        }
                    }
                };
                response.Add(tokenExchangeResponse);
            }

            return(response);
        }
        public override async Task <TokenResponse> ExchangeTokenAsync(string userId, string connectionName, string channelId, TokenExchangeRequest exchangeRequest, CancellationToken cancellationToken)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(ExchangeTokenAsync));
            }

            _ = userId ?? throw new ArgumentNullException(nameof(userId));
            _ = connectionName ?? throw new ArgumentNullException(nameof(connectionName));

            _logger.LogInformation($"ExchangeAsyncAsync ConnectionName: {connectionName}");
            var result = await _client.ExchangeAsyncAsync(userId, connectionName, channelId, exchangeRequest, cancellationToken).ConfigureAwait(false);

            if (result is ErrorResponse errorResponse)
            {
                throw new InvalidOperationException($"Unable to exchange token: ({errorResponse?.Error?.Code}) {errorResponse?.Error?.Message}");
            }
            else if (result is TokenResponse tokenResponse)
            {
                return(tokenResponse);
            }
            else
            {
                throw new InvalidOperationException($"ExchangeAsyncAsync returned improper result: {result.GetType()}");
            }
        }
Esempio n. 27
0
 public override Task <TokenResponse> ExchangeTokenAsync(string userId, string connectionName, string channelId, TokenExchangeRequest exchangeRequest, CancellationToken cancellationToken)
 {
     Capture(MethodBase.GetCurrentMethod().Name, userId, connectionName, channelId, exchangeRequest);
     return(Task.FromResult(new TokenResponse {
     }));
 }
        public Task <List <TokenExchangeResponse> > PostPassThroughHandlerExchangeAsync(TokenExchangeRequest tokenExchangeRequest)
        {
            var result = new List <TokenExchangeResponse>()
            {
                new TokenExchangeResponse()
                {
                    accessToken = new AccessTokenResponse()
                    {
                        hint          = "briar_rabbit/pass-through-handler",
                        access_token  = $"briar_rabbit_access_token_{Guid.NewGuid().ToString()}",
                        refresh_token = $"briar_rabbit_refresh_token_{Guid.NewGuid().ToString()}",
                        expires_in    = 1234,
                        token_type    = $"briar_rabbit_Type",
                        authority     = $"https://briar.rabbit.com/authority",
                        HttpHeaders   = new List <HttpHeader>
                        {
                            new HttpHeader()
                            {
                                Name  = "x-bunnyAuthScheme",
                                Value = "BunnyAuthority"
                            }
                        }
                    }
                }
            };

            return(Task.FromResult(result));
        }
Esempio n. 29
0
        /// <summary>Exchange with HTTP message.</summary>
        /// <param name='userId'> User ID. </param>
        /// <param name='connectionName'> Connection name. </param>
        /// <param name='channelId'> Channel ID. </param>
        /// <param name='exchangeRequest'> Exechange request. </param>
        /// <param name='customHeaders'> Headers that will be added to request.</param>
        /// <param name='cancellationToken'> The cancellation token. </param>
        /// <exception cref="ErrorResponseException"> Thrown when the operation returned an invalid status code. </exception>
        /// <exception cref="SerializationException"> Thrown when unable to deserialize the response. </exception>
        /// <exception cref="ValidationException"> Thrown when an input value does not match the expected data type, range or pattern. </exception>
        /// <exception cref="System.ArgumentNullException"> Thrown when a required parameter is null. </exception>
        /// <return> A response object containing the response body and response headers. </return>
        /// <returns> A task that represents the work queued to execute.</returns>
        public async Task <HttpOperationResponse <object> > ExchangeAsyncWithHttpMessagesAsync(string userId, string connectionName, string channelId, TokenExchangeRequest exchangeRequest, Dictionary <string, List <string> > customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (userId == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "userId");
            }

            if (connectionName == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "connectionName");
            }

            if (channelId == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "channelId");
            }

            if (exchangeRequest == null)
            {
                throw new ValidationException(ValidationRules.CannotBeNull, "exchangeRequest");
            }

            // Tracing
            bool   shouldTrace  = ServiceClientTracing.IsEnabled;
            string invocationId = null;

            if (shouldTrace)
            {
                invocationId = ServiceClientTracing.NextInvocationId.ToString(CultureInfo.InvariantCulture);
                Dictionary <string, object> tracingParameters = new Dictionary <string, object>();
                tracingParameters.Add("userId", userId);
                tracingParameters.Add("connectionName", connectionName);
                tracingParameters.Add("channelId", channelId);
                tracingParameters.Add("exchangeRequest", exchangeRequest);
                tracingParameters.Add("cancellationToken", cancellationToken);
                ServiceClientTracing.Enter(invocationId, this, "ExchangeAsync", tracingParameters);
            }

            // Construct URL
            var           baseUrl         = this.BaseUri.AbsoluteUri;
            var           url             = new System.Uri(new System.Uri(baseUrl + (baseUrl.EndsWith("/", System.StringComparison.InvariantCulture) ? string.Empty : "/")), "api/usertoken/exchange").ToString();
            List <string> queryParameters = new List <string>();

            if (userId != null)
            {
                queryParameters.Add(string.Format(CultureInfo.InvariantCulture, "userId={0}", System.Uri.EscapeDataString(userId)));
            }

            if (connectionName != null)
            {
                queryParameters.Add(string.Format(CultureInfo.InvariantCulture, "connectionName={0}", System.Uri.EscapeDataString(connectionName)));
            }

            if (channelId != null)
            {
                queryParameters.Add(string.Format(CultureInfo.InvariantCulture, "channelId={0}", System.Uri.EscapeDataString(channelId)));
            }

            if (queryParameters.Count > 0)
            {
                url += "?" + string.Join("&", queryParameters);
            }

            // Create HTTP transport objects
            var httpRequest = new HttpRequestMessage();
            HttpResponseMessage httpResponse = null;

            httpRequest.Method     = new HttpMethod("POST");
            httpRequest.RequestUri = new System.Uri(url);

            // Set Headers
            if (customHeaders != null)
            {
                foreach (var header in customHeaders)
                {
                    if (httpRequest.Headers.Contains(header.Key))
                    {
                        httpRequest.Headers.Remove(header.Key);
                    }

                    httpRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }
            }

            // Serialize Request
            string requestContent = null;

            if (exchangeRequest != null)
            {
                requestContent      = Rest.Serialization.SafeJsonConvert.SerializeObject(exchangeRequest, this.SerializationSettings);
                httpRequest.Content = new StringContent(requestContent, System.Text.Encoding.UTF8);
                httpRequest.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8");
            }

            // Set Credentials
            if (this.Credentials != null)
            {
                cancellationToken.ThrowIfCancellationRequested();
                await this.Credentials.ProcessHttpRequestAsync(httpRequest, cancellationToken).ConfigureAwait(false);
            }

            // Send Request
            if (shouldTrace)
            {
                ServiceClientTracing.SendRequest(invocationId, httpRequest);
            }

            cancellationToken.ThrowIfCancellationRequested();
            httpResponse = await this.HttpClient.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false);

            if (shouldTrace)
            {
                ServiceClientTracing.ReceiveResponse(invocationId, httpResponse);
            }

            HttpStatusCode statusCode = httpResponse.StatusCode;

            cancellationToken.ThrowIfCancellationRequested();
            string responseContent = null;

            if ((int)statusCode != 200 && (int)statusCode != 400 && (int)statusCode != 404)
            {
                var ex = new ErrorResponseException($"Operation returned an invalid status code '{statusCode}'");
                try
                {
                    responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

                    ErrorResponse errorBody = Rest.Serialization.SafeJsonConvert.DeserializeObject <ErrorResponse>(responseContent, this.DeserializationSettings);
                    if (errorBody != null)
                    {
                        ex.Body = errorBody;
                    }
                }
                catch (JsonException)
                {
                    // Ignore the exception
                }

                ex.Request  = new HttpRequestMessageWrapper(httpRequest, requestContent);
                ex.Response = new HttpResponseMessageWrapper(httpResponse, responseContent);
                if (shouldTrace)
                {
                    ServiceClientTracing.Error(invocationId, ex);
                }

                httpRequest.Dispose();
                if (httpResponse != null)
                {
                    httpResponse.Dispose();
                }

                throw ex;
            }

            // Create Result
            var result = new HttpOperationResponse <object>();

            result.Request  = httpRequest;
            result.Response = httpResponse;

            // Deserialize Response
            if ((int)statusCode == 200)
            {
                responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

                try
                {
                    result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject <TokenResponse>(responseContent, this.DeserializationSettings);
                }
                catch (JsonException ex)
                {
                    httpRequest.Dispose();
                    if (httpResponse != null)
                    {
                        httpResponse.Dispose();
                    }

                    throw new SerializationException("Unable to deserialize the response.", responseContent, ex);
                }
            }

            // Deserialize Response
            if ((int)statusCode == 400)
            {
                responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

                try
                {
                    result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject <ErrorResponse>(responseContent, this.DeserializationSettings);
                }
                catch (JsonException ex)
                {
                    httpRequest.Dispose();
                    if (httpResponse != null)
                    {
                        httpResponse.Dispose();
                    }

                    throw new SerializationException("Unable to deserialize the response.", responseContent, ex);
                }
            }

            // Deserialize Response
            if ((int)statusCode == 404)
            {
                responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

                try
                {
                    result.Body = Rest.Serialization.SafeJsonConvert.DeserializeObject <TokenResponse>(responseContent, this.DeserializationSettings);
                }
                catch (JsonException ex)
                {
                    httpRequest.Dispose();
                    if (httpResponse != null)
                    {
                        httpResponse.Dispose();
                    }

                    throw new SerializationException("Unable to deserialize the response.", responseContent, ex);
                }
            }

            if (shouldTrace)
            {
                ServiceClientTracing.Exit(invocationId, result);
            }

            return(result);
        }
 public override Task <TokenResponse> ExchangeTokenAsync(string userId, string connectionName, string channelId, TokenExchangeRequest exchangeRequest, CancellationToken cancellationToken)
 {
     return(Task.FromResult(new TokenResponse()));
 }