Hey all. I have an ASP.NET MVC application that I am going to be deploying to a live server soon. Theoretically, I would like to password protect the application while I'm beta testing without modifying the underlying code base or membership within the application. I will have several people beta testing, so it is compulsory that it is available on the web. A simple scenario:
User navigates to the application under beta
Perhaps an HttpHandler will process the request and redirect them to an interstitial, temporary login page where they have to enter a beta password to access the application
Stackoverflow used a similar technique when they were under beta test. Any ideas?
An edit for clarification. I don't have access to IIS for this particular application because I'm using a managed host.
A couple ideas:
Use windows authentication for the whole application/site in IIS
The idea you mentioned is also a good approach IMO, implementation would probably be flexible in that case.
You could wire up a quick custom AuthorizeAttribute that checks for a custom Auth cookie. Just decorate your controllers with it under beta and delete them when you're ready to go.
Something like this (PS - Did this on the fly without testing):
public class BetaTestAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//if(cookie checks out ok)
//return true;
//else
//httpContext.Response.Redirect("BetaLoginPage");
return base.AuthorizeCore(httpContext);
}
}
Have an action method like so:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult BetaLogin(string username, string password)
{
if(username == "whatever" && password == "whatever")
{
//create custom cookie
return RedirectToAction("Index", "Home");
}
else
return View();
}
When you crate a new ASP.NET MVC project in Visual Studio, you automatically get an AccountController that uses ASP.NET's underlying MembershipProvider to provide a login mechanism.
Even if you don't have it in your final application, you can use it as a temporary solution until you get your real security mechanism up and running.
It requires you to set up a SQL Server database for those ASP.NET services, but depending on how familiar you are with that, you can do it within ten minutes to a couple of hours.
When the public beta is over, you can just discard the AccountController and the database.
I'm with dhulk -- use Windows Authentication on IIS. That route will allow you to avoid putting any authentication code in your application. Simpler is better, and I'd want to avoid doing the work to implement a membership system then to un-implement it.
I would create a simple login View which sets a Session that gets checked on Session_Start() in your Global.asax file... Like so:
protected void Session_Start()
{
if (!Convert.ToBoolean(Session["authenticated"]))
{
// Redirect to the login View
}
}
When you are ready to open up your application for everyone, just remove the View and the three lines of code in your Global.asax file.
Use the good old RoleProvider and create a Beta role and check it via Authorize
Create your own AuthorizeAttribute and check for the IP address or a cookie
.
Related
I am looking for a bit of a point in the right direction...
We have an MVC site, with a variety of virtual directories that all point at the same code, e.g.
https://www.x.com/dir1
https://www.x.com/dir2
The different virtual directories are used partly for business reasons due to the URL 'content' and partly to control how the site is skinned.
The sites are locked down for access using forms authentication, and I am trying to track down a slightly elusive issue.
A user logs into the site using the url 'dir1', authenticates fine, SetAuthCookie is called.
We have code that runs on OnActionExecuting throughout the site - it takes the logged in user and determines which virtual directory they should be accessing (one per user) and if they are in the wrong URL, will redirect them, e.g. (simplified code):
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Authenticated && UserIsNotInCorrectDirectory())
{
filterContext.Result = new RedirectResult("https://www.x.com/dir2");
}
}
The problem I am having is this - if I start a fresh browser (using firefox at the minute, to view the cookies) and do the following:
Log into the site using the 'dir1' url.
I get authenticated fine - I can see the set-cookie http header containing our auth cookie. This response will also redirect me to 'dir2'.
On the subsequent page, when I view the cookies, the auth cookie is not there - this is the problem.
To add to my confusion, if I then bring up the login page again (same browser, session not closed), and try this again, it works. Anybody got a clue?
My bet is that your OnActionExecuting filter is getting in the way of your login form and your session cookie is getting lost when you overwrite the result. In case this code resides in an attribute, I would try removing the attribute from your Login action and see if that works.
I am currently working with an MVC4 and have a secure area to the site. To manage this, I am working with windows authentication. I have implemented this in web forms some time back but this is the first time I have worked with it in respect of MVC.
I am using cookies to store the auth. So when a user authenticates, it gets persisted to cookie. A user could be in a number of different roles. Should this also get persisted to a cookie?
After authentication, how can I check in controllers, filters etc if the user is logged in and if they are a member of a certain role? Does such information need to be loaded in to the users context on each request?
If you're using a Membership Provider then you should be able to do what you want using Action Filter attributes on your controller methods.
[Authorize]
public ActionResult SomeControllerAction()
{
return View();
}
or to test for a particular role:
[Authorize(Roles = "Administrator,Moderator")]
public ActionResult SomeControllerActionRequiringSpecificRoles()
{
return View();
}
I know the easy way to get to an SSL page in ASP.NET MVC - via the [RequireSSL] attribute but I'm a little confused to the best way to do the opposite.
I have many links on my site in a header bar and most of those links don't require SSL and I don't want to still use SSL.
The futures project makes it very easy to redirect automatically to an SSL page with [RequireSSL(Redirect=true)], but it doesnt seem to make it easy to get out of this context and automatically redirect back to http.
What am I missing?
You're not missing anything; there is no out-of-the-box functionality for this. You can easily create your own by taking the RequireSslAttribute source and modifying it.
Answer from a dupe question elsewhere:
How to step out from https to http mode in asp.net mvc.
CAUTION: If choosing to use this approach your auth cookie will be sent over plain text after switching back to HTTP, and can potentially be stolen and used by someone else. See this. In other words - if you were using this for a bank site you would need to make sure that switching to http would first log the user out.
public class DoesNotRequireSSL: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var response = filterContext.HttpContext.Response;
if (request.IsSecureConnection && !request.IsLocal)
{
string redirectUrl = request.Url.ToString().Replace("https:", "http:");
response.Redirect(redirectUrl);
}
base.OnActionExecuting(filterContext);
}
}
This is well worth reading (epecially to realize the security implications of switching carelessly back to http from https :
Partially SSL Secured Web Apps With ASP.NET - not MVC specific but relevant security concerns
Partial SSL Website with ASP.NET MVC - MVC friendly
It's quite a complicated issue overall. Still haven't found a true solution to everything I want to do, but thought these articles may help others.
I'm really new to asp.net and mvc, so I'm a bit lost.
I'm managed to log in with OpenID in my application using this Tutorial.
But I'm not sure if just setting Session["Admin"] = true is the right path to follow, so far my code is something like this:
switch (openid.Response.Status)
{
case AuthenticationStatus.Authenticated:
if (openid.Response.ClaimedIdentifier.ToString() == Settings.Default.AdminClaimedIdentifier)
Session["Admin"] = true;
FormsAuthentication.RedirectFromLoginPage(openid.Response.ClaimedIdentifier, false);
break;
...
}
The application I'm trying to write only needs one Administrator right now, and I found it to be very easy to just have this admin's OpenID in the Settings.
Basically what I want to do is have one Admin's OpenID in the Settings and them protected a whole folder based on this authentication, so every action inside it and it's subfolders needs Admin rights, something like: ~/Admin/whatever/edit/1 needs authentication.
Which would be the simplest and cleanest possible way to do this kind of authentication?
OpenID provides you with Authentication (who are you?) where as limiting access to the "folder" or Admin Controller is Authorization(s) (what can you do?).
A simple solution which can also work for you in the future (based on your needs) is to use the RoleProvider which will allow you to use the Authorize attribute as griegs suggests.
I don't know about OpenId but normally you would place the following either at the top of your controller class to lock the whole folder, or at the ActionResult to lock that action;
[Authorize(Roles="admin")]
Hope this helps.
I have a development server running IIS 7.0 with an ASP.NET MVC Web Application, that authenticates using Forms Authentication/Membership.
I need to be able to prevent unauthorized users from viewing this site. Our customers however should be able to enter a simple username/password to gain access.
After they do so, they should be able to interact with the web application using Forms Authentication as if they just came to an unprotected site.
Any suggestions?
My previous answer said forms auth and basic http auth could live side by side in II7 integrated mode. I was completely wrong and have since made a simple solution.
Using a custom HttpModule you can add basic auth along side regular forms auth
public class CustomBasicAuthHttpModule : IHttpModule
{
private HttpApplication httpApplicationContext;
public void Dispose()
{
}
public void Init(HttpApplication context)
{
this.httpApplicationContext = context;
context.BeginRequest += this.OnBeginRequest;
context.EndRequest += this.OnEndRequest;
}
private void OnBeginRequest(object sender, EventArgs e)
{
// your logic of checking Auth header goes here
if (this.httpApplicationContext.Request.Headers["Authorization"] != "Basic base64-encoded-user:pass")
{
this.httpApplicationContext.Response.StatusCode = 401;
this.httpApplicationContext.Response.End();
}
}
private void OnEndRequest(object sender, EventArgs e)
{
if (this.httpApplicationContext.Response.StatusCode == 401)
{
this.httpApplicationContext.Response.AddHeader("WWW-Authenticate", "Basic");
}
}
then in your web.config
<system.webServer>
<modules>
<add name="CustomBasicAuthHttpModule" type="Namespace.CustomBasicAuthHttpModule, AssemblyName"/>
</modules>
</system.webServer>
I just did this with Helicon Ape. The free license includes 3 sites, which for me was good enough.
If you use this on a site, just remember to check if the license is activated for the site (start menu > helicon > ape > manager, help, license manager).
As Aaron points out, this isn't so straightforward in IIS7. Now, the flip side is this old trick is insecure at best and there are better ways to do it now and being able to use all authenticaiton methods with all apps has lots of advantages. There are some ways to get around this such as:
a) keeping the development site behind a VPN which your clients can access.
b) reverse proxying the site, and letting the proxy do the http authentication.
c) A bit more involved would be to build your app with a demo mode. Trick here is to make it turn on or off from the first request given a special magic query string. Check for that in Session_Start() then tag users that come with it and profit.
We wrote a custom module for IIS to allow certain IP ranges through automatically, and present anyone else with a login dialogue. Once they'd logged in, it stored that fact in their session and simply passed requests through.
Works alright, can be applied to anything in IIS sites or services.