ASP.NET mvc 3 Anonymous Authorization not working - asp.net

I have a strange issue that of course only occurs on our production box. It works on our test server and on my box.
I have an ASP.NET MVC 3 controller that is serving exposing a RESTful API. I have enabled anonymous users to call these service with the code shown below. Calling these methods via GET works just fine (using WebRequest). However, when trying to POST data (using HttpClient) it fails with a 401 error.
This web service is hosted within another IIS site which uses Windows Auth. But I configured this directory to allow Anonymous and disabled windows auth. It lives in /Areas/Services under the main site.
I have configured IIS to allow Anonymous authentication and even enabled it in the web.config. However, when I try to POST data to this controller, I get back "401 - Unauthorized: Access is denied due to invalid credentials". I don't want any credentials! Again, GET on this same controller works fine anonymously.
This seems to be a configuration issue (since it works in QA) but I do not know any other things to configure. I have been configuring IIS websites for anonymous/windows/forms auth for 10 years but have never run into anything like this before.
Here is the code that allows MVC 3 to serve these methods up to anyone:
[AuthorizeAnonymous]
public class LtWebsiteController : Controller
{
...
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class AuthorizeAnonymousAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!(filterContext.Controller is LtWebsiteController))
base.OnAuthorization(filterContext);
}
}
This is driving me nuts! Please help.

You are likely missing HTTP headers for NTLM authentication. I would configure HttpClient to send the right credentials as part of the request.
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
HttpClient client = new HttpClient(handler);
It's confusing since you are enabling anonymous authentication. But, with Windows Authentication the request needs to have proper headers. A 401 tells me the server flat out rejects the HTTP request.
http://www.asp.net/web-api/overview/security/integrated-windows-authentication

Related

Azure AD reply url failing on html handler

Via ASP.NET I have created a startup file that will use Azure AD to log in a user
e.g.
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
{
ClientId = "42067b8d-b972-44e9-af86-ef60bc6d6fdb",
Authority = "https://login.windows.net/...com",
RedirectUri = "http://localhost:50560/content/story_html5.html",
PostLogoutRedirectUri = "http://localhost:50560/content/story_html5.html",
Scope = OpenIdConnectScope.OpenIdProfile,
ResponseType = OpenIdConnectResponseType.IdToken
});
}
And as you can see my RedirectUri in hitting a static file html file.
On my app registration in Azure portal my manifest for the replyUrls states
"replyUrls": [
"http://localhost:50560/content/story_html5.html"
],
So everything is working and connecting correctly.
(if I use a aspx for example the redirection would work)
However using the .html file I'm getting the error
HTTP Error 405.0 - Method Not Allowed
The page you are looking for cannot be displayed because an invalid
method (HTTP verb) is being used.
All I believe I need to do is add the html handler to Azure AD, does anyone know how to do this?
Thanks
This has nothing to do with Azure AD, but your configuration. Your end. Your Project. Your IIS config. Because sign-in response is a HTTP POST for security reasons. And static files handler in IIS does not accept anything beside GET for obvious reasons.
More information you will find here and there.
First, why would you want to redirect to a static page?! With the redirection after OIDC login, the IdP (Identity Provider, understand Azure AD in that case) sends valuable information which is needed by the OIDC middleware (understand the .UseOpenIdConnectAuthentication method) to be able to verify the token and initialize user session. By sending the sign-in response back to a static page you accomplish couple of things:
You cut out the OIDC middleware from the authentication - it is no longer able to process the response. Because it will not listen on static file requests. Static files are processed outside your OWIN authentication middleware.
Thus not able to verify authenticity of the user.
Thus not able to create secure cookie.
Thus not able to sign-in the user into your application.
Conclusion
Do not change the reply URL for your ASP.NET middleware, unless you explicitly and knowingly want to override the complete handling of sign-in responses.

Using Identity Server 3, ClaimsPrinciple null even after successful bearer token authentication

I have a test console app which I'm pointing at a local instance of Identity Server 3 to request an access token. The following code does this and returns my token fine (passing a single scope "scope.test.client").
static TokenResponse GetClientToken(string clientId, string clientSecret, string[] scopes)
{
var uri = new Uri(string.Concat(ID_BASE_URI, ID_URL_TOKEN));
var client = new TokenClient(
uri.AbsoluteUri,
clientId,
clientSecret);
return client.RequestClientCredentialsAsync(string.Join(" ", scopes)).Result;
I then use this token to call an API also running locally. This takes the TokenResponse obtained above and passed it to this method:
static void CallApi(string url, TokenResponse response)
{
try
{
using (var client = new HttpClient())
{
client.SetBearerToken(response.AccessToken);
Console.WriteLine(client.GetStringAsync(url).Result);
}
}
catch (Exception x)
{
Console.WriteLine(string.Format("Exception: {0}", x.Message));
}
}
The API (an ASP.NET WebApi project) uses an Owin Startup class to enforce bearer token authentication for all requests:
appBuilder.Map(baseApiUrl, inner =>
{
inner.UseWebApi(GlobalConfiguration.Configuration);
// Enforce bearer token authentication for all API requests
inner.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://identityserver/core",
ValidationMode = ValidationMode.ValidationEndpoint,
RequiredScopes = new[] { "scope.test.client" }
});
});
It also ensures all API requests are handled by a custom authorize attribute:
GlobalConfiguration.Configuration.Filters.Add(new DefaultApiAuthorizeAttribute());
Debugging this API, the first line in my overridden OnAuthorize method (in DefaultApiAuthorizeAttribute) is this:
var caller = actionContext.RequestContext.Principal as System.Security.Claims.ClaimsPrincipal;
If I break on this line I can see that actionContext.RequestContext.Principal is always null. However, I can see that ((System.Web.Http.Owin.OwinHttpRequestContext)actionContext.RequestContext).Request.Headers contains an Authorization header with the bearer token passed from my console app.
So it would seem that the API project is not authenticating the bearer token. Certainly the Identity Server logs suggest it isn't being hit at all after issuing the initial access token. So I'd appreciate your expert advice about why this might not be happening, or at least some pointers about where to look.
I suspect it might have something to do with SSL. Both sites are hosted locally under self-signed SSL certs, although Identity Server is configured to not require SSL and uses the idsrv3test.pfx development certificate for signing. I do have another test MVC web app which delegates authentication to the same IS3 instance which works fine locally, so I believe my IS3 instance is configured correctly.
You need to call UseIdentityServerBearerTokenAuthentication before you call UseWebApi. When you set up an OWIN Middleware Pipeline, the order is important.
In your case, Web API will be handling your requests before they get sent onto Identity Server (if they get sent on at all).
I imagine a range of possible issues could have the impact I described, but in my case I was able to find the cause by adding a diagnostics log to my consuming API. This led me to discover that the problem was an assembly conflict. The Owin middleware was looking for a Newtonsoft.JSON assembly with version 8.0.0.0 but my consuming API (actually running on top of a CMS intance) was using 7.0.0.0.
For anyone else who wants to find the answer fast, rather than spend hours tweaking configurations, here's the documentation that describes how to add this logging: https://identityserver.github.io/Documentation/docsv2/consuming/diagnostics.html

SignalR WinAuth does not Work

I have a problem in SignalR connection with Win Auth. When I enable anonymous in IIS Authorize settings, it works but sometimes it gives HTTP 403 Forbidden error. After I researched, I found that I need to disable Anonymous Connections. But when disable and enable the windowsAuth in IIS then there is always HTTP 401.2 UnAuthorized error. How I can connect with WinAuth? For my project I need to use WinAuth.
Not1 : I am using Silverlight 5.
Not2 : I have already tried possible solutions on StackOverflow but none of them worked.
So why cant I use WinAuth? It is enabled everywhere in config files, in IIS settings as well as in my web.config.
I spent 2 days but still I could not find a solution. If you need more information just write a comment. I am not sure what else information I can share. I dont want to put here lots of unnecessary texts.
EDIT:
When I use this code, i.e if I enter the username and password explicitly then it works. Internet Explorer first uses Anonymous Authentication and then it fails then it uses NetworkCredentials directly. This is the code
hubConnection = new HubConnection("URL");
hub = hubConnection.CreateHubProxy("HUBNAME");
hubConnection.Credentials = new System.Net.NetworkCredential("ID", "PASSWORD");
(The ones with capital letters are specific to my app.)
So how can I get Windows Credentials for my Silverlight App? DefaultCredentials does not work for silverlight.
Have you added authorization to your hub?
[Authorize(Roles = "Admin")]
public class AdminAuthHub : Hub
{
}

How to restrict SignalR server connections?

I have a SignalR app. hosted in a Windows service (used OWIN & Katana as self hosting) and it's listening on mydomain.com:8080
On the same server, I also have an MVC application which is basically a website that connects to my SignalR hub which I mentioned above.
I want to restrict access to my SignalR app only to my MVC application. I've searched the internet but didn't come along an example of this.
Is it possible to achieve this? How can I get the information about if the connection is coming from my MVC app or from another app? Do I need to implement an authorization for my own MVC application to be able to connect to my SignalR application?
Right now, everyone on the internet can access to mydomain.com:8080/signalr endpoint which basically means a competitor can code a client that connects to my SignalR hub and use it. What are the options to prevent this scenario?
p.s: Please ask for more information -if you need- instead of just marking the post as "non constructive" because I don't know how this question can be asked more "constructive"
I believe I have a working example, it's quick and dirty, but it should do the job, and you should be able to expand it so it'll fit your needs better:
I created a class that inherits from Microsoft.AspNet.SignalR.AuthorizeAttribute and overrode the AuthorizeHubConnection method:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthorize : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(Microsoft.AspNet.SignalR.Hubs.HubDescriptor hubDescriptor, IRequest request)
{
string referer = request.Headers["Referer"];
string authority = new Uri(referer).Authority;
if (authority == "mydomain.com:8080")
{
return true;
}
return false;
}
}
all it does is check the Referer header's host/authority against a hard coded one, and returns true if they match.
You can then use it like this:
[CustomAuthorize]
public class ChatHub : Hub
{
//Hub code here...
}
If CustomAuthorize returns false, the request will stop there. The hub's OnConnected() will not be triggered.
Just Use cors option instead of writing code.in cors allow your domain only

authentication in singalR selfhost server- and web client in SSL

I have a singalR self host server that is hosting my singalR in a console application on https
I am using this packages to self host:
Install-Package Microsoft.Owin.Hosting -pre
Install-Package Microsoft.Owin.Host.HttpListener -pre
Install-Package Microsoft.AspNet.SignalR.Owin
i have a web client which is backed by WebApi, I can connect to my selfhosted singalR from my webclient and send messages however I would now like to add authentication to this, which means only logged in users can send messages to my selfhosted singalR server.
I used [Authorize] attribute before my method
[Authorize]
public void Test(string test)
{
Console.WriteLine(test);
}
I have my web client authentication done via forms authentication however after logging in sucessfully in my webclient, when i do call singalR method, i recieve javascript error
Uncaught Value cannot be null. Parameter name: user
It tells that my method is protected but somehow my user is not passed to my self hosted singalR server, What is missing here?
Support for this was introduced with SignalR 1.0, you can read a little about that on David Fowlers blog. The problem is, with it being so new it's a little sparsely documented.
I'm not exactly sure what's going on in your application at the moment but you can find a similar question already on Stack Overflow which might help you get on the right track: Integrating SignalR with existing Authorization
Basically, you can create a SignalR Attribute that implements IAuthorizeHubConnection and IAuthorizeHubMethodInvocation, then decorate your Hubs/Methods that you want authorized.
public class HubAuthorizeAttribute : Attribute, IAuthorizeHubConnection, IAuthorizeHubMethodInvocation {
public virtual bool AuthorizeHubConnection(HubDescriptor hubDescriptor, Microsoft.AspNet.SignalR.IRequest request) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedController(hubDescriptor.Name);
}
public virtual bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedAction(hubIncomingInvokerContext.MethodDescriptor.Hub.Name, hubIncomingInvokerContext.MethodDescriptor.Name);
}
}
Alternatively, you could add the HubAuthorizeAttribute as a HubPipeline Module to Globally require Authorization.
var globalAuthorizer = new HubAuthorizeAttribute ();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));
I've asked a similar question a few times over the last days in the SignalR JabbR chat and haven't got any answer.
When I was about to post my question here I found your question and this other one. Unfortunately, from the answer given there a couple of weeks ago, it seems like SignalR itself provides no Authentication support, so that's a huge problem for many selfhosted applications (we were intending to use Integrated Windows Authentication with SignalR...)

Resources