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.