How to allow anonymous authentication for index in owin pipeline? - c#

My index page in a MVC 5 Application return an unauthorized status code.
I have configured my application under IIS 10.0 with none authentication to manage the authentication in the owin pipeline :
<system.web>
<compilation debug="true" targetFramework="4.7.1" />
<httpRuntime targetFramework="4.7.1" />
<authentication mode="None" />
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<clear />
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
</handlers>
</system.webServer>
Here my controller to allow anonymous on index action :
[Authorize]
public class SPAController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
}
And my owin pipeline where i suspect that i miss something :
// Enable static file serving for the current application before authentication phase
app.UseStaticFiles(new StaticFileOptions() {
RequestPath = new PathString(""),
FileSystem = new PhysicalFileSystem(HostingEnvironment.MapPath("~/"))
});
Update
I also tried this without success :
[Authorize]
public class SPAController : Controller
{
[OverrideAuthorization]
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
}
and without attributes

Related

MVC5 anonymous access failing for new pages

I'm a noob when it comes to MVC security as I usually use my own, so please bear with me.
I have an MVC5 application which I'm using pretty-much straight out of the box.
It all works fine when I run it locally but after I have deployed it to a remote webserver I have authentication issues.
The pages which come with the project as standard open fine (Home, About, etc) but when I try to open one of my own I get this error:
Login failed. The login is from an untrusted domain and cannot be used
with Windows authentication.
The error is being raised on the first line of the view that tries to reference the model.
I haven't added anything to the web.config to allow or deny authentication.
An extract from the config looks like this:
<system.web>
<authentication mode="None" />
<compilation targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthenticationModule" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="LessAssetHandler" path="*.less" verb="GET" type="BundleTransformer.Less.HttpHandlers.LessAssetHandler, BundleTransformer.Less" resourceType="File" preCondition="" />
</handlers>
<security>
<authorization>
<add accessType="Allow" users="?" />
</authorization>
</security>
</system.webServer>
What do I need to do to allow access to the other pages?
[Edit]
The Home controller works fine. It is the standard out-of-the-box one which looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ASP.NET_MVC5_Bootstrap3_3_1_LESS.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
This was a SQL server problem, not ASP authentication as I had thought.
The server name in the connection string was the fully qualified version, e.g.:
server.domain.local
Changing this to its short version server fixed this issue!

HttpContext.User NullReferenceException only on deployed server

I am using formsauthentication on my MVC project and when testing locally using the Visual Studio Development Server everything works as expected. Once deployed to IIS 7.5 the HTTPContext.User is causing NullReferenceExceptions.
Both Dev and Prod machines are using the same SQL db (at the moment - this will change post-deployment of course) so I know it is not a problem with the DB or data within.
This must be a setting in IIS or my web.config but I cannot find it.
I've tried various changes to my web.config(from suggestions I've found around SE), here is part of my web.config for the current implementation:
<appSettings>
<add key="autoFormsAuthentication" value="true" />
<add key="enableSimpleMembership" value="false" />
<add key="webpages:Version" value="2.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="PreserveLoginUrl" value="true" />
<add key="ClientValidationEnabled" value="true" />
****Snip****
<system.web>
<httpRuntime targetFramework="4.5" />
<compilation debug="true" targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" cookieless="UseCookies"/>
</authentication>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="ProjectSquid.WebUI.HTMLHelpers" />
</namespaces>
</pages>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
<providers>
<clear />
<add name="CustomRoleProvider"
type="Project.Domain.Filters.CustomRoleProvider"
connectionStringName="EFDbContext"
enablePasswordRetrieval="false"
cacheRolesInCookie="true"/>
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="EFDbContext" />
</providers>
</sessionState>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-UA-Compatible" value="IE=9" />
</customHeaders>
</httpProtocol>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="false">
<remove name="FormsAuthentication" />
<remove name="DefaultAuthentication" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="" />
<remove name="UrlRoutingModule-4.0"/>
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" preCondition="" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
</modules>
</system.webServer>
What could cause HttpContext.User to differ from the VS Development Server and the IIS 7.5 implementation?
EDIT:
HttpContext is fed through the inherited BaseController:
protected virtual new CustomPrincipal User
{
get { return HttpContext.User == null? null : HttpContext.User as CustomPrincipal; }
}
public new HttpContextBase HttpContext
{
get
{
return ControllerContext == null ? null : ControllerContext.HttpContext;
}
}
The cookie isn't created until the PostAuthenticationRequest:
public void MvcApplication_PostAuthenticationRequest(object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
var ticket = FormsAuthentication.Decrypt(encTicket);
var id = new UserIdentity(ticket);
string[] userRole = Roles.GetRolesForUser(id.Name);
var prin = new CustomPrincipal(id);
HttpContext.Current.User = prin;
Thread.CurrentPrincipal = prin;
}
}
}
The authentication itself appears to be working fine as the function causing the exception starts with [Authorize] and successfully begins executing but fails as null when it reaches the first User reference:
int userT = User.Team.TeamId;
In this context the User being CustomPrincipal BaseController.User.
EDIT2:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880"
cookieless="UseCookies"
name=".ASPXAUTH"
protection="All"
slidingExpiration="true"/>
</authentication>
EDIT3
Custom IIdentity:
[Serializable]
public class UserIdentity : MarshalByRefObject, IIdentity
{
private readonly FormsAuthenticationTicket _ticket;
public UserIdentity(FormsAuthenticationTicket ticket)
{
_ticket = ticket;
}
public string AuthenticationType
{
get { return "Custom"; }
}
public bool IsAuthenticated
{
get { return !string.IsNullOrEmpty(this.Name); }
}
public string Name
{
get { return _ticket.Name; }
}
public string UserId
{
get { return _ticket.UserData; }
}
public bool IsInRole(string Role)
{
return Roles.IsUserInRole(Role);
}
public IIdentity Identity
{
get { return this; }
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (context.State == StreamingContextStates.CrossAppDomain)
{
GenericIdentity gIdent = new GenericIdentity(this.Name, this.AuthenticationType);
info.SetType(gIdent.GetType());
System.Reflection.MemberInfo[] serializableMembers;
object[] serializableValues;
serializableMembers = FormatterServices.GetSerializableMembers(gIdent.GetType());
serializableValues = FormatterServices.GetObjectData(gIdent, serializableMembers);
for (int i = 0; i < serializableMembers.Length; i++)
{
info.AddValue(serializableMembers[i].Name, serializableValues[i]);
}
}
else
{
throw new InvalidOperationException("Serialization not supported");
}
}
Custom IPrincipal:
interface ICustomPrincipal : IPrincipal
{
int Id { get; set; }
string Name { get; set; }
string Role { get; set; }
}
public class CustomPrincipal : IPrincipal
{
public CustomPrincipal(UserIdentity identity)
{
this.Identity = identity;
}
public IIdentity Identity { get; private set; }
Most likely, you are attempting to retrieve HttpContext.User before it has been initialized. This behavior differs between IIS Classic (or the Visual Studio Web Server) and IIS Integrated pipeline modes, which would explain why you are seeing different behavior between the environments.
Explanation
HttpContext is part of an application's runtime state. In modern hosting environments (IIS integrated pipeline mode and OWIN), HttpContext is not populated until after the Application_Start method is complete. Any behavior that you have that requires HttpContext.User should not be executed until the Application_BeginRequest event or after.
Reference: Request is not available in this context
It's not clear from your post since configuring the authentication depends on various settings in your project plus the configuration file. For example in Web.config file, there are several places to customize/configure the authentication like this one (the most important rule) that you haven't placed in your post:
<system.web>
<authentication mode="" />
</system.web>
As you know, since the configuration system is based on a hierarchical system of management system that uses **.config* files, you should consider the defaults, perhaps by <remove/> or <add/> some parameters. The configuration files for IIS 7 and later are located in your %WinDir%\System32\Inetsrv\Config folder, and the primary configuration files are:
ApplicationHost.config - This configuration file stores the settings for all your Web sites and applications.
Administration.config - This configuration file stores the settings for IIS management. These settings include the list of
management modules that are installed for the IIS Manager tool, as
well as configuration settings for management modules.
Redirection.config - IIS 7 and later support the management of several IIS servers from a single, centralized configuration file.
This configuration file contains the settings that indicate the
location where the centralized configuration files are stored.
Note: Some settings can be delegated to Web.config files, which may override settings in the ApplicationHost.config file. In addition, settings that are not delegated cannot be added to Web.config files.
Tip: A default installation of IIS 7 does not contain Digest authentication, so adding the settings for Digest authentication to your ApplicationHost.config will have no effect or may cause errors until the Digest authentication module is installed.
You need to see both local and deployment configurations to meet your purpose. If you have trouble with integrated pipeline, see the following pages to take its advantages :
Debugging the IIS7 integrated pipeline with failed request
tracing
How to Take Advantage of the IIS 7.0 Integrated Pipeline
Update About SlidingExpiration : According to MSDN:
Sliding expiration resets the expiration time for a valid
authentication cookie if a request is made and more than half of the
timeout interval has elapsed.
If the cookie expires, the user must re-authenticate. Setting the SlidingExpiration property to false can improve the security of an application by limiting the time for which an authentication cookie is valid, based on the configured timeout value. So I think there's no need to use this as false. This means It will expire cache after time period at the time of activating cache if any request is not made during this time period. This type of expiration is useful when there are so many data to cache. So It will put those items in the cache which are frequently used in the application. So it will not going to use unnecessary memory.

The page isn't redirecting properly after MVC 3 deploy

I'm deploy my MVC 3 application to a server and, after solve several issues related with missing MVC dlls (the server does not have MVC installed) it start to give a error:
Firefox "The page isn't redirecting properly"
Chrome "This webpage has a redirect loop"
IE "This page can't be displayed"
I found people saying that it is something cookie related, but I can't understand how to solve the problem.
I never see the default page whether.
I suspect there is a problem with my Global.asax file or my Web.Config.
Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
And there is a part of my Web.Config without AppSettings, connectionStrings and system.serviceModel:
<system.web>
<compilation debug="true" defaultLanguage="c#" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
<customErrors mode="Off">
<error statusCode="404" redirect="/Error/PageNotFound" />
</customErrors>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="UrlRoutingHandler" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Index action from Login page:
public ActionResult Index()
{
if (CurrentAuthenticatedData != null && CurrentAuthenticatedData.User != null)
ViewBag.IsLogin = true;
else
ViewBag.IsLogin = false;
return View();
}
CurrentAuthenticatedData:
System.Web.Routing.RequestContext Ctx = null;
public AuthenticatedData CurrentAuthenticatedData
{
get
{
AuthenticatedData retval = null;
if (Ctx.HttpContext.User.Identity.IsAuthenticated)
{
retval = (AuthenticatedData)ViewBag.Auth;
}
return retval;
}
}
AuthenticatedData is a class where I store several attributes related to logged user.
And finally my View code:
#{
ViewBag.Title = "Index";
}
<h2>Efetuar Login</h2>
#using (Html.BeginForm())
{
<div style="#(ViewBag.IsLogin??false ? "display: none" : "")">
#Html.ValidationMessage("Error")
<p>Username:<input type="text" name="usr" /></p>
<p>Password:<input type="password" name="pwd" /></p>
<p>
<input type="submit" value="Login" />
</p>
</div>
}
I try to deploy a dummie MVC application and it works! =/
Can you help me?
Thanks
There's probably a problem with your MVC installation. Make sure you install MVC correctly.
I'm guessing that your routes are not properly registered and thus if you go to your app's home page it will show you a 404. This gets picked up by this line in the web.config:
<error statusCode="404" redirect="/Error/PageNotFound" />
and redirects you to that page, which also throws a 404, redirecting you again to the same page, and so on and so on, causing the redirect loop.
For debugging purposes, you could comment out that line and check whether your routes are registered or not.
I discover that MVC runs a method called Initialize, in my BaseController, before any other:
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
...
}
Inside that method I has a verification to know if user is authenticated and when not I do a Session.Abandon(); and a strange thing (I don't know why):
if (!requestContext.HttpContext.Request.CurrentExecutionFilePath.Equals("/MyWebSite/"))
Response.Redirect("~/", true);
It runs me into a infinite loop because the request page was MyNewWebsite insted MyWebSite...
Sorry and thank you for your patience

MVC 3, Elmah and The view 'Error' or its master was not found

I am working on a legacy website that uses MVC 3, elmah and nhibernate. The Elmah log has literally thousands of " The view 'Error' or its master was not found" errors. I assume that it is covering up the real error. I cannot figure out how to have the real error get logged by Elmah.
As a means to attempt to debug, I added - return RedirectToAction("noWhere"); - to force an error. Locally I get a .net screen that simply says "An exception occurred while processing your request..." on staging I get YOSOD screen telling me to set the web.config customerrors node. Both have the customerrors set to on.
The web config has the following:
<pages>
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
<customErrors mode="On" defaultRedirect="~/Views/Shared/PageNotFound">
<error statusCode="404" redirect="~/Views/Shared/PageNotFound" />
<error statusCode="500" redirect="~/Views/Shared/PageNotFound" />
</customErrors>
The Global.asax has:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandleErrorAttribute());
}
The Elmah class has
public class ElmahHandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
var e = context.Exception;
if (!context.ExceptionHandled // if unhandled, will be logged anyhow
|| RaiseErrorSignal(e) // prefer signaling, if possible
|| IsFiltered(context)) // filtered?
return;
LogException(e);
}
and the baseController class has:
protected ViewResult PageNotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View("PageNotFound", PageViewModelBuilder.UpdateSiteProperties(new PageViewModel()));
}
protected ViewResult PageBadRequest()
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return View("PageNotFound", PageViewModelBuilder.UpdateSiteProperties(new PageViewModel()));
}
Any help on getting the correct errors to log would be appreciated....
Change "~/Views/Shared/PageNotFound" to "~/Views/Shared/PageNotFound.aspx” (or "~/Views/Shared/PageNotFound.chtml”) in your web.config and make sure you have PageNotFound.aspx in your Shared folder.

Custom handler failing to work due to Request Filtering

This is in IIS express.
public class FooHandler : HttpTaskAsyncHandler
{
public override async Task ProcessRequestAsync(HttpContext context)
{
var val = await new FooRequest().ProcessRequest();
context.Response.Write(val);
}
}
That s the handler and below is web.config.
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<sessionState mode="Off" />
<compilation debug="true" targetFramework="4.5" />
<machineKey compatibilityMode="Framework45" />
<httpHandlers>
<add verb="*" path="*.foo" validate="false" type="FooServer.FooHandler" />
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<add name="FooHandler" verb="*" path="*.foo" type="FooServer.FooHandler" />
</handlers>
</system.webServer>
</configuration>
I keep getting the below error. google didnt help. may be you can?
HTTP Error 404.7 - Not Found
The request filtering module is configured to deny the file extension.
Most likely causes:
Request filtering is configured for the Web server and the file extension for this request is explicitly denied.

Categories