0
votes

I have an OAuthServerProvider issuing tokens after authenticating username and passwords. When the username or password is invalid I reject the owin Context, which will by default return 400 Bad Request as the status code.

But I want to respond with 401 Unauthorized

To achieve this I have written a middleware which will check the header and see if a custom header is present and if so will replace the status code with 401.

if (context.Response.StatusCode == 400 && context.Response.Headers.ContainsKey(Constants.OwinChallengeFlag))
{
   var headerValues = context.Response.Headers.GetValues(Constants.OwinChallengeFlag);
   context.Response.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());
   context.Response.Headers.Remove(Constants.OwinChallengeFlag);
}

This works absolutely fine when I hit it with fiddler, but the unit test I have written below always gets a 400. Somehow when I make a request with my unit test the middleware is skipped.

[TestFixture]
public class UnitTest1
{
    private TestServer _server;

    [SetUp]
    public void SetUp()
    {
        _server = TestServer.Create<Startup>();
    }

    [Test]
    public void ShouldReturnUnauthorizedResponse()
    {

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "/token");

        //wrong password 
        var requestContent = "grant_type=password&UserName=foo&Password=bar";

        request.Content = new StringContent(requestContent, Encoding.UTF8, "application/x-www-form-urlencoded");

        var response = _server.HttpClient.SendAsync(request).Result;

        //This assert fails, but shouldn't
        Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized));
    }
}

Need to know what I am doing wrong here.

1
1) This is an integration test not unit test. 2) Show the startup configuration and the full middleware. 3) Are you buffering the response to have access to it down stream?Nkosi

1 Answers

0
votes

I finally figured it out....

await _next.Invoke(environment) was the culprit. I was invoking it with the same environment Dictionary Object which was passed into the middleware and hence the modification made to the context object was not reflecting in the unit test.

The following code works as expected....

public async Task Invoke(IDictionary<string, object> environment)
{
    var context = new OwinContext(environment);

    var response = context.Response;

    response.OnSendingHeaders(state =>
    {
        var resp = (OwinResponse)state;
        if (resp.StatusCode == 400 && resp.Headers.ContainsKey(Constants.OwinChallengeFlag))
        {
            var headerValues = context.Response.Headers.GetValues(Constants.OwinChallengeFlag);
            resp.StatusCode = Convert.ToInt16(headerValues.FirstOrDefault());
            resp.ReasonPhrase = HttpStatusCode.Unauthorized.ToString();
            resp.Headers.Remove(Constants.OwinChallengeFlag);
        }
    }, response);

    await _next.Invoke(context.Environment);
}

Apart from passing the environment variable obtained from modified context object, modifying the response header inside the response.OnSendingHeaders is essential, this ensures the headers are modified before the response Headers are dispatched.

However I still have no idea how fiddler was picking up the correct response status code.

Hope it helps someone.