ASP.NET MVC How to get allowed users? in windows authentication - c#

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.

Related

Role Manager in Web.Config

I'm trying to develop an ASP.NET MVC application which has few views. I have the following code for controller to restrict access for users:
Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (!string.IsNullOrEmpty(model.ReturnUrl))
return Redirect(model.ReturnUrl);
return RedirectToAction("Edit", "Home");
}
ModelState.AddModelError("Password", "The user name or password provided is incorrect");
}
// if we got this far, something failed, redisplay form
return View(model);
}
In Web.Config:
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="10" />
</authentication>
<authorization>
<allow users="*" />
</authorization>
<membership defaultProvider="LabourTimeProvider">
<providers>
<clear />
<add name="LabourTimeProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="LabourTime" attributeMapUsername="sAMAccountName" />
</providers>
</membership>
<roleManager defaultProvider="CustomRoleProvider" >
<providers>
<clear />
<add name="CustomRoleProvider" type="LabourTime.CustomRoleProvider" />
</providers>
</roleManager>
</system.web>
<location path="Home/Login">
<system.web>
<authorization>
<allow roles="mydomain\mygroup" />
<deny users="*" />
</authorization>
</system.web>
</location>
<location path="Home/Edit">
<system.web>
<authorization>
<allow roles="mydomain\mygroup" />
<deny users="*" />
</authorization>
</system.web>
</location>
In location path, if I use something like,
allow users = "my-user", it is working fine. Only the user is having access.
However, I would like a group of users in the mygroup to access the page. I don't know how to achieve this. I tried this code by doing some research but it didn't work. What to do I do in order to get access for the whole group?
When I try to login using an ID from the group, it doesn't work. Any suggestion is appreciated. Thanks!
There are different ways of achieving access by groups. Since you already use attributes I would suggest using the following approach:
[Authorize(Roles="Administrators")]
public class AdminController : Controller
{
.....
}
When you wanna put logic within your code you can use a construction like this:
if (Roles.IsUserInRole(userName, "ConfirmedUser")
{
.....
}
In your example, it is clear you are talking about a domain joined users group (part of an Intranet). In general Group Policy Objects (GPO) and Security Groups (SGs) are created within in Active Directory (AD), and domain users are member of these SGs.
In other cases DB hosted on DB Server can also be linked to same SGs, and in some cases DBs are not linked to any AD SGs, but have a different login account for an added security.
Access to these SGs are managed by IT Support Specialists of a given organization.
<authorization>
<allow users="*" />
</authorization>
Having said that, upon using <allow users="*" /> within Web.config will only allow domain users whose domain accounts are member of their appropriate Security Groups (SGs), created for their organization with in Active Directory (AD). As long as the application being developed is deployed on Application server joined to same domain, the GPOs and SGs security automatically gets synchronized to users and computer accounts for that domain. Therefore, only users member of SGs are able to access the application within an Intranet.

Role-based restriction not working for ASP.NET MVC Forms Authentication via AD

I've got a ASP.NET MVC page that I'd like to secure with a login and not only authenticate against an Active Directory using Forms Authentication, but also grant access only to specific roles.
web.config
<system.web>
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Home/Login" timeout=45 protection="All" />
</authentication>
<authorization>
<allow roles="Admin" />
<deny users="*" />
</authorization>
...
Controllers
[HttpGet]
public ActionResult Index() {
return View("~/ng-app/index_template.cshtml");
}
[HttpGet, AllowAnonymous]
public ActionResult Login() {
return View("~/ng-app/login_template.cshtml");
}
[HttpPost, AllowAnonymous]
public ActionResult Login(LoginDto dto) {
... // validate dto & stuff
FormsAuthentication.SetAuthCookie(loginModel.Username, loginModel.RememberMe);
}
Now, basic protection and general authentication works perfectly. I can log in with my domain account and I don't have access to any other pages as anonymous users. However, I'm somehow unable to restrict access only to a certain role. When I add <allow roles="Admin" /> to the authorization section, it does absolutely nothing. When I additionally add <deny users="*" />, I lock myself out and even after successful login, the server always returns 302 Found without doing any redirects or serving the actual file.
You should be doing the allowed roles on the controller declaration
So above your actionresult declaration put this above
[HttpGet]
[Authorize(Roles="Admin")]
public ActionResult AuthorizedView() {
return View("~/ng-app/admin_template.cshtml");
}
This will then do a check to see if the user is in the role declared or not
To declare the roles in the webconfig you could do something like below
<authorizationConfiguration>
<controllerAuthorizationMappings>
<add controller="Home" role="GeneralAccess">
<!-- Define allowed roles for actions under the Home Controller -->
<actionAuthorizationMappings>
<add action="MyTopSecretActionForSuperCoolPeopleOnly" roles="Developer,Manager,Fonzie" />
</actionAuthorizationMappings>
</add>
</controllerAuthorizationMappings>
</authorizationConfiguration>
And here is a link to the site
http://www.ryanmwright.com/2010/04/25/dynamic-controlleraction-authorization-in-asp-net-mvc/
There is far to much for me to bring it into this thread, I will turn it in to a wiki answer when I have 5 minutes

ASP.NET MVC 4 Applying Windows Authentication to a single Controller?

I have an MVC 4 application which is open to all users, no login needed. There is one controller only which I need to apply Windows Authentication to via a Web.Config, like this:
<authentication mode="Windows" />
<authorization>
<allow users="domain\jsmith" />
<deny users="*" />
</authorization>
The controller would MySite.Com/MyApp/MyAdminReportController
If this is possible, how?
I think you just need Windows auth and specify paths which are only need authorization. If you don't need Forms auth as well it looks like this:
<configuration>
...
<system.web>
......
<authentication mode="Windows">
</authentication>
</system.web>
<location path="MyAdminReport">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
</configuration>
This is web config approach, other options is adding [Authorize] attribute to your controllers (even not hole controller you can add this attr for only specific actions too).
[Authorize]
public class MyAdminReportController : Controller
{
//[Authorize]
public ActionResult PrivatePage()
{
return View();
}
}

Configuring custom authorization with ELMAH

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.

Validating a user on every page using session information, c# & ASP.NET

My question is more of a request for advice on how to implement a feature to a website using session information. I have a website that asks for username and password on the landing page. When a user successfully logs in, a session is created that stores their username and a few other variables related to the account. In the Page_Load function immediately following login, I successfully access this information attached to the user via session variables, verifying that it is implemented properly.
In the MySession class:
private MySession()
{
Username = Data.User.lblUsername;
CompanyId = Data.User.lblCompanyId;
}
In my welcome page (immediately following successful login)
private void Page_Load(object sender, System.EventArgs e)
{
secure_username = MySession.Current.Username;
...
}
I want to use this information, i.e. secure_username to validate the user once a page is accessed so that people can no longer skip the login form. From MySession class, do I simply use if(MySession.Current.Username == ??) statements to check each variable at the start of the Page_Load function, or is there a proper way to go about this?
Please ask for clarification if it is needed. Thanks.
EDIT: Based on some of the responses given, i think it is important to note that if a user suddenly becomes anonymous (or times out) they should be redirected to the login page.
If you are using form authentication then you can add following tags to web.config to deny any anonymous access. If you do this, you don't have to check if user is logged in on every page.
<authorization>
<deny users="?" />
</authorization>
Add this to allow all users to see Login.aspx so that they can login
<location path="Login.aspx" allowOverride="false">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
Add this so that all your css/images folders are visible to anonymous users
<location path="css" allowOverride="false">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="images" allowOverride="false">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
You may have to add extra location tags based on your website setup and the folders you want any anonymous user to have access to
If login form authentication session expires user will be redirected to url you mention in this tag
<forms loginUrl="Login.aspx" timeout="30">
</forms>
If you need to do the same action on every page it sounds like you need a base class where all your secure pages inherit from:
Base page:
public class BasePage : System.Web.UI.Page
{
public user secure_username
{get;set;}
protected void Page_Load(object sender, EventArgs e)
{
//add your checks that repeat on each page
}
}
Other pages:
public class AuthenticatedUsersPage : BasePage
{
}
Note: This of course assumes that you have already taken care of authorization and authentication on your config file (see rs' answer for more info). Also, if you are using forms authentication, remember to make your session last longer than your forms authentication timeout.

Categories