Role based authentication in the new MVC 4 Internet template using simplemembership - asp.net-mvc-4

I like the new simplemembership feature in MVC 4 internet template with links to OAuth for external logins in VS 2012 RTM. For the most part authentication feature are working. However even after spending over 8 hours on this I am unable to implement roles based authorization to work on my controllers. SimpleMembership is turning out to be anything but simple.
I have searched stackoverflow, googled and have read the latest by John Galloway, tried many suggestions and still have not been able to resovle this issue. It all started with getting Sql connection error and could not figure out why when the connection string and everything else was good. It took many hours to figure out the it is Roles class that is causing problem.
The [Authorize] attribute on controllers works as before for basic authentication. But any time I try to use Roles it give sql connection error (because it reverts to the old DefaultRolesProvider which tries to connect to default SqlExpress aspnetdb file and fails). So something like:
[Authorize(Roles="admin")]
does not work. It will work if I go back to the old asp.net membership providers, but then I lose the simple database tables, token bases confirmation and recovery, more secure password hashing and more importantly external logins via OAuth.
The only thing that works inside code and razor views is
User.IsInRole("admin")
which is OK for menu items and such, but ver cumbersome to implement inside every single Action in controller (and I do not like that it only tests for single role at a time).
I will greatly appreciate any guidance to resovle this issue.

Found an answer here by Mehdi Golchin which seems to take care of:
[Authorize(Roles="admin,editor,publisher")]
If I also add this to the home controller:
[InitializeSimpleMembership]
Because this attribute is on the Accounts controller, SimpleMembership database gets initialize only after the first use of the accounts controller like login/register. Even when the current user gets logged in from the cookie, the database is not initialized and so it throws an error. One solution is to put this attribute on the home controller which gets called when I launch my Website. But, then it needs to be placed on every controller because I check roles and display different menu items based on role.
This is poor design as the database should be initialized on the App_Start and not when first used.
I did try to put
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
in the Global.asax Application_Start(), and it takes care of role checking in menu items using User.IsInRole("admin"), but then throw error in any controller with [Authorize(Roles="admin")] attribute, even with additional attribute [InitializeSimpleMembership] is applied.
So right now the solution is to put `[InitializeSimpleMembership] on all controllers as a user may initially land on any page using external links.
It still can't figure how to initialize the SimpleRolesProvider class to do more of the role management instead of just User.IsInRole().
These things do work better in the webmatrix webpages site and obviously the port ot MVC is not complete. It conflicts and gets confused with the default asp.net membership providers.
EDIT
OK I was not thinking [InitializeSimpleMembership] filter could be applied globally by putting this line in the FilterConfig.cs in the App_Start folder:
filters.Add(new InitializeSimpleMembershipAttribute());
That takes care of that problem. Now need a solution for SimpleRolesProvider initialization or else I will have to write my own roles provider.
UPDATE:
This post by Scott Allen has solved all my problems.
By including this in web.config:
<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear/>
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear/>
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData"/>
</providers>
</membership>
all the methods of Roles and Membership classes become available and can be initialized in code as follows:
var roles = (SimpleRoleProvider) Roles.Provider;
var membership = (SimpleMembershipProvider) Membership.Provider;

Had the same problem when I was moving my web app from VS2010/MVC3 to VS2012/MVC4.
And couldn´t get [InitializeSimpleMembership] to work.
Found out that adding this to your web.config does the trick:
<appSettings>
<add key="enableSimpleMembership" value="false" />
</appSettings>
And everything works fine as it did before.

Related

ASP Net MVC Core - Load User Data From Active Directory when User browses Any Page

Here is my development environment:
Intranet Website
Active Directory Authentication/Authorization
Asp Net Core
I am trying to get the data stored in Active Directory attributes when a user enters firstly to any page in our application. All users rights and permissions, employeeid, studentid, etc.... are stored in AD Attributes and Security Groups. Some Attributes need to be displayed on the website too.
Let's say my website got the following urls...
http://mysite/Home/Index
http://mysite/Student/Index
http://mysite/Student/MyJobs
http://mysite/Staff/Applications
etc....
Any users can go onto some areas/urls of the website freely from other Intranet portals and I don't know where should I write the code to fulfill that criteria. The problem is that, there is no specific entry point to the application like http://mysite/Login or Authenticate, etc. If there is, I could load all users details and rights from AD on that single entry point.
In MVC5 era, I used Custom Global Authorize Attribute and put it on the BaseController is inherited from all other controllers to load that AD data. I put the AD's data into Session on the first hit and use the Static Class to display on Views and use in Controllers. But when I did some research in MVC Core, some say that it's outdated and I should use the Authorize Policy instead of custom Authorize Attributes.
Getting the data from Active Directory is already achieved by using my old webservices and we don't need to worry about .Net core not supporting AD yet.
I looked at the tutorials about Policy and saw something about Claims and Custom User Managers. I couldn't decide which one I should use to load data from Active Directory to the object (probably Scoped Object DI) which lasts for the whole user's session.
Should I load the data onto claims attributes
Eg...
var claims = new List<Claim>();
claims.Add(new Claim("UserName", "John.Smith", ClaimValueTypes.String, Issuer));
claims.Add(new Claim("RefNo", "02343001", ClaimValueTypes.String, Issuer));
claims.Add(new Claim("Email", "MyEmail#email.com", ClaimValueTypes.String, Issuer));
Or Should I write customized SignInManager and IdentityUser?
Eg...
public class ApplicationUser : IdentityUser
{
public string RefNo { get; set; }
public string Email { get; set; }
}
Is there anywhere I could put my code to check AD and load data?
And should I store the data in that Claimed Object rather than using Session Data?
Could you guys please advise me? Feel free to criticize if I miss anything and my idea is not working.
You're right in saying there's no System.DirectoryServices yet (it's on the backlog, I promise) so there are a couple of places to do this.
If you're already using Integrated Authentication you have SIDs for group membership, which are resolved when you call IsInRole(), so you can use role based membership (rather than Claims based) to solve basic authentication problems.
However if you want to support a forms based mechanism then you should look at using the cookie middleware, raw, to at least give you a simple login, calling your web service to validate your login. You could query your API in the controller code, and write an identity cookie. This cookie automatically encrypted and signed, so it can't be tampered with.
The problem comes when you want roles, and attributes. If you head down the cookie route you might be tempted to put all of those as claims in the identity before writing the identity out as a cookie. This might work, provided there are not too many - cookies have a maximum size (browser dependent, but under 4k usually). You can used chunked cookies, but there's a performance impact here. Instead you might use a reference cookie, where you put in a reference to another store where the actual fully populated identity is stored, be it session, redis or something else.
Then in the claims transformation middleware you can pull the reference out, go to your store, and rehydrate the identity.
I'd honestly avoid trying to merge all of this into ASP.NET Identity. That's mean to be the sole source for user information in an application, and in your case that's not true. Your sole source should be AD.
There's also a port of Novell's ldap library to core, which should stand in nicely for DirectoryServices should you want to avoid your web services approach.

Dynamic Roles/Hierarchy with SimpleMembership

I finally got my MVC 4 application all set up with SimpleMembership, but now have run into a new problem. I have a menu system (in a sidebar) that gives users access to various functionality throughout the app. I recently realized that, in order to be somewhat user-friendly, I need to disable or remove various menu links based on roles. So I set up a role system and a relationship to these menu links, which works perfectly. However, the "basic site access" role should not have access to all of the links in the menu (and their corresponding controllers/actions). Previously, I had given site access by simply applying the Authorize attribute globally, via my filter config:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
}
Now I've figured out that, in order to control "basic" access to the app, I would need to add individual Authorize attributes at the action level (with the "admin" role having full access). While this is fine, albeit somewhat annoying, it doesn't seem very scalable. What if my client adds a new role through the administration interface and wants to control access to various tasks? I have already coded the menu system to disable links dynamically, based on what roles have access to which tasks. But there's no way (that I know of) to dynamically apply different roles to the Authorize attribute.
Though I've read about why SimpleMembership may not be the bee's knees, I've just finished migrating from ASP.NET Membership (which had serious shortcomings of its own), and I certainly do not want to roll my own user/role management system. Has anyone successfully implemented something to handle this scenario?
You should definitely take a look at Fluent Security if you have a lot of controllers/actions that you don't want to decorate with annotations.
It allows all authorisation to be handled from Global.asax. It's well documented and there's a good tutorial on it here.

How to setup login? Forms Authentication

so I started building a website in MVC 4 with a template and everything was going fine. But, I felt that there were a lot of features already added into the template that I didn't understand in the slightest and therefore it was a challenge using some of those features properly. One such feature being the login system.
Now I managed to to setup and talk to my external database without to many hassles, but I was/am at a complete loss on how the template knows the users name and that he is logged in.
So I am trying to recreate/setup the same functionality, but from scratch so I can understand how it actually works. That being said... I am lost!
[AllowAnonymous]
public ActionResult Login(LoginModel model)
{
try
{
var canLogin = Services.Login(model.Username, model.Password);
var cas = Services.CheckAcountStatus(canLogin.Token);
if (cas.Payload.Items.Exists(m => !m.IsSynchronized)) RedirectToAction("VerifyPin", "Account", cas.Payload);
return RedirectToAction("Index", "MyPage");
}
catch (CustomException ase)
{
ModelState.AddModelError("", ErrorCodeToString(ase.Error));
}
return View(model);
}
This is what I have thus far.
<authentication mode="Forms">
<forms name="MyName" loginUrl="~/Account/Login" timeout="30" />
</authentication>
A lot of examples have explanations for setting up a database using EF and such, but im afraid that is the equivelant to my external database.
Is a database really needed to know if a user is logged in? or is it more just a cookie?
Beyond this I don't know where to go. If someone could at least point me in a good direction I would appreciate it.
In the end my only real goal is to have an easy way for communication between pages that a user is logged in.
if (Request.IsAuthenticated)
{
// Lets us know if the Request is authenticated
}
A simple answer to: "In the end my only real goal is to have an easy way for communication between pages that a user is logged in."
I would suggest reading about the configuration options for forms authentication in the web.config as well as researching the inner workings of the formsauthentication ticket. MVC also has the Authorize Attribute you can use.
http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.108).aspx
ASP.NET MVC 4 introduced a new membership provider called SimpleMemberhsip which is very flexible and easy to use. Here is an article that shows you how to customize SimpleMembership, which may be the best approach for you instead of trying to build a security framework from scratch that is compatible with ASP.NET forms authentication. Forms authentication relies on cookies to tell if a user is logged in across pages. I do not see anything in your code example that handle the cookies. If you look at the Login method that is generated by the Internet template you will see that the method WebSecurity.Login not only handles authenticating the user, it also handles generation of the cookie.

WCF REST - how best to architect for multiple users but also limit access

I'm new to WCF and REST so please excuse any obvious questions.
I'm trying to create a RESTful API that will be used by clients. The API needs to be available only to authenticated users so I believe the best way to do this (from what I've read over the last couple of days) is using Basic Auth over SSL which is fine.
I have a basic WCF REST Service Application in VS2010 targeting .NET 3.5. - the bare bones of this have been directly taken from http://www.codeproject.com/KB/WCF/BasicAuthWCFRest.aspx
What I'm struggling to understand and to differentiate on is how to authenticate suers while also restricting the calls that clients can make based on who they are.
So the call that the clients will need to make will pass some basic information from their system to ours, each client will be able to make the same call however I don't want client A being able to post info into client B's area on our side and vice versa.
I was planning on having both clients POSTing something like the following url:-
api.mydomain.com/sale/
however, I wonder if it would make more sense to make it clearer to do this:-
api.mydomain.com/clientA/sale/
api.mydomain.com/clientB/sale/
...as you can see, I'm quite lost!
Also, the example code I have is using a custom MembershipProvider - I understand the basics of Membership but again, don't know if I should be using this in some way to restrict the clients posting data to eachothers areas?
Sorry for the waffling - sooo many questions :(
Regarding authorization (granting an authenticated use access to specific resources) there's a couple of ways.
You can restrict access to certain areas (directories / URL paths) via the <location> element in the web.config, and then using the <authorization> element only allow certain users or roles (groups) to access those locations. This is OK if the number of locations / users / roles is manageable and doesn't change too much. For example:
<location path="ProtectedPlaces/Foo">
<system.web>
<authorization>
<allow roles="FooGroup"/>
<deny users="*"/>
</authorization>
</system.web>
</location>
Alternatively, under the covers you can use an API based approach that essentially does the same thing. There are a number of libraries out there that can help, including AzMan; an authorization library that's in the same 'family' as the role membership provider; there is also one in the Enterprise Libraries.
This article might be of some help (see: "Step 2: Limiting Functionality Based On the Currently Logged In User’s Roles").
Here is how I did this. I used a standard membership provider (but you can also do the same with a custom membership provider) to authenticate the user, but I do not let IIS do this. I authenticate the user myself (as part of the REST API) and generate a token for that user, which I store in the membership database and send back to the client.
For each request the client makes it needs to send a valid token as well. As the token is stored together with a user id, I can then determine if the token is valid and what user is making the request. Because of this I can then determine if the request is allowed based on my own security rules.
If a user is only allowed to do a certain request on it's own data, then you don't need to send any identifying information except for the token.
HTH.

WCF Authorization - access to operations via claims

I am trying to implement authorization for a WCF service but I have run into some significant difficulties. I think I need to use a hybrid solution combining custom authentication and claims, but I am not sure if this is correct.
My application uses Windows authentication to connect to the application. Once the user has been authorized, access to functions needs to be granted based on permission information stored in the database.
Users can be assigned permissions via the application interface. One level of the permission heirarchy corresponds to access to individual WCF functions:
Access to module (purely organizational)
Access to function (access to WCF function, checked automatically)
Function-specific permissions (checked dynamically in code)
Sample structure and usage:
Shipping
Can Create Shipment
Can override naming conventions
Can Package Shipment
Must be verified by supervisor
Can generate customs documentation
...
class ShippingService : IShippingService
{
// Access corresponds to "Can create shipment" permission
public bool CreateShipment(string name)
{
...
// Check the function-specific permission dynamically.
if (!ConformsToNamingConvention(name) && !CheckPermission(Permissions.CanOverrideNamingConvention))
return false;
....
return true;
}
}
I think what I need to do is to create a custom Authorization Policy by implementing IAuthorizationPolicy. This will connect to the database, pull the permissions for the user and add a claim for each of the permissions. I will then need to create a custom authorization manager that will compare the requested action with the list of claims to determine if the connecting user is authorized.
Is this the correct way to approach this, or am I:
a) overcomplicating the issue, or
b) using WCF components incorrectly (such as claims, IAuthorizationPolicy, AuthorizationManager...)
Thanks in advance for any help, and best regards.
The problem you'll have with this approach as with just about all the other approaches is the fact you want to allow business users to create and delete roles on the fly. How are you even going to check that in code? Typically, you'd restrict execution of a method or service call to a specific role (or set of roles) - how is this going to work if you want to have roles that get created dynamically at runtime?
If you can live with pre-defined roles, there's a few solutions. Have you checked out the ASP.NET role provider? It's part of the more general ASP.NET membership and role provider set, but it can be used on its own, too.
To activate it, use this snippet in your config (once you've set up the basic infrastructure for the ASP.NET role provider stuff):
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceAuthorization principalPermissionMode ="UseAspNetRoles"
roleProviderName ="SqlRoleProvider" />
</behavior>
</serviceBehaviors>
</behaviors>
The only other idea I have is looking at the Authorization Manager (AzMan): this is a set of tools to allow you to specify fairly granular "atomic" permissions that a business user can then compose into roles and assign users to those. But basically, in the end, at the bottom level of the granular program functions ("Tasks" in AzMan), you're dealing with a static set of rights, again.
Check out this MSDN article on AzMan as an introduction and see this article in the WCF security guidance on how to use it from a WCF service. I don't know the current status of AzMan and I don't know if it will be developed much further anymore - it almost seems a bit like it won't (but I'm not 100% sure on that).
Marc