Reputation: 7913
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?
Upvotes: 2
Views: 1697
Reputation: 7913
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.
Upvotes: 1
Reputation: 172
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.
Upvotes: 0