How does IPrincipal gets its roles? - asp.net

I need to get know how SiteMapProvider.IsAccessibleToUser() works.
Built-in XmlSiteMapProvider calls HttpContext.User.IsInRole() which uses System.Security.Principal.GenericPrincipal in case of forms authentication.
Where does the current user gets its roles? Which provider loads this kind of information? I want to overload it and use custom logic.

You do this by implementing a RoleProvider. Check out these links:
http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx
http://www.codeproject.com/KB/aspnet/WSSecurityProvider.aspx

To use custom logic, you can create your own forms authentication cookie with roles and read it back in Global.asax.
See these:
private void SetAuthenticationCookie(int employeeID, List<string> roles)
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
http://weblogs.asp.net/rajbk/archive/2010/04/01/securing-an-asp-net-mvc-2-application.aspx

Related

Asp.net preventing HTTP Replay Attack

I have an asp.net webforms project. In there, an "Admin" has the ability to get to a screen to submit a form that will create a new user (CreateUser.aspx).
If that user's permission is changed later to be less than Admin they can't access that screen anymore to create new users. However, if they saved the exact web request to create a new user from when they were an admin, they can replay this and create new users still.
It is not possible for a random person to submit this form though unless they guess an active session id (that is the only thing checked on each form submit).
CreateUser is one of many examples of admin functions. Is the proper solution to this to validate that the user is an admin on each of these different form submits (not sure of a clean way to do this in asp.net)? Or is it acceptable to just expire the session on logout and never reuse session id's? Does asp.net have any other security features built-in to protect against this type of attack?
One way, is to have a base class(Which inturn inherits the class - "page") and all your aspx pages should inherit this base class. so that whenever a aspx page loads, your base pageLoad method is called. In this method you can check the authentication and authorization.
public class BasePage : System.Web.UI.Page
{
public BasePage()
{
this.Load += new EventHandler(BasePage_Load);
}
void BasePage_Load(object sender, EventArgs e)
{
//Check authentication/authorized
//if authenticated/authorized leave it.. If not redirect to error page
}
}
public partial class Forms_CreateUser : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
public partial class Forms_CreateRole : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
User web.config's Authorization settings to restrict access to CreateUser.aspx to users in the admin role: http://support.microsoft.com/kb/316871 (attribute name is roles instead of users).

Custom Principal reverting to GenericPrincipal on new requests

I'm trying to implement a custom principal and custom identity in a .NET MVC website. I've created a custom principal class which inherits from IPrincipal and a custom identity which inherits from IIdentity.
When a user logs in I set both Thread.CurrentPrincipal and HttpContext.Current.User to my custom principal. When I view either through the debugger the values are set with all the properties.
However once the request is complete and I try and request any other pages both Thread.CurrentPrincipal and HttpContext.Current.User are of type System.Security.Principal.GenericPrincipal and not my custom principal.
Do I need to do anything "extra" to get my custom principal out of the thread or HttpContext?
Thanks
The values in Thread.CurrentPrincipal and HttpContext.Current.User are not persisted between requests, they are rebuilt on each request. The best place for you to do this is probably in the Global.asax; write a function with the prototype:
void Application_PostAuthenticateRequest(object sender, EventArgs e)
That should get called after a user is authenticated on each request, which will allow you to set the principal how you would like.
Overridding Principal in:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
Instead of
protected void Application_AuthenticateRequest(object sender, EventArgs e)
In Global.asax.cs worked for me in an ASP web application
I would like to expand on the accepted answer slightly, hopefully I can save somebody a little bit of time.
In my case, the principal I used contained claims that were populated from the results of an external service, so I wanted to cache the results at login time.
I created a simple cache interface, IUserPrincipalCache, and registered it with the MVC DependencyResolver. At login, I build up the principal and add it to the cache. (Since your implementation may vary, I'll leave all that out.)
I then implemented this in Global.asax.cs:
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
var cache = DependencyResolver.Current.GetService<IUserPrincipalCache>();
var claimsPrincipal = cache.FindUser(User.Identity.Name);
if (claimsPrincipal != null)
{
Context.User = claimsPrincipal;
Thread.CurrentPrincipal = claimsPrincipal;
}
}
}
I think it is important to point out the check for IsAuthenticated, since I could bypass the cache check in many cases. You also may not need to update Thread.CurrentPrincipal, I guess that depends on how you're using it.

Determining what Url the user originally entered to visit a web page after redirection

Currently, I'm just using clientside Javascript (location.href), but I am wondering if there is a way in Asp.Net to figure out the URL the user originally entered (assume I did not change it myself via 301), or at least to track it in a simple and reliable manner. As I am using my own implementation of URL rewriting via the global.asax (e.g. Context.RewritePath), this is not an easy task, particularly since I don't want to touch it too much.
Example
Global.asax:
public override void Init()
{
base.Init();
this.BeginRequest += new EventHandler(Global_BeginRequest);
}
void Global_BeginRequest(object sender, EventArgs e)
{
if (VARIOUSCONDITIONS) Context.RewritePath("SOMEURL");
}
SomePage.aspx.cs
protected void Page_Init(object sender, EventArgs e)
{
//Request.RawUrl is equal to "SOMEURL", as
//are other properties that store the URL.
}
Maybe I am misunderstanding your question, but if you are trying to capture the page the user first hits on your website, cant you capture this in the session_start event of global.asax? Then store in sessionstate or database for future use?

How to keep RoleProvider from overriding custom roles?

I have an custom role provider that gets the roles a user belongs to from a database. I also have a custom authentication module registered in my web.config's httpModules which sniffs incoming HTTP requests and (if it's an OAuth signed request) sets the HttpContext.Current.User property to impersonate the user, and the IPrincipal that it sets includes all the user's roles, plus an extra one called "delegated".
The trouble is, after I set my custom IPrincipal, apparently ASP.NET still calls my custom role provider, and then resets the IPrincipal with one that has only the standard roles for that user.
If I set <roleManager enabled="false" ...> in my web.config file, the authentication module's assigned roles stick. Obviously though, I want the best of both worlds. How can I use the role provider, but "cancel" the role provider's effect when my authentication module decides to?
It turns out that in the authentication http module's Init method, I can find the RoleManager, and then hook an event that gives me veto power on whether it does its overriding work:
public void Init(HttpApplication context) {
var roleManager = (RoleManagerModule)context.Modules["RoleManager"];
roleManager.GetRoles += this.roleManager_GetRoles;
}
private void roleManager_GetRoles(object sender, RoleManagerEventArgs e) {
if (this.application.User is OAuthPrincipal) {
e.RolesPopulated = true; // allows roles set in AuthenticationRequest to stick.
}
}
private void context_AuthenticateRequest(object sender, EventArgs e) {
if (/*oauth request*/) {
HttpContext.Current.User = CreateOAuthPrincipal();
}
}

How can I hook into the current FormsAuthenticationModule in a Medium Trust environment?

I've got an HttpModule in my application that hooks into the FormsAuthenticationModule's Authenticate event with the following code:
public void Init(HttpApplication context)
{
FormsAuthenticationModule faModule =
(FormsAuthenticationModule)context.Modules["FormsAuthentication"];
faModule.Authenticate +=
new FormsAuthenticationEventHandler(faModule_Authenticate);
}
Unfortunately, the call to context.Modules fails because the app needs to run in a medium-trust environment. Is there another way that I can hook into this event?
That's a tough one - you can't even access the Modules collection from within your Global application file.
You could try calling your custom code from the AuthenticateRequest handler in Global:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// Call your module's code here..
}
You can't grab your custom module from the collection, either, so you'd need a static reference to your module's library.
Other than granting the AspNetHostingPermission (as detailed for other permissions here) to your site in the machine level web.config, I'm out of ideas!

Resources