OWIN Authentication Login Page - asp.net-mvc

I have an ASP.NET MVC5 application I am working on right now that I am integrating OWIN authentication into. I currently have my app configured in the startup class as so
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, // "ApplicationCookie",
LoginPath = new PathString("/Producer/LogIn/")
});
This is working great. But I have a few areas in my code where I need to know the login path. I am not looking to directly call a method to log out the user and redirect them, I just need the value of the PathString.
I could hard code it of course as its a value that wouldn't change often, (if ever) but I hate to do that and I want a solution that I can reuse in other projects cleanly. I would prefer to be able to access this value programmatically.
TIA.

Related

MVC application Authorization for ApiController doesn't work

I'm building an MVC application that has standard Controllers and APIControllers in the same project. All functionality works fine, I can call Controllers or APIControllers no issues.
What I'm trying to achieve is to make sure that if you call /api/products from outside it shouldn't be accessible, only authorized users can call it.
I added and Authorize attribute to my api controller and I still can call it and get results from a client application like Postman. You can see my code below.
[Authorize] //System.Web.Http
public class ProductsController : ApiController
[HttpGet]
public IHttpActionResult Get()
Here is what I have in my Startup.Auth.cs file.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
If I commented out this code, I get a proper response from the APIController, but I also cannot login.
<Error>
<Message>Authorization has been denied for this request.</Message>
</Error>
Not sure what I'm missing. Per my understanding I don't need to create a custom Filter for my API controllers, I should be able to use a built in Authorization functionality. Let me know if you need more details or code samples.
I think that the auth for your MVC controllers is defined by Startup.Auth.cs while for the API controllers is at WebApiConfig.cs.
Make sure that on WebApiConfig.cs in the Register() method you have a call to config.SuppressDefaultHostAuthentication(); which prevents the configured authentication method on your MVC controllers to work on ApiController calls.
Also note that you must need, in certain cases, to add the [AllowAnonymous] attribute in some API calls like login, register, etc.
Interesting findings. I tried to call the API Controllers that are required authentication from within the application without authorization and I received a proper response, Not Authorized. I tried to call the API endpoint using Fiddler, the same result.
So for some reason, Postman still can get results without any errors. I created even a new API endpoint the same behavior. I'm going to refrain from using the Postman because even it's a great tool it creates a lot of confusion, and as a result, I wasted a few hours.
Hopefully, my example is going to save somebody else time.

MVC ASP.Net local Active Directory Login

I've written a web site that uses Owin to login using the standard Login form. This is working fine. Each customer has their own version of the site on their server with different web.config values so it behaves the way each want it to.
I've now been asked for a version that automatically logs users in by retrieving their Windows Id and then using this to get their details from the local Active Directory.
I have a script that will do this, but I'm having difficulty calling it.
I'd like to keep as much of the code I have there already so I can continue to use the User and UserManager objects.
I'm hoping it is possible to amend something in the Startup.Auth.cs script so instead of using LoginPath for the CookieAuthenticationOptions it points to my Active Directory script.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
Unfortunately replacing the LoginPath with the path of the Active Directory script causes an endless loop which results in the querystring being too long for the browser error.
I have set IIS with:
Anonymous Authentication: Disabled, ASP.Net Impersonation: Enabled, Forms Authentication: Disabled, Windows Authentication: Enabled
I have been stuck on this for the past 5 days so any help would be much appreciated. Thank you.
Just create your own provider which will check username and password against your AD and add it to your CookieAuthenticationOptions object in appBuilder. Your provider class should inherit CookieAuthenticationProvider and override sign in methods you need. Here you can find list of available methods
https://msdn.microsoft.com/en-us/library/microsoft.owin.security.cookies.cookieauthenticationprovider(v=vs.113).aspx

Context.User is null in self-hosted SignalR hub when called from IIS-hosted MVC app

I'm have an IIS hosted MVC 5 app that uses Asp.Net Identity and OWIN for authentication via .AspNet.ApplicationCookie. From one of its views, I make calls to long-running methods on a self-hosted SignalR hub (running on the same server) via a SignalR JS client. These calls all work as expected. I now wish to decorate my hub with [Authorize(Roles = "Administrator")]. This has proved problematic. Setting a breakpoint in a hub method reveals that the Context.User is null, even though the .AspNet.ApplicationCookie is clearly in the Context.RequestCookies.
Here is the bootstrap for the hub (self-hosted in a windows service):
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
var hubConfiguration = new HubConfiguration();
map.RunSignalR(hubConfiguration);
});
Here is the auth config for the web app (hosted in IIS):
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(UserAccountContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
Question 1: Is the use of [Authorize] possible in the scenario described above? If so, how?
Question 2: Would it be better to just merge the self-hosted hub into the IIS hosted app? If so, are there any issues with long-running hub methods under IIS?
Update 1
I've tried adding TicketDataFormat = new TicketDataFormat(new MachineKeyDataProtector("ASP.NET Identity")) to the CookieAuthenticationOptions on my hub config, but that didn't help. Sure seems like this should be easier than it is.
I ended up moving my self-hosted hub into my ASP.Net application and it worked just fine. This seemed easier and more maintainable than implementing the workaround in this SO question, OWIN Self-Host CookieAuthentication & Legacy .NET 4.0 Application / FormsAuthenticationTicket

Double authentication with Web app & Web API needed?

I'm stuck on how to solve following problem.
I'll start with describing what my app looks like in a general context.
[ ASP MVC (Angular App) ]
Uses Owin cookie
[ WEB API 2 ]
Uses Oauth Token Bearer
This scenario is happening:
User visits app and authenticates with a login form which lies in ASP MVC app and generates a cookie.
Now I've decided to use AngularJs to add a couple features which made me use $resources and Web API 2. However, those features are only available if user is authorized.
To the problem: Now I must use a token for each request to the Web Api 2 to access different methods within controllers. This means I must login the user again but this time through AngularJs. Using /token route.
How would I do this?
Should I take the cookie, check credentials in it and send it as a authentication request?
Can I do something within the form authentication, in the same method, in the Asp MVC app?
Please help me, this gave me a lot of overhead. Walking from a simple app to this in 30min. Can't even get my head around all stuff in the authentication.
Regards!
My WebAPI supports both token and cookie auth.
During startup I register the authentication like this:
private void ConfigureAuth(IAppBuilder app)
{
//Token
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
});
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
// this is to ensure that a 401 response is sent if the
// user is not authenticated, rather than redirecting to
// a logon page.
}
},
CookieDomain = ".example.com" //might not need to set this
});
}

Owin + DefaultAuthenticationTypes.ApplicationCookie + Windows Authentication

My MVC5.1 application uses OWIN authentication based on http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown
The user persistence in db and login validation is handled by my custom UserService class. This works perfectly fine when using individual accounts for users to login into the system.
I also need to make this work with Windows Authentication (Active Directory). So if Windows auth is turned on (on IIS & a flag in my web.config) the AD user will be validated against my DB to see if the logged in user has access to my web application and if yes log him in (set the application cookie).
I enabled Windows Auth in IIS, disabled Anonymous Auth in IIS, and removed <authentication mode="None" /> from my web.config file. This makes OWIN think the user is already authenticated even though in the startup I configure it to use ApplicationCookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
Well this is fine, I could write a wrapper around AuthenticationManager.User.Identity.IsAuthenticated property and add the check to validate the user against my db. But then I am not able to add custom claims as OWIN doesnt seem to be using an Application Cookie but directly uses the WindowsClaimsIdentity.
My login function (the one that tries to add additional claims) is as follows:
_authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
var identity = new ClaimsIdentity(
new[] {
new Claim(ClaimTypes.NameIdentifier, user.UserID.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.UserData, user.CurrentDomainID.ToString())
},
DefaultAuthenticationTypes.ApplicationCookie,
ClaimTypes.Name,
ClaimTypes.Role);
_authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
Now If I add the line <authentication mode="None" /> in web.config it seems to be working, meaning OWIN only looks for claims inside its cookie and doesnt authenticate the user until the user exists in the DB.
But in both these cases, I am stuck in a redirect loop on the login page unless i remove login path from the startup. I tried setting Response.SuppressFormsAuthenticationRedirect=false in my login controller but no change.
Another problem I am facing is, the browser doesnt show me the login page until I enter a valid username/password in the basic auth popup even if i am logged in with my AD account in windows. Is there a way to hide this popup?

Resources