How do I go about Authorization in MVC 2?
I want to use AD groups/roles rather than the default that is provided. That seems to be "AspNetSqlMembershipProvider".
Anyway I put :
[Authorize(Users = "username")]
public ActionResult About()
{
ViewData["Welcome"] = "Welcome About";
return View();
}
And then loading the page gives me: The connection name 'ApplicationServices' was not found in
the applications configuration or the connection string is empty.
Line 34: <providers>
Line 35: <clear />
Line 36: <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
Line 37: </providers>
Line 38: </membership>
I read this stackoverflow, but after creating a custom class AuthorizationAttribute extending ActionFilterAttribute ContextCache, IoC and a number of other things could not resolve, and not really sure where to go from there. I also read this stackoverflow and it suggests going about it differently, starting to get confused.
How do I go about using AD groups rather than AspNetSqlMembershipProvider in MVC app ?
Bonus question: Say I have a "Edit" button a page. Can I add logic to decide whether to render this button based on the Authorization ?
Thank you for your help.
Edit: some further information.
I do not intend to block or allow ALL access to this site.
I intend to have 3 basic user groups differentiating level of access, i.e. Super Admin, Admin,
Basic Access.
There will be no log in form, when the user hits the site we will check which group the user is a member of- then the page renders based on that.
So for example, user 'bob' in 'Basic Access' group will hit the page and buttons/actions like "Edit", "Delete" are disabled, so basically a read only group. But user 'jim' in group 'Super Admin', has all actions/buttons available to him. How could I achieve this ?
You should look into Windows Authentication
Still use the Authorize attribute on your controllers/actions, but configure your site to use Windows Authentication instead.
Bonus answer: To check authentication and authorization in code, you can use one of the following from a controller:
this.User.Identity.IsAuthenticated
this.User.Identity.Name
this.User.IsInRole("roleName")
The answers to use Windows authentication work great, with the following caveats.
First, the server must be joined to your Domain. And it has to have free AD access if there are any firewalls in place.
Second, you have to be ok with having a popup dialog for login, rather than using a form based login.
If you need AD with forms login, then there's more work involved. Can you be more specific about your needs?
well, you can restrict access to the site via webconfig.
<authentication mode="Windows" />
<authorization>
<allow roles="[YOURADSERVER]\[YOUR AD GROUP]"/>
<deny users="*"/>
</authorization>
this will block any others not listed in the given ad groups.
in IIS you will need to disable anon access and enable windows auth
Related
web.config
<roleManager enabled="true" defaultProvider="SqlRoleManager">
<providers>
<clear />
<add name="SqlRoleManager"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="DefaultConnection"
/>
</providers>
</roleManager>
in asp.net mvc 5, i'm trying to detect the role of the current user so i can redirect him to a page specific to it's role but
in my controller
if (Roles.IsUserInRole(User.Identity.GetUserName(), "superadmin")
or
if (Roles.IsUserInRole(User.Identity.Name, "superadmin")
the both are not true, i'm sure that i'm logged bec User.Identity.GetUserName() is displaying my login
Trying to debug, i found that Roles.GetRolesForUser() is empty, i've checked online resources but still no solution
Further debugging shows that Roles.GetAllRoles() is also empty, but my AspNetRoles table has 5 records.
I've looked at AspNetUserRoles and i found my current User id assigned to specific role id
and i've successfully run aspnet_regsql.exe to add all features but still cannot get the Roles
i think aspnet_regsql.exe is for web forms (i'm not sure)
I'm on my phone so can't double-check, but I'm sure IsUserInRole() will accept a single argument like IsUserInRole("superadmin") to check the current user in a session. I would remove the username part because you're checking the current user and not a different named user. It's quicker and will at least check and eliminate one part of the logic.
How are you seeding the roles?
I wanted to build a membership system at the beginning of my MVC project and I used Membership.ValidateUser method to verify credentials. However I could not understand how does this method access my database and check my email and password informations.
[HttpPost]
[ActionName("Login")]
public ActionResult Login(LoginModel loginModel)
{
if (Membership.ValidateUser(loginModel.Email, loginModel.Password))
{
FormsAuthentication.SetAuthCookie(loginModel.Email, true);
return Json(true);
}
return new JsonNetResult()
{ Data = new { Error = true, Messages = new[] { new { Message = "Wrong username or password" } } } };
}
It' used the MembershipProvider specified on your Web.config file to validate the user. By default, it uses DefaultMembershipProvider
Membership.ValidateUser method at first check membership defaultProvider in your web.config file which matches with name that you provide like below:
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider"
connectionStringName="Context" applicationName="myapp"
enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="true"
passwordFormat="Hashed" minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="0" />
</providers>
</membership>
Above configuration will call .net framework abstraction class MembershipProvider -> ValidateUser (abstract method) which implementation lies in SqlMembershipProvider -> ValidateUser method that you have configured in your web.config file [like above].In that method it simply call two store procedures of your database , first one is aspnet_Membership_GetPasswordWithFormat which check your application name, username , last login activity date and current time and based on that makes you authenticate and secondly call to other store procedure which name is aspnet_Membership_UpdateUserInfo which is self explanatory as you realize which update aspnet_membership table with columns like islockedout, lastlockoutdate, failedpasswordattemptcount.. etc.
Hope this helps you.
I am using AspNet Membership Provider in MVC 3.
I am facing issue in change password.
I have two functionality in my project
Forgot password : ask security question and based on security answer change password.
Admin change password: a admin can change password of any user without knowing old password or security answer.
Now the issue is that for functionality # 1, i have to make changes in web config for making requiresQuestionAndAnswer="true" for change password so that i can change password only if security answer is valid.
<membership>
<providers>
<clear />
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
and i am using below code for changing password in forgot password:
string resetPassword = res.ResetPassword(model.PasswordAnswer);
MembershipService.ChangePassword(model.Username, newPassword, model.NewPassword)
now for situation # 2, where for admin i wants facility to change password of any user without knowing old password or security answer. which is only possible (as i know) by making requiresQuestionAndAnswer="false" .
Note:I am using separate MVC AREA for admin part, so may be a another web config can do some magic.
please suggest how can i have have both the features (reset password with security answer and without security answer) together in single application.
Thanks a lot
Finally got the answer:
In web config i set the requiresQuestionAndAnswer="true" so this resolves the issue#1, now for forgot password a security answer is required.
and for issue#2 where i want the facility for admin to change password of any user without knowing old password or security answer. I have used Reflection for it to change the value of private variable _RequiresQuestionAndAnswer to false then reset the password and then again set its value to true:
var _requiresQA = Membership.Provider.GetType().GetField("_RequiresQuestionAndAnswer",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
//change the value in the private field
_requiresQA.SetValue(Membership.Provider, false);
//do the reset
tempPassword = user.ResetPassword();
//set it's original value
_requiresQA.SetValue(Membership.Provider, true);
I got this solution at : http://djsolid.net/blog/asp.net-membership---change-password-without-asking-the-old-with-question-and-answer
Got the following ProviderException :
The Role Manager feature has not been enabled.
So far so good.
Is there somewhere a method that can be called to check if the Role Manager has been enabled or not?
You can do this by reading from the boolean property at:
System.Web.Security.Roles.Enabled
This is a direct read from the enabled attribute of the roleManager element in the web.config:
<configuration>
<system.web>
<roleManager enabled="true" />
</system.web>
</configuration>
Update:
For more information, check out this MSDN sample: https://msdn.microsoft.com/en-us/library/aa354509(v=vs.110).aspx
If you got here because you're using the new ASP.NET Identity UserManager, what you're actually looking for is the RoleManager:
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
roleManager will give you access to see if the role exists, create, etc, plus it is created for the UserManager
I found 2 suggestions elsewhere via Google that suggested a) making sure your db connectionstring (the one that Roles is using) is correct and that the key to it is spelled correctly, and b) that the Enabled flag on RoleManager is set to true. Hope one of those helps. It did for me.
Did you try checking Roles.Enabled? Also, you can check Roles.Providers to see how many providers are available and you can check the Roles.Provider for the default provider. If it is null then there isn't one.
I found this question due the exception mentioned in it. My Web.Config didn't have any <roleManager> tag. I realized that even if I added it (as Infotekka suggested), it ended up in a Database exception. After following the suggestions in the other answers in here, none fully solved the problem.
Since these Web.Config tags can be automatically generated, it felt wrong to solve it by manually adding them. If you are in a similar case, undo all the changes you made to Web.Config and in Visual Studio:
Press Ctrl+Q, type nuget and click on "Manage NuGet Packages";
Press Ctrl+E, type providers and in the list it should show up "Microsoft ASP.NET Universal Providers Core Libraries" and "Microsoft ASP.NET Universal Providers for LocalDB" (both created by Microsoft);
Click on the Install button in both of them and close the NuGet window;
Check your Web.config and now you should have at least one <providers> tag inside Profile, Membership, SessionState tags and also inside the new RoleManager tag, like this:
<roleManager defaultProvider="DefaultRoleProvider">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=NUMBER" connectionStringName="DefaultConnection" applicationName="/" />
</providers>
</roleManager>
Add enabled="true" like so:
<roleManager defaultProvider="DefaultRoleProvider" enabled="true">
Press F6 to Build and now it should be OK to proceed to a database update without having that exception:
Press Ctrl+Q, type manager, click on "Package Manager Console";
Type update-database -verbose and the Seed method will run just fine (if you haven't messed elsewhere) and create a few tables in your Database;
Press Ctrl+W+L to open the Server Explorer and you should be able to check in Data Connections > DefaultConnection > Tables the Roles and UsersInRoles tables among the newly created tables!
If you are using ASP.NET Identity UserManager you can get it like this as well:
var userManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roles = userManager.GetRoles(User.Identity.GetUserId());
If you have changed key for user from Guid to Int for example use this code:
var roles = userManager.GetRoles(User.Identity.GetUserId<int>());
<roleManager
enabled="true"
cacheRolesInCookie="false"
cookieName=".ASPXROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All"
defaultProvider="AspNetSqlRoleProvider"
createPersistentCookie="false"
maxCachedResults="25">
<providers>
<clear />
<add
connectionStringName="MembershipConnection"
applicationName="Mvc3"
name="AspNetSqlRoleProvider"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add
applicationName="Mvc3"
name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>
Here is the code that you need to put in your Account Controller in MVC5 and later
to get the list of roles of a user:
csharp
public async Task<ActionResult> RoleAdd(string UserID)
{
return View(await
UserManager.GetRolesAsync(UserID)).OrderBy(s => s).ToList());
}
There is no need to use Roles.GetRolesForUser() and enable the Role Manager Feature.
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.