ASP.NET MVC Authorization for a dynamic path - asp.net

I am using forms authentication with ASP.NET MVC. Within web.config at application level I can set the paths that I require authentication to as follows;
<location path="subdir1">
<system.web>
<authorization>
<allow users ="?" />
</authorization>
</system.web>
</location>
subdir1 is folder name within the Views folder. This works for the web page routing as siteurl.com/subdir1.
However, if my subdir1 is under another dynamically created route, this setting does not work. For instance; siteurl.com/dynamic/subdir1 does not request authentication. dynamic is created at runtime and web.config does not know about it at application start but it should not care about it, I just want it to ask for authentication whenever there is an access to subdir1 route.
Is there any way that I can set the location's path attribute for this case? or do you have any other way to solve this issue?
Any help would be appreciated.
cas sakal

You can control authorization by using the Authorize attribute on the appropriate actions or controllers.
[Authorize]
public ActionResult MyAction()
{
//stuff
}
Some more information can be found at ASP.NET MVC Authorization

You should be using the AuthorizeAttribute on your controllers/actions rather than setting up access in the web.config file for routes that map onto your controllers. You only need to apply the attribute to those actions (methods) that require authorization if not all of your actions require a logged in user.
[Authorize]
public class ProtectedController : Controller
{
// all actions in this controller require the user to be logged in
}
public class MixedController : Controller
{
[Authorize]
public ActionResult ProtectedAction()
{
// this action requires the user to be logged in
}
public ActionResult PublicAction()
{
// this action is available to anonymous users
}
}

Related

How to enable Windows authentication for specific controller in ASP.Net Web API

I was wandering if there is a way to enable Windows authentication only for the particular action of the particular ASP.Net Web API controller. My Web API web service has a couple of controllers with numerous actions, but only one action of one controller needs Windows authentication. This web services is implemented using Web API 2.1, and is hosted in IIS (v7.5 and above). Even though, it’s an intranet web service I don’t want to enable windows authentication on controllers and actions that don’t need it. Please let me know if there is a way to enable Windows authentication for a specific controller and action.
My web service code is similar to the code below. Only endpoint api/controller1/action1 implemented by Controller1.Action1 requires windows authentication. The rest of actions don't need Windows authentication:
[RoutePrefix("api/controller1")]
public class Controller1: ApiController
{
[Route("action1")]
public HttpResponseMessage Action1()
{
return Request.CreateResponse<object>(HttpStatusCode.OK, null);
}
[Route("action2")]
public HttpResponseMessage Action2()
{
return Request.CreateResponse<object>(HttpStatusCode.OK, null);
}
}
[RoutePrefix("api/controller2")]
public class Controller2 : ApiController
{
[Route("action1")]
public HttpResponseMessage Action1()
{
return Request.CreateResponse<object>(HttpStatusCode.OK, null);
}
[Route("action2")]
public HttpResponseMessage Action2()
{
return Request.CreateResponse<object>(HttpStatusCode.OK, null);
}
}
Thank you,
Rita
is this what your want? adding this to your config file.
<location path="api/controller1">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
I had the same problem. The solution was
Enable Windows Authentication in IIS Website, where your API is hosted. If you are using OWIN to self host, see this SO discussion
Then in your controller or controller action, which requires Windows Authentication, just add an "Authorize" attribute.
[Authorize]
public async Task GetDocumentContent([FromUri]DocumentContentRequest request)
{
}
That is it.

Windows Authentication Initialization ASP.net

In a ASP.net WebForms project, we currently use Forms Authentication, but the client wishes to use Windows Authentication instead. So I've changed the web.config to use Windows authentication. However, the application needs some user input and put in into a session before any webpage can be accessed. We currently do this in the postback of the loginpage.
Since Windows authentication does not have a 'Login' page, how can this be achieved? Should I check on every page it's On_Init event if the session has been set correctly..?
If you need a specific data in session available in every single page, the easiest approach would be to have a dedicated module that checks the condition in one of early pipeline events where the session is available (the acquire request state event sounds most suitable).
public class CustomConditionCheckModule : IHttpModule
{
public void Init( HttpApplication context )
{
context.AcquireRequestState += new EventHandler( acq_req_state );
}
public void acq_req_state( object sender, EventArgs e )
{
// check your condition there - the data is in session
var session = HttpContext.Current.Session;
if ( ... the condition ... )
Response.Redirect( "~/anonymous.page.aspx" );
}
}
Then you also need a page that can be accessed anonymously (you need a section in the web.config for this):
<location path="anonymous.page.aspx">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
I think you could go with LDAP (Active Directory Authentication)
with windows authentication in web.config but if its intranet web application or another way i.e. role based security with windows authentication.

asp.net session logout

I have made an asp.net application. This application has session variables which shows that a user is logged in or logged out.
If there any way to capture the expiration of session without going to single pages and once this is logged out user can be redirected to login( Re-login) page?
Can my asp.net classes inherit some base class which can have some abstract method to check if session is existing or not.
Please suggest me some architecture to do this.
Thanks in advance.
This application has session variables which shows that a user is logged in or logged out.
This can be achieved by checking the HttpContext.Current.Request.IsAuthenticated property.
If there any way to capture the expiration of session without going to single pages and once > this is logged out user can be redirected to login( Re-login) page?
Configure the following elements in your applications web.config to restrict\allow access to resources\pages\directories on your site:
<authorization>
<allow .../>
<deny .../>
</authorization>
http://msdn.microsoft.com/en-us/library/8d82143t
And, configure the FormsAuthentication defaulturl and loginurl attributes to redirect users away from restricted resources.
You can use global.asax's session end event:
void Session_End(Object sender, EventArgs E) {
// your code....
}
When the session expire this event called.

Using Custom RoleProvider with Windows Identity Foundation - STS

I created STS that does the authentication part. It uses Custom Membership provider.
After successful login I get redirected to my RP website. All works fine in terms of authentication.
I have defined a CustomRolesProvider defined in web.config of my RP website. It uses the username returned by STS to fetch the roles for that user from RP's database.
When I use Roles.GetRolesForUser I do get the right roles.
I have the following in the web.config of my RP to allow only admin to give access to admin folder.
And the sitemap provider has securityTrimmingEnabled="true"
<location path="admin">
<system.web>
<authorization>
<allow roles="admin" />
<deny users="*" />
</authorization>
</system.web>
</location>
<add name="default" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true" />
Problem:
When the user is in the admin role, the menu tabs for admin pages won't showup. I did check that Roles.IsUserInRole("admin") returns true. So the role is recognized by roles provider but not by authorization rules and sitemap provider in the web.config.
If I comment out the "location" from the web.config i.e. allowing every logged-in user to admin folder, my menu items show up fine.
From my understanding of WIF, RP can have it's own implementation of Roles and does not have to rely on Roles Claim from STS.
Does anyone has any ideas?
Update 2(01/20/2012): I found that the STS returns role claims as below:
http://schemas.microsoft.com/ws/2008/06/identity/claims/role = Manager
So if I change <allow roles="admin" /> to <allow roles="Manager" /> the role is picked up and menu tabs are shown appropriately.
So I am sure I am missing a link on how to make use of my roles and not the one returned via claims.
Update 2(01/20/2012):
If I add the role to the claimsIdentity like below it works:
void Application_AuthenticateRequest(object sender, EventArgs e) {
if (Request.IsAuthenticated) {
IClaimsPrincipal claimsPrincipal = HttpContext.Current.User as IClaimsPrincipal;
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
if (!claimsIdentity.Claims.Exists(c => c.ClaimType == ClaimTypes.Role))
{
claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "admin"));
}
}
}
But then what would be the best place to add that code? If I add it in Application_AuthenticateRequest it's added upon each request and it keeps adding.(I fixed this by adding if statement)
*Update 3(01/24/2012):*Version 2 of my code that uses my CustomRoleProvider to get the Roles and then add it to the ClaimsCollection:
void Application_AuthenticateRequest(object sender, EventArgs e) {
if (Request.IsAuthenticated) {
string[] roleListArray = Roles.GetRolesForUser(User.Identity.Name);
IClaimsPrincipal claimsPrincipal = HttpContext.Current.User as IClaimsPrincipal;
IClaimsIdentity claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
var roleclaims = claimsIdentity.Claims.FindAll(c => c.ClaimType == ClaimTypes.Role);
foreach (Claim item in roleclaims)
{
claimsIdentity.Claims.Remove(item);
}
foreach(string role in roleListArray)
{
claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, role));
}
HttpContext.Current.User = claimsPrincipal;
}
But I am not sure if that's the right way.
Is there anyone who has done something like this??
Update 4 (01/26/2012): Found that I can use Custom ClaimsAuthencationManager(Step 4) to transform my claims.
I moved the code in AuthenticateRequest method in Global.asax to Authenticate method in ClaimsAuthenticationManager class.
I doubt it can get any better than this. I will post my solution as answer. But still if anyone has any other better solution feel free to comment.
You could use a custom ClaimsAuthencationManager, however, it will be called on every request. My recommendation would be to use WSFederationAuthenticationModule.SecurityTokenValidated. Use the ClaimsPrincipal property of SecurityTokenValidatedEventArgs class and add the roles using your provider. Also, instead of hard coding the role claim type, you may wish to consider using ClaimsIdentity.RoleClaimType.
The looked up roles will be saved in the encrypted cookie (assuming you are using the default).
The best solution would be to have an IdP (your current STS) and an RP-STS (or Federation Provider). As you say, if in the future you rely on more than one IdP (e.g. you use Live or Google, etc), it is very unlikely that they will provide the claims you need.
The purpose of the RP-STS is precisely to normalize the claimset to whatever your app requires, without polluting your app with identity concerns.
It would look like this:
An RP-STS is especially useful when you have:
Many IdP (yours and external ones)
Many Aplications
Claims transformations that can apply to many RPs. This, the RP-STS being an "authority" on the knowledge of userX being in role Y. And that knowledge not being exclusive of one app.
Protocol transition functions
The transformation (T) would add/remove claims as needed by each app, independently of the IdP.
The reason your app works when you add a "role" claim, but not with Roles.IsUserInRole, is because in general apps check User.IsInRole, which is resolved against the claimset in the principal, and is completed disconnected from Roles provider. This is arguably, a problem in the way Roles provider is designed.
The drawback of an RP-STS is the extra component you need to manage. There are however, rather simpler options today: ACS (Access Control Service) is one. If you are building a custom STS, you could do any of this of course.
The proper place to transform claims in the RP itself is by writing a Custom ClaimsAuthenticationManager (already identitfied by you). At least, that's the "official" extensibility point for doing it. Other soutions might work too though.

Role based authorization

I am trying to use Role based authorization in declarative way, when unauthorized user attempt to access a page, it never fire an exception or show the user an error message. What I should do to show unauthorized message? is that possible in declarative way?
using coding is not a nice option sense I have several roles, and folder authorized for several roles while other folders are authorized for one role.
thanks
Use the following code in your Login page to redirect the user to either an unauthorized page or the default page.
protected void Page_Load( object sender, EventArgs e )
{
if( Page.IsPostBack )
return;
if( !Request.IsAuthenticated )
return;
if( !string.IsNullOrEmpty( Request.QueryString["ReturnUrl"] ) && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(Request.QueryString["ReturnUrl"], User,"GET"))
{
// In Forms Authentication, authenticated but unauthorized requests are converted into a Redirect to the Login page.
// Redirect these to an error page instead.
Response.Redirect( "~/UnauthorizedAccess.aspx", false );
}
else
{
Response.Redirect( FormsAuthentication.DefaultUrl, false );
}
}
See this link for a picture of what's happening and more info:
http://www.asp.net/security/tutorials/user-based-authorization-cs
If it fails authorization it will throw an exception. It must be passing. What are you using for authentication? Have you disabled anonymous access?
Perhaps you could make use of a site map. More on those here, plus a bit about tying security to them here.
It's also possible to use web.config to set up permissions for various folders or files. Each folder could have a list of allows or denys like so:
<?xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<allow roles="Administrators" />
<allow roles="Random Role" />
<deny users="*" />
<deny users="?" />
</authorization>
</system.web>
</configuration>
Then when someone hits the page that requires authorization that they don't have permission for it will redirect them to your login page. You could then check the query string for the page they came from and perhaps set up case specific responses, or at the very least if it has a returnURL page on it, say "You are not authorized to see this page."

Resources