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.
Related
I have a pretty simple requirement (I use Spring-Security 4.0.1) but I can't find any examples on the web except what is been told on this page: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-handler
It is relatively simple to integrate a WebSocketHandler into other
HTTP serving environments with the help of
WebSocketHttpRequestHandler.
What I have: An implementation of WebSocketHandler that does the job and an HTTP serving environments using a Basic Authentication. My WebApplicationInitializer looks like this:
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
// WebSocket support - Handshake
Dynamic ws = servletContext.addServlet("webSocketHttpRequestHandler", new HttpRequestHandlerServlet());
ws.addMapping("/streaming/*");
// Spring Security Filter
FilterRegistration.Dynamic springSecurity = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
springSecurity.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
}
}
This is how I plugged my websocket endpoint to my existing web application.
My WebSocket configuration class looks like (very simplified) this:
#Configuration
public class WebSocketServicesConfig{
#Bean
public WebSocketHttpRequestHandler webSocketHttpRequestHandler() {
return new WebSocketHttpRequestHandler(new StreamingWebSocketHandler());
}
}
StreamingWebSocketHandler implements WebSocketHandler.
I also have a RESTful Web Service (in the same server) that uses the configured Basic Authentication.
What is working: My RESTful Web Service is working with any web browsers. I can do some authenticated queries (credentials can be sent in the HTTP headers).
WebSocket queries are working and ask for authentication the first time I try to do some (under FireFox, a popup appears asking for credentials, once I enter them, client and server are able to communicate via WebSocket messages).
In my WebSocketHandler, the Spring object: WebSocketSession that contains informations about the authenticated user is correct (#getPrincipal() method returns a Authentication containing the right granted Authorities, details and so on...).
Note that once the websocket is authenticated, I can relaunch the query without re-enter them.
What I want: On a user point of view, this is bad because the credentials are required twice:
First for RESTful queries
Second for WebSocket queries
How can I bypass the second authentication assuming the first one succeeded? Is there a way to detect the client has been authenticated and not ask for credentials?
What I don't want: I don't want to use neither Stomp over websocket nor SockJs (I don't need to support old web browsers).
We are developing an ASP.Net MVC intranet style app and attempting to leverage windows authentication as the vast majority of users are internal and pre-authenticated to a local domain.
Authentication is implemented in a fairly standard way, except for role information which we have opted to store in our database. We have implemented this in two different ways, (custom RoleProvider and override Context.User-- IsInRole) both of which meet the requirement and work without issue in the development environment hosted on both IIS Express and local IIS servers.
The problem is once we move the app to a staging environment, which is still on the same local network/domin, neither authentication method works. Both methods appear to be ignored, with the windows authentication role provider taking over.
To demonstrate this I have a chunk of code in my Home/Index page which enumerates the windows domain groups and tests User.IsInRole for each of them, in addition to User.IsInRole("Users") (a custom role). Under development environment each Windows group returns false, whilst the custom role returns true. Under staging environment the opposite is true.
I am happy with either method of achieving the desired outcome, so I am after some pointers as to why either of the following simply do not work.
Custom role provider is not taking effect
Global.asax "Application_AuthenticateRequest" event never fires, thus custom User object with overridden IsInRole method is not used.
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (Context.User != null)
Context.User = new UserPrincipal(Context.User.Identity);
}
Server 2008, IIS 7, MVC 5.1
Thank you in advance.
The issue was I followed a recommendation to remove runAllManagedModulesForAllRequests="true" from the modules section of my application's web.config, however this caused the relevant application events to cease firing (as the module wasn't registered).
See article here, and further info regarding this issue in the comments.
http://www.britishdeveloper.co.uk/2010/06/dont-use-modules-runallmanagedmodulesfo.html
Replacing the runAllManagedModulesForAllRequests="true" attribute has now resolved the issue, however I'm attempting to install the MS provided hotfix which is mentioned to remove reliance on this and/or manually registered modules.
Im building a small webshop and have run into a problem. The company which im building this webshop for has a lot of old SEO links pointing to products and categories. They, of course, do not want to loose these inbound links and still want value from them. I need to catch an inbound link e.g. www.myshop.com/myproduct.html and relay it with a HTTP 301 to e.g. www.myshop.com/products/ShowProduct/42
Any ideas on how to do this, i did this before in a asp.net webforms with a generic handler, that intercepted all calls, but i cant seem to get that to work.. I need to do this in code, i dont have access to the IIS since its a web hotel. I know all the inbound links.
You could implement the Application_BeginRequest method to intercept all requests. In this method you can test on the Request.Url property to determine what to do.
Something like this (in Global.asax.cs):
protected void Application_BeginRequest()
{
if (this.Request.Url.AbsolutePath.EndsWith(".html", StringComparison.OrdinalIgnoreCase))
{
// TODO: Apply logic here.
this.Response.Redirect("/MyUrl/", true);
}
}
This will redirect all requests to *.html to /MyUrl/
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
.
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.