custom Role Provider initilized but not being used? - asp.net-mvc

I am trying to use a simple custom role provider and using the code from here: http://code.google.com/p/sfckopanka/source/browse/trunk/App_Code/OdbcRoleProvider.cs?r=45
Which is implemented using this: http://msdn.microsoft.com/en-us/library/tksy7hd7(v=vs.100).aspx
This is all just simple boilerplate code from Microsoft.
When I debug my app I can see that my Role Provider is initialized BUT no methods are ever called when I try to check roles.
[Authorize(Roles="Customer")]
or
User.IsInRole("Customer")
I put break points in several places in my role provider and they are just never hit.
FYI I am using WebAPI and I am not using a Membership Provider, instead I am using Basic Auth via a message handler.
http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/
The Basic Auth is working great, but I ma not sure if this is what is preventing my Role Provider from being called.

Answering this in case it can help someone else. In the Basi Auth code linked above there there is a PrincipalProvider class. in this class you create a GenericPrincipal, which also takes the roles that the user is in, so I just had to add a line of code to get my roles to provide to the GenericPrincipal
public IPrincipal CreatePrincipal(string username, string password)
{
if (!MyRepo.Authentication.ValidateUser(username, password))
{
return null;
}
var identity = new GenericIdentity(username);
//Code to get my roles from my role provider to use when setting principal
string[] roles =Roles.Provider.GetRolesForUser(username);
IPrincipal principal = new GenericPrincipal(identity,roles);
ShopZioRepo.ClearUserCache(ShopZioGlobal.MyCookies.UserID);
var user = ShopZioRepo.GetUserByEmail(username);
ShopZioGlobal.MyCookies.UserID = user.SalesRepID;
ShopZioGlobal.MyCookies.Username = username;
return principal;
}
Hope this helps someone.

Related

Windows Authentication use groupsid claims instead on role claims in IsInRole function

I'm building MVC 5 webapp with Windows Authentication.
Since I have external authorization store, so I want to add some custom claims authentication. I handle the PostAuthenticationRequest event
void Application_PostAuthenticateRequest()
{
if (Request.IsAuthenticated)
{
var id = ClaimsPrincipal.Current.Identities.First();
...
//query authorization store
id.AddClaim(new Claim(ClaimTypes.Role, "SomeRole"));
}
}
Then in controller, I check the IsInRole("SomeRole") , but I found it always return false even the identity have the SomeRole role claim
Then I found out that in Windows Authentication, the IsInRole() is using groupsid claims as role
Instead of add my custom claim to groupsid claim, how can I set the IsInRole function use the standard Role claims?
Look like RoleClaimType is the way to go, but it is readonly I cannot set it.
I don't think you can change the behavior of the WindowsPrincipal.IsInRole method.
What you can do is create a new ClaimsPrincipal from a new ClaimsIdentity, using the claims from the WindowsPrincipal. One of the ClaimsIdentity constructors lets you specify the nameType and roleType.
Having set the new ClaimsPrincipal, your IsInRole calls should work on the specified roleType.

asp.net identity with domain controller

I need to achieve to authenticate users with their domain user/password, if they're are in the domain controller, but the application should be available for other users as well, who should be authenticated with their own username/password; this should be stored in the application database, and their username/password to be checked against the DB.
So far i started with new asp.net template in vs2015, choosing Individual User Accounts.
I'm able to authenticate users agains domain controller, but if that is succeeded I'm unable to store the user to HttpContext.User property.
In SignInManager i call PasswordSignIn and return Success or Failure depending on AD check.
public SignInStatus PasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout) {
if(AuthenticateAD(userName, password)) {
//
// to create identity/principal and assign to HttpContext.User
//
return SignInStatus.Success;
}
else {
return SignInStatus.Failure;
}
}
public bool AuthenticateAD(string username, string password) {
using(var context = new PrincipalContext(ContextType.Domain, "domainname")) {
return context.ValidateCredentials(username, password);
}
}
thanks for any hint!
The only way this really works is if you create proxy users in your application for users in AD. Essentially, you just set up a script that populates new users/updates existing users based on the data in AD on a schedule (nightly, etc. based on your needs). Then, you're dealing with just one type of user whether they're part of the domain or external. The only change you need to make is to selectively authenticate via AD or via the standard password authentication. Either way, the same user principal is in play.
You can use ADFS and allow users to choose where to authenticate. It is quite trivial to implement using default template. Just like usual login mechanics with Sign-in via google and local account.
I think this is most correct way of doing things, because domain users may end up with Kerberos/Ntlm, if they want, and it lowers complexity of your system.
Here is a WS-Fed example: Using Claims in your Web App is Easier with the new OWIN Security Components
For other stuff you can create app with default template. This app will have external authentication stuff as example.

how to implement User.identity.getUserEmail()

A user should have unique email instead of UserName. To achieve this I stored email in UserName and UserName in email column of AspNetUsers Table. Now I want to access user name in my view. The method User.Identity.GetUserName() is great, But now I need User.Identity.GetUserEmail(). I can I implement User.Identity.GetUserEmail() ?
Update:
I have to use User.Identity.GetUserEmail() in every view. As I use User.Identity.GetUserId().
I want to write this method in Microsoft.AspNet.Identity namespace so that it will be accessible everywhere.
I had to add a new value to the Identity model and to get the new value I did this:
private string GetUserEmail()
{
//Instantiate the UserManager in ASP.Identity system so you can look up the user in the system
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
//Get the User object
var currentUser = manager.FindById(User.Identity.GetUserId());
return currentUser.Email;
}
You can build this in a relevant controller, or it can be a static function somewhere else, you just need to have a reference to identity.
Personal note: I have to say that I don't fully support the idea to change between the username and email. I think you should consider editing the model instead , this link might help.
Let me start by saying that I don't like the idea of executing code in your view. Besides, if you do this everytime, you're breaking the DRY principle.
I think what you need here is the ASP.NET Identity framework. This allows you to customize the authentication & authorization process, including how and where to retrieve user information. By overriding the UserManager class, you can start overriding the methods you want (like GetEmailAsync). You could also modify the CreateUserIdentity method by changing the claims of the identity.
This way you only define your rule once, which you then can use all across your application. But in order to achieve this, you'll have to do some research about ASP.NET Identity yourself or post more accurate information (like your accountcontroller code).
When creating a user through the user manager you can apply some custom settings, one of these is requiring an unique email:
var um = new UserManager<User>(new UserStore<User>(new ApplicationDbContext()));
um.UserValidator = new UserValidator<User>(um)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};

Add roles to ADFS IPrincipal

I have been looking for answer to this question for a few days now, but I have not found any success. I would post the links, but it would probably take up the entire page.
So here is what I have...
I have an MVC application, which uses the WC-Federation protocol. I have been able to configure the application, so that it authenticates the users, and returns the claims from ADFS. This works perfect. I can also extract all the claims with no issues. But I am doing this within one of the actions in the controller.
And here is what I want to do...
I want to use ADFS to authenticate the user, but I want to use my own internal roles to authorize the user to have access to specific controllers (e.g. [Authorize(Roles = "CoolRole")]). I want to be able to do this, because I already have a Web API that uses OAuth 2.0, with a backend SQL Server database to manage users and roles (internal and external user.) I now want a secure portal that will allow internal users to access the data with a single-sign-on experience. Looking at the Controller model, I noticed there are some properties associated with the authentication process (OnAuthentication, OnAuthenticationChallenge) and one for the authorization process (OnAuthorization.)
I don't necessarily need the code, but I feel like I've hit a brick all, and I need to be pointed in the right direction.
UPDATE
I tried this:
protected override void OnAuthorization(
System.Web.Mvc.AuthorizationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.HttpContext.User = user;
base.OnAuthorization(filterContext);
}
This returned a 401 (Unauthorized) response.
and...
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.Principal = user;
base.OnAuthorization(filterContext);
}
This just calls the STS numerous times, before it fails. I even tried swapping after the assignment to after the base is called in both. No luck.
Prior to the previous ones, I also tried to add an AuthorizeFilter to the control, but that didn't help:
http://pratapreddypilaka.blogspot.in/2012/03/custom-filters-in-mvc-authorization.html
I found this link: http://brockallen.com/2013/01/17/adding-custom-roles-to-windows-roles-in-asp-net-using-claims/
From there, I guessed my way through
Here is the basics of what I did:
I ended up overriding the OnAuthentication method of the Controller, but still made sure to call the base. I did this from within an extended class. Here is the concept:
public class AdfsController : Controller
{
//Some code for adding the AppUserManager (used Unity)
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
//Private method to set the Principal
_setCurrentUser(filterContext.Principal);
}
private void _setCurrentUser(IPrincipal principal)
{
//Put code to find to use your ApplicationUserManager or
//dbContext. roles is a string array
foreach(var role in roles)
{
((ClaimsIdentity)((ClaimsPrincipal)principal).Identity)
.AddClaim(new Claim(ClaimTypes.Role, role));
}
}
}
In the Controller, you can now add the follow:
public class HomeController : AdfsController
{
//I used a magic string for demo, but store these in my globals class
[Authorize(Roles = "CoolRole")]
public ActionResult Index()
{
return View();
}
}
I tested this by checking a role assigned to the current user, and that worked! Then I changed the role to something like "reject", which the user was not assigned; and I received a 401 Unauthorized.
ADFS is the authentication/token service in Azure. to enable the Roles Based Authentication, you can use Azure RBAC (Role Based Access Controll) service to basically Augment the claims that you get back from the ADFS and add the roles that you get back from RBAC to the token, and use the same token in your API so lock down or secure the backend with that augmented token...
here is the reference for RBAC:
http://azure.microsoft.com/en-in/documentation/articles/role-based-access-control-configure/

MVC4 Trying to get the security model to work with my Environment

I hope someone will be able to put me on the right track, been trying to resolve this now for hours.
I am currently in the process of redeveloping a web application and I would like to use the MVC4 attributes for managing access to the various parts of the application.
The issue I am having is that the Authentication & Permissions are all handled by middle-ware applications that the web app has to interface with.
I was wondering if even with this restriction would I be able to use the security attributes & letting the web app know that the user is Authenticated.
Yes, you will be able to use existing Authorize attribute. All you have to do is write a custom Membership and Role providers that will use your existing services instead of relying on the default SQL database.
If you don't want to go through all this hassle you could also write a custom authorization attribute (deriving from AuthorizeAttribute) and inside the AuthorizeCore method call your service to check whether the current user has the desired roles.
Definitely. Not only is it possible, but also it's pretty easy. And if you can think of ASP.NET Roles as "activities", then you don't need to derive anything; everything you need is built in.
These examples assume securityService is the service that communicates with your middle-ware applications, and has two methods, GetUser and GetUserRoles:
Your Login action method
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!ModelState.IsValid) return View();
var user = securityService.GetUser(model.Username, model.Password);
if (user == null)
{
ModelState.AddModelError("", "Username or password are incorrect.");
return View();
}
FormsAuthentication.SetAuthCookie(user.Username, model.Remember);
return Redirect(returnUrl);
}
In your Global.asax.cs
protected void Application_AuthenticateRequest()
{
if (Request.IsAuthenticated)
{
string username = User.Identity.Name;
string[] roles = securityService.GetUserRoles(username);
IIdentity identity = new GenericIdentity(username);
Context.User = new GenericPrincipal(identity, roles);
}
}
That's it. Login handles the authentication (when the user logs in), while Application_AuthenticateRequest handles the authorization (on every request). You then proceed to decorate your action methods with Authorize(Roles = "XYZ") making sure "XYZ" matches what comes back from your GetUserRoles method.

Resources