How can I configure ELMAH to display only for certain people without default ASP.NET authorization roles manager?
I (as well as many others, I think) use my own authorization logic and build my projects from zero without using provided templates. I want to log errors but it seems that it is impossible to configure ELMAH (somehow override functionality) to make it work with some other authorization or even to make it work only for particular IP addresses.
Since I will have access to web.config I tried to change these values in order to NOT display elmah by default.
<add key="elmah.mvc.disableHandler" value="false" />
<add key="elmah.mvc.disableHandleErrorFilter" value="false" />
<add key="elmah.mvc.requiresAuthentication" value="false" />
And when I want to view errors switch them from true to false and see errors, then switch back. But it seems that when I change these values all logs are erased.
What can I do?
I think the easiest approach would be to make some minor alterations to your custom authorization so the ELMAH authorization will work.
Option 1: Set the FormsAuthentication cookie on login. This way, in the web.config the allow users="username" should work. On successful login you can set the cookie with
FormsAuthentication.SetAuthCookie(theUsername, true).
The ELMAH authorization would look something like:
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<authorization>
<allow users="theUserName" />
<deny users="*" />
</authorization>
</system.web>
...other config settings
</location>
Option 2: If you are using putting users into roles, you can override the default role provider to use the function you made to get roles. This way is a little more involved but then lets you harness role-basing authentication in the web.config, which is really nice for securing things like static file (.pdf etc) delivery. I can add code for this if interested.
I was using the ASP.NET Identity Framework, so this answer is regarding that setup. I also used the Elmah.MVC package in NuGet. I edited the following lines in web.config. (you need to supply your own user name in the allowedUser setting)
<add key="elmah.mvc.requiresAuthentication" value="true" />
<add key="elmah.mvc.allowedRoles" value="*" />
<add key="elmah.mvc.allowedUsers" value="your_user_name" />
It appears that ELMAH does get the authentication information from the current thread principal, which the ASP.NET Identity Framework will establish on your behalf upon login.
It doesn't matter how the system gets the username or roles in this case. Whether it be from the built-in providers, a provider you implement yourself, or if during your custom authentication you populate this information yourself. All it takes is to manually set the principal during something like the Application_PostAuthenticationRequest event. This should give you the jist of it.
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
//Obtain username and roles from application datastore and use them in the next line
Thread.CurrentPrincipal = new GenericPrincipal(
new GenericIdentity("userNameHere"),
new string[] { "Admin", "CanDeleteStuff", "CanEditStuff", "OtherRole" }
);
}
This will let you use something like this in your web.config
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<authorization>
<allow roles="Elmah"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Not to mention being able to use User.IsInRole("CanEditStuff") in your code.
Related
This question already has answers here:
How to specify root (/) location in web.config?
(10 answers)
Closed 4 years ago.
I am attempting to migrate from Forms Authentication / Membership to asp.net identity.
One issue I have encountered: If I set the LoginPath to "/account/", logged out users end up with an infinite redirect loop (not really; it keeps extending the returnURL until the server blocks the request for having an overly long query string). This occurs on /account/, but /account/default.aspx is accessible to logged out users. I believe that the issue is that somehow default documents are treated differently by the OWIN middleware than they are by forms authentication/IIS. Currently, "default.aspx" is configured as a Default Document.
I tried setting using UseFileServer to set DefaultFileNames to include "default.aspx", but this did not seem to help. I also tried using path="." inheritInChildApplications=false" instead of path="default.aspx", but this caused a, "Config section 'system.web/authorization' already defined" exception, presumably because it overlapped with the previous system.web declaration.
I realize that there are several possible work-arounds:
tolerate default.aspx in the path:
use MapPageRoutes instead of relying on default pages
set the web.config to allow /account and then use location path to manually disable every subdirectory
Is there a way to convince Microsoft Identity that loading /account/ does not require authentication without using the workarounds in the bullet points above?
public void Configuration(IAppBuilder app)
{
app.UseFileServer(new FileServerOptions() {
DefaultFilesOptions = {DefaultFileNames = {"default.aspx"}}});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/account/")
});
}
<!--/account/web.config-->
<configuration>
<system.web>
<authorization>
<allow roles="activeuser" />
<deny users="*" />
</authorization>
</system.web>
<location path="Default.aspx">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
</configuration>
Voting to close my own question as a duplicate. For reference, this can be resolved by modifying the root web.config as follows:
<urlMappings>
<add url="~/account/" mappedUrl="~/account/default.aspx"/>
</urlMappings>
Somehow I completely failed to find https://stackoverflow.com/a/19154854/18192 while investigating this problem.
Edit #2: config.FilePath is showing that it's looking at a different file than what I'm expecting: "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config". I was expecting it to use the web.config in my project. Need to figure out why that's happening.
I have a method in my web API where I'm trying to read the values from the authorization section in my web.config. Based on what I've found, this should work:
public AuthorizationSetting GetAuthorizationSettings()
{
var config = WebConfigurationManager.OpenWebConfiguration(null);
var section = config.GetSection("system.web/authorization") as AuthorizationSection;
foreach (AuthorizationRule rule in section.Rules)
{
if (rule.Action.ToString().ToLower() == "allow")
{
Debug.WriteLine(rule);
}
}
return new AuthorizationSetting();
}
And this is the section of the web.config that contains the authorization info:
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<identity impersonate="true" />
<authentication mode="Windows" />
<authorization>
<allow roles="role1,role2,role3"/>
<deny users="*"/>
</authorization>
</system.web>
You can see that there is one allow and one deny. When I run the code, it appears that there is only one rule. Shouldn't there be two since there is an allow and a deny? And the one rule looks to have an Action of Allow and "*" for Users. That's not what's in the web.config. What am I missing here?
** Edit **
I've considered the possibility that it's reading a different web.config file. But there is only one other web.config file in the solution (under Views). I also changed it to have the same authorization section, but I still get the same result.
As you already figured out using Null in for the path parameter of OpenWebConfiguration loads the server root web.config in
%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\Config\
the documentation says:
The virtual path to the configuration file. If null, the root Web.config file is opened.
but one could assume it would be the root web config of the site, not the server. Anyway, try using:
var config = WebConfigurationManager.OpenWebConfiguration("~");
I'm new to ASP.NET MVC4 and therefore read many things about how to authenticate on an Intranet Website.
I've inherited of this type of project in order to improve it and after quick reading the source code, I saw that login/password are stored in clear text in a SqlServer database...
So my first improvement is to upgrade the authentication process in order to store passwords in the right manner.
Here is what I've done so far, in my GlobalAsax.cs add :
WebSecurity.InitializeDatabaseConnection(
connectionStringName: "AppConnectionString",
userTableName: "Employe",
userIdColumn: "IDE",
userNameColumn: "E_mail",
autoCreateTables: true);
in order to add the "webpages_*" tables to my database.
I changed the IIS configuration in order to deactive "AllowAnonymous" connection and activate "Basic Authentication".
But now I'm faced to Forms vs SimpleMembership, my Web.config:
<add key="autoFormsAuthentication" value="false" />
<add key="enableSimpleMembership" value="true" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="30" />
</authentication>
Can someone explain me clearly the use of each attribute?
I don't understand because autoFormsAuthentication is set to false but authentication use it after.
What the enableSimpleMembership?
Thanks
It's hard to find any information on the topic but in my opinion autoFormsAuthentication set to true will set:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
If you need other parameter you need to use <authentication mode="Forms">
explicity.
Also autoFormsAuthentication redirecting unauthorized users from any contollers. Not only with 'authorize' attribute.
But it is just my opinion...
I have web config:
<location allowOverride="true" path="Admin/Secure">
<system.web>
<authorization>
<allow users="SpecificUserName1" />
<allow users="SpecificUserName2" />
<deny users="*" />
</authorization>
</system.web>
</location>
I need to get all users (SpecificUserName1, SpecificUserName2) in runtime.
How can i accomplish this?
UPDATE I need to do this in View
Now i use default approach:
#if (Request.IsAuthenticated)
{
//secure menu
}
Now:
Menu showing for all users in domain, but access granted only users which exists in web.config
Need:
Hide menu/allow access for all users in domain except users which exists in web.config
UPDATE
I found the solution
http://forums.asp.net/t/1787320.aspx/1
UrlAuthorizationModule.CheckUrlAccessForPrincipal(Request.Url.AbsolutePath, HttpContext.Current.User, HttpContext.Current.Request.HttpMethod);
First things first, don't use web.config to control authorization in an ASP.NET MVC application.
Use the [Authorize] attribute. Decorate the corresponding controller/action with it:
[Authorize(Users = "SpecificUserName1, SpecificUserName2")]
public ActionResult Secure()
{
...
}
You could then externalize those usernames in a constant and reuse the value. By the way depending on where exactly you need those values, there might be other ways to retrieve them.
I am using Forms authentication in my asp.net (3.5) application. I am also using roles to define what user can access which subdirectories of the app. Thus, the pertinent sections of my web.config file look like this:
<system.web>
<authentication mode="Forms">
<forms loginUrl="Default.aspx" path="/" protection="All" timeout="360" name="MyAppName" cookieless="UseCookies" />
</authentication>
<authorization >
<allow users="*"/>
</authorization>
</system.web>
<location path="Admin">
<system.web>
<authorization>
<allow roles="Admin"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Based on what I have read, this should ensure that the only users able to access the Admin directory will be users who have been Authenticated and assigned the Admin role.
User authentication, saving the authentication ticket, and other related issues all work fine. If I remove the tags from the web.config file, everything works fine. The problem comes when I try to enforce that only users with the Admin role should be able to access the Admin directory.
Based on this MS KB article along with other webpages giving the same information, I have added the following code to my Global.asax file:
protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
if (HttpContext.Current.User != null) {
if (Request.IsAuthenticated == true) {
// Debug#1
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(Context.Request.Cookies[FormsAuthentication.FormsCookieName].Value);
// In this case, ticket.UserData = "Admin"
string[] roles = new string[1] { ticket.UserData };
FormsIdentity id = new FormsIdentity(ticket);
Context.User = new System.Security.Principal.GenericPrincipal(id, roles);
// Debug#2
}
}
}
However, when I try to log in, I am unable to access the Admin folder (get redirected to login page).
Trying to debug the issue, if I step through a request, if I execute Context.User.IsInRole("Admin") at the line marked Debug#1 above, it returns a false. If I execute the same statement at line Debug#2, it equals true. So at least as far as Global.asax is concerned, the Role is being assigned properly.
After Global.asax, execution jumps right to the Login page (since the lack of role causes the page load in the admin folder to be rejected). However, when I execute the same statement on the first line of Page_Load of the login, it returns false. So somewhere after Application_AuthenticateRequest in Global.asax and the initial load of the WebForm in the restricted directory, the role information is being lost, causing authentication to fail (note: in Page_Load, the proper Authentication ticket is still assigned to Context.User.Id - only the role is being lost).
What am I doing wrong, and how can I get it to work properly?
Update: I entered the solution below
Here was the problem and solution:
Earlier in development I had gone to the Website menu and clicked on Asp.net configuration. This resulted in the following line being added to the web.config:
<system.web>
<roleManager enabled="true" />
</system.web>
From that point on, the app was assuming that I was doing roles through the Asp.net site manager, and not through FormsAuthentication roles. Thus the repeated failures, despite the fact that the actual authentication and roles logic was set up correctly.
After this line was removed from web.config everything worked perfectly.
this is just a random shot, but are you getting blocked because of the order of authorization for Admin? Maybe you should try switching your deny all and your all Admin.
Just in case it's getting overwritten by the deny.
(I had code samples in here but they weren't showing up.