2

I have a WebApi project self-hosted using OWIN.

I want to enable Windows Authentication on some of the controller's actions, but allow other actions to be called anonymously.

So, following some examples I found online, I setup my WebApi like this in my Statrup class:

public void Configuration(IAppBuilder appBuilder)
{
    HttpListener listener = (HttpListener)appBuilder.Properties["System.Net.HttpListener"];
    listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication | AuthenticationSchemes.Anonymous; //Allow both WinAuth and anonymous auth

    //setup routes and other stuff
    //...

    //Confirm configuration
    appBuilder.UseWebApi(config);
}

Then, in my controller, I created two actions:

[HttpGet]
[Authorize]
public HttpResponseMessage ProtectedAction()
{
    //do stuff...
}

[HttpGet]
[AllowAnonymous]
public HttpResponseMessage PublicAction()
{
    //do stuff...
}

This, however, does not work. Calling the action marked AllowAnonymous works as expected, but calling the one marked Authorize always returns a 401 error and the following message:

{
    "Message": "Authorization has been denied for this request."
}

even if the caller supports windows authentication, tested on browsers (Chrome and Edge) and Postman.

What am I missing here?

6
  • how are you calling the API ? Probably your API client you are not passing useDefaultCredentials = true. Commented Apr 26, 2019 at 13:40
  • @ManojChoudhari: as I said in the question, I tried with Postman (with NTLM authentication configured) and with browsers (Chrome and Edge) running on the same machine as the server, so they should authenticate automatically by default. Both have failed. Note that if I onyl enable IntegratedWindowsAuthentication in the HttpListener and then do not use the Authorize/AllowAnonymous attributes the authentication works as expected (both with Postman and with browsers). But if I do that I lose the ability to mark some actions as authorized and some as anonymous, which is waht I'm trying to do. Commented Apr 26, 2019 at 13:45
  • are you using ` appBuilder.Use(typeof(WinAuthMiddleware));` in the configure method ? Commented Apr 26, 2019 at 16:44
  • @ManojChoudhari: what is the WinAuthMiddleware class and where do I find it? Is it part of a nuget package? Commented Apr 29, 2019 at 7:10
  • one more thing - are you hosting this web API in IIS / IIS Express ? Did you check if both windows / anonymous authentication were enabled in IIS settings. Commented Apr 29, 2019 at 10:18

2 Answers 2

1

Well, I found a workaround for this in another question. Instead of specifying multiple auth modes (which doesn't work), you can chose the auth mode for each request at runtime, by setting up an AuthenticationSchemeSelector method like this:

public void Configuration(IAppBuilder app)
{
    HttpListener listener = (HttpListener)appBuilder.Properties["System.Net.HttpListener"];
            listener.AuthenticationSchemeSelectorDelegate = new 
    AuthenticationSchemeSelector(GetAuthenticationScheme);
}

private AuthenticationSchemes GetAuthenticationScheme(HttpListenerRequest httpRequest)
{
    if(/* some logic... */){
        return AuthenticationSchemes.Anonymous;                    
    }
    else{
        return AuthenticationSchemes.IntegratedWindowsAuthentication;
    }
}

While not ideal (you have to manually check the request URL or some other parameter of the request to decide which method to use) it works.

Sign up to request clarification or add additional context in comments.

Comments

0

Since your description about the question is bit limited I have set-up a demo app, where I implemented OAuthAuthorizationServerProvider as Provider for OAuthAuthorizationServerOptions and override GrantResourceOwnerCredentials and ValidateClientAuthentication

  public void Configuration(IAppBuilder app)
    {
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
        {
            Provider = new ApplicationOAuthBearerAuthenticationProvider()
        });
        app.Use<AuthenticationResponseMiddleware>();
        var options = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/api/xxxx"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 
            Provider = new OwinAuthorisationProvider()

        };
        app.UseOAuthAuthorizationServer(options);

    }

also tried to have a custom AuthorizeAttribute and added as filters in the configuration class .Filters.Add(new AuthorizeAttribute());

In AuthenticationResponseMiddleware i inherited OwinMiddleware and in the public override async Task Invoke(IOwinContext context) method please inspect the flow of the request.

It hits OAuthBearerAuthenticationProvider first in RequestToken method then to OwinMiddleware class, before going to any DelegatingHandler pipelines, mostly your authentication is implemented in this layer.

Please comment your findings after this check, parallelly I too modify the API and update you, hope it can help you.

2 Comments

Thanks for your answer, but it looks like (correct me if I'm wrong) you're suggesting using OAuth. Instead, what I wanted to use is Windows Authentication (NTLM/Kerberos). Are the two compatible? Can I use OAuth for windows authentication? How would a browser handle this, would it present the user with a username/password prompt like it does for NTLM? Sorry for the maybe stupid questions, but I'm not familiar with OAuth.
Yes, you're right I was demonstrating with OAuth. The example I gave was using Oauth if you want I can develop the OAuth token-based authentication. Please refer OAuth with Windows-Authentication here, docs.wso2.com/display/AM210/Kerberos+OAuth2+Grant I have limited knowledge with windows OAuth authentication, so it may be time taking.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.