AuthorizationContext.Principal is changing from ClaimsPrincipal to GenericPrincipal automatically - c#

I dont know how come the context principle is changing in AuthorisationManager. My code is like
public class AuthorisationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
return context.Principal.HasClaim(resource, action);
}
public override void LoadCustomConfiguration(System.Xml.XmlNodeList nodelist)
{
base.LoadCustomConfiguration(nodelist);
}
}
I have list of items in GUI. It works fine first time but when I select second item the context.Principle is chnaged to GenericPrinciple.
Any idea will be helpfull on this.

OK - WPF.
Yeah I vaguely remember that there is some "feature" in WPF around Thread.CurrentPrincipal.
try
Thread.CurrentPrincipal = principal
AppDomain.CurrentDomain.SetThreadPrincipal(principal);
IIRC you maybe have to do that in the App class (ctor?).

"return context.Principal.HasClaim(resource, action);"
Well - typically there is no 1:1 corellation of claims and authorizatin "decisions". Also in typical scenarios claims only hold identity data - something data can be used later to base authorization decisions on. The authorization manager then uses its own data management to make those deicions.
Now since this is a client application (i didn't know that it was WPF) you may do things a little differently. In server applications your approach would scale very well.

Related

Authorization in ASP.net5

I am trying to see if there is something "out of the box" in ASP.net5 for authorization for my application needs. I am using a group/permission based approach for authorization. Using Identity3 I am using Role as Group and then I have created permissions from this. Each permission has a resource that it links to and 1 or more values, like:
Resource = Page, Permissions = Add, Update, View, Delete
Another complication is that the groups have dynamic names, and dynamic permissions!!
I have started to read about authorization in ASP.net5 and it seems that I have found something called Policies, which sound good. It seems to force you to use Claims, which is possible if I use a ClaimsTransformer to get all my permissions and add them as claims from the Db. But am I right in thinking that I would have to create a policy for each Permission, on each resource? That seems like a lot of setup.
Is there anything that I do not know about is already built in ASP.net5 that I could use? Like an attribute like this
[Authorize("Page", "Delete")]
Which I could add to the PageController Delete method.
If I have to use some sort of service and DI that into the controller to implement this, then that would be fine as well.
There is a ClaimsPrincipalPermissionAttribute that can fit to your requirements.
Or you can implement your own AuthorizeAttribute.
I use AspNet.Security.OpenIdConnect.Server for authorization. But you can also have a look at OpenIddict
In any case you can add the Authorize attribute to any method you want like this
[Authorize(Roles = "Administrator,SimpleUser,AnOtherRole")]
public void MyMethod() {}
Resource based authorization might fulfill your needs, but I am a little confused with the page being the resource, rather than what the page acts upon.
Taking your Page/Delete combination, I would imagine that rather than the resource being Page, your Page Delete action takes a parameter, indicating the page that is to be deleted? (If this is not the case then this approach isn't going to work of course)
In this case you'd do something like
[Authorize]
public class PageController : Controller
{
IAuthorizationService _authorizationService;
public PageController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public Delete(int pageId)
{
var page = pageRepo.GetPage(pageId);
if (await authorizationService.AuthorizeAsync(User, page, Operations.Delete))
{
return View(page);
}
else
{
return new ChallengeResult();
}
}
}
In order to enable this you're write a handler based on page and an Operations requirement (or any old requirement, but a parameterized operations requirement means you can write a single handler and branch accordingly).
We tried very hard to move away from putting data in the attribute, and move it into requirements, because data in attributes is, to be frank, a maintenance nightmare.
One other thing to note; as handlers are resolved through DI you could inject your user to permissions resolver into the handler, which would avoid using claims transformation.
ASP.NET provides authentication mechanism out of the box which is easy to use, example:
public class HomeController : Controller
{
[Authorize]
public ActionResult Index()
{
ViewBag.Message = "This can be viewed only by authenticated users only";
return View();
}
[Authorize(Roles="admin")]
public ActionResult AdminIndex()
{
ViewBag.Message = "This can be viewed only by users in Admin role only";
return View();
}
}
Check this tutorial
Or if you want more sophisticated mechanism you can implement your own memberhsip provider based on the ASP.NET Membership Provider

How to inject the current user for a request in to a controller / service?

In my WebApi based application I have a Ninject binding for injecting the current user in to things ...
Bind<User>().ToMethod((context) =>
{
User result = new User { UserName = "Guest" };
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
var service = Kernel.Get<IUserService>();
var user = service.GetAll().FirstOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
return user;
}
return result;
});
Pretty straightforward right?
I then have a webApi controller that has a service class injected to its ctor, which in turn has the current user injected in to it, the stack looks something like this ...
class SomethingController : ApiController {
public SomethingController(ISomethingService service) { ... }
}
class SomethingService : ISomethingService {
public SomethingService(User user) { ... }
}
Frustratingly for some odd reason when i inject the current user in to the service constructor the user is not authenticated yet.
It appears that the stack is being constructed before the authentication provider (aspnet identity) has done its work and confirmed who the user is.
Later when the actual service call is made from the controller the user is authenticated and the user object I have been given is for a guest not the actual user that made the call.
My understanding was that a controller was not constructed until authentication and determining the request / user details was done.
How can I ensure that the current, authenticated user is passed to my business services correctly every time (only after authentication has taken place)?
EDIT:
I think I found the problem: dotnetcurry.com/aspnet/888/aspnet-webapi-message-lifecycle it looks like the controller and all its dependencies are created before any auth logic is run. I guess the question then becomes ... can I force the AuthoriseFilter to run and confirm the users identity before the controller is constructed.
This changes my question somewhat to become:
How do I ensure authentication occurs before the controller and all its dependencies are constructed?
EDIT 2: An Answer - Not ideal but an answer ...
Can someone with more rep unlock this question please, this is not a duplicate of the other question, the OP is asking about the basica usage of Ninject I am asking about WebApi lifecycle and how to get session related context prior to the session being known for the current request.
Ok I don't like this answer but its a solution.
If anyone else has a better one I would love to hear it ...
If I update my service constructor to this ...
class SomethingService : ISomethingService {
public SomethingService(IKernel kernel) { ... }
}
... and I drop the kernel in to a local field, when I come to run my service code ...
public void Foo() {
var user = kernel.Get<User>();
}
... What this means ...
I get the user at the point of the request lifecycle where authentication and authorisation has taken place, and the stack is correctly constructed.
Now if I ask for the user, when the rule runs the HttpContext is correctly showing the right user details.
It works but ...
This is very much DI antipattern type behaviour, I don't like it and would prefer to find a solution that meant I could Authenticate the user there and then if it hadn't already happened yet but it would basically mean replicating code that the WebApi stack already has (that could mean its easier though) and will take place anyway basically resulting in the Authentication process happening twice.
In the absence of such a solution ... this is a "semi" reasonable workaround.
It's been a while but I later found out the answer to this.
The problem was that whilst I had some auth info in the form of say a an auth token provided as a header value, I was trying to construct information about the user and I may not have even needed it during the request.
I wanted to ensure that all my business services sat behind the controller handling the request would be given the current user when in fact they only needed the auth information so that the auth info could be used to determine and make security related decisions (such as getting the user if appropriate).
In the end I took to creating an IoC binding that could examine my owin context and ask that for the auth information, that auth information I would then inject in to my controller / service as needed.
From there I at least had the contextual information I needed to make the key decisions.

Is a Role Provider implementation necessary?

I am struggling a little bit to completely understand what is the correct way to implement a windows authentication and role based authorization scheme into an MVC4 application. When the user accesses the (intranet) website I currently have the following method check the user name against the against a database table
List<string> permissionList =
PermissionBo.GetUserPermissionsList(PermissionBo.ParseUserName(User.Identity.Name));
Permissions permissions = new Permissions(permissionList);
Then the following if state adds a role to a user object:
if (permissions.IsAdmin)
{
if(!Roles.RoleExists("UtilitiesToolAdmin"))
{
Roles.CreateRole("UtilitiesToolAdmin");
}
if(!Roles.IsUserInRole(User.Identity.Name, "UtilitiesToolAdmin"))
{
Roles.AddUsersToRole(new string[] { User.Identity.Name }, "UtilitiesToolAdmin");
}
}
I feel like this may be an incorrect way to go about implementing this, but I am not sure where I am going wrong. Is this sufficient to begin using the authorize attribute like so:
[Authorize(Roles="UtilitiesToolAdmin")]
public static void Foo()
{
return "Bar"
}
If not what am I missing?
If all you are doing is simple role checking, a custom Role Provider might be a bit of an overkill (Role Providers also provide facilities for managing the roles themselves). What you will end up with is a class full of
throw new NotImplementedException();
Instead, consider creating a custom user principal. The IPrincipal interface defines an IsInRole method that returns a bool. This is where you would put your custom role checks. The advantage of the custom user principal is that now all of the built in ASP.NET role-checking goodies should "just work" as long as you replace the default user principal object with your custom one early enough in the lifecycle.
This SO answer has one of the best examples I've seen of using a custom user principal with an MVC application.

Combine WindowsAuthentication with rules stored in DB

I have an ASP.NET MVC5 application that uses WindowsAuhhentication to authenticate the user. Now I need to add a security layer to this application and would like to base this on the standard MVC security model and use the AuthorizeAttribute. This relies on User.IsInRole, but currently this will return the groups that the user belongs to. I do not want to have to store roles as groups in the AD, instead I would like to just have the roles for each user stored in my DB.
So the question is, how do I override the IsInRole method in the WindowsPrincipal, or can I create a CustomPricipal that does what I want?
I have found lots of information on similar topics but most of them seem to reference MVC4 and from what I can gather the entire security model has changed between MVC4 and MVC5. So what is the best way of doing that now?
All help and pointers much appreciated.
Cheers Mike
P.S. And if anyone has any idea how to best incorporate EF, IOC and caching into this then that would be great.
I have found MVC5 Asp.Identity to be really developer friendly compared to the old membership provider... which might be the reason there is a lack of documentation at this time. It is actually intuitive.
If your authentication rules reside in a database EntityFramework will convert stored procedures into Complex Types. After you do that you could create an 'AuthenticationService' service layer and use DI to inject the complex types into Asp.Identity as needed.
To customize Asp.Net Identity all you have to do is add properties to IdentityModels.cs and AccountViewModels.cs, by default Asp.Identity uses the ApplicationDbContext which you have to do absolutely nothing to configure.
In addition, you can access the users information in a similar manner to User.IsInRole.
OK, this is what I have done. I would really like peoples feedback as to best practice and improvements I could make.
I created a new Principal derived from WindowsPrincipal and with an overridden IsInRole Method.
public class QSDPrincipal : WindowsPrincipal
{
private readonly IUserService userService;
public QSDPrincipal(WindowsIdentity ntIdentity,
IUserService userService) :
base(ntIdentity)
{
this.userService = userService;
}
public override bool IsInRole(string role)
{
return userService.CurrentUserIsInRole(role);
}
}
This uses DI to populate the userService object that lives in my BL layer. So I had to configure the container to build this properly.
container.RegisterType<WindowsIdentity>(new HierarchicalLifetimeManager(),
new InjectionFactory(x => (WindowsIdentity)HttpContext.Current.User.Identity));
container.RegisterType<IPrincipal, QSDPrincipal>(new HierarchicalLifetimeManager());
The I use the DependencyResolved to create my new Principal in the PostAuthenticateRequest event.
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var newUser = (IPrincipal)DependencyResolver.Current.GetService(typeof(IPrincipal));
HttpContext.Current.User = newUser;
}
Then in the UserService itself I implement a method and implement some simple caching so it only makes one DB query per request.
public bool CurrentUserIsInRole(string role)
{
return CurrentUserRoles.Contains(role);
}
private IEnumerable<string> currentUserRoles;
public IEnumerable<string> CurrentUserRoles
{
get
{
if (currentUserRoles == null)
{
var user = GetCurrentUser();
currentUserRoles = new List<string>
{
user.Role.Name
};
}
return currentUserRoles;
}
}
And that is it and it all seems to work.
Thoughts and improvements much appreciated.
Cheers Mike

Where is the best place to have custom Principal/Identity set?

I have been working on a web site (using ASP.NET C#) that uses both forms based and claims based authentication. I wanted to override the ClaimsIdentity class so I could implement a custom IsAuthenticated method and add more properties for the identity specific for the claims authentication.
I'm implementing a custom WSFederationAuthentionModule currently, but I was trying to figure out what module I should override (specifically what method) so I can set my custom identity/principal rather than the default ClaimsPrincipal?
So far I have looked at both the SessionAuthenticationModule and ClaimsPrincipalHTTPModule, but I could not figure out at what step the principal is set/the best way to override it.
Thanks
Addition:
Since I'm kind of new at this let me be sure this is correct: The way to set an identity is to set a custom principal which is set to use that identity:
System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;
Alternatively if a custom principal was not needed then the ClaimPrincipal class could be constructed with a ClaimsIdentityCollection.
There are several places you can do this, but if you are using the SessionAuthenticationModule, some of the process is not documented well which can make using a custom principal tricky. The rest of this answer explains one possible way to handle this when using the SessionAuthenticationModule.
Override the SessionAuthenticationModule.SetPrincipalFromSessionToken method.
The SessionAuthenticationModule stores the security token, principal, identities, and claims in a cookie and an in-memory cache to avoid having to make round-trips to the identity provider/token service on every request. What's not documented well is the existence of the cache and that it is the first place checked, then the cookie, and the limits on serializing the ClaimsPrincipal.
If you already set a custom principal in ClaimsAuthenticationManager.Authenticate and the cache is intact, your custom principal will most likely be there already since the cache stores native .NET objects. If you haven't yet set a custom principal, or the cache is not populated, then the security token will be retrieved from the FedAuth session cookie.
When the token is serialized/deserialized to/from the cookie, the process uses custom serialization that is only capable of reading and writing attributes of the IClaimsPrincipal and IClaimsIdentity interfaces (or the ClaimsPrinicpal and ClaimsIdentity classes - I can't remember which). Any custom principal and identity object attributes will not be included. It may be possible to override the serialization, but that requires several (3 IIRC) more layers of class overrides.
You'll also need to be aware of the fact that the base SetPrincipalFromSessionToken method creates a new ClaimsPrincipal object and sets it on the thread and context, so even if the sessionSecurityToken parameter contains a custom principal object, it will get translated back into a ClaimsPrincipal object.
Here's an example override method:
protected override void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
SessionSecurityToken newToken = MyClaimsPrincipalUtility.CreateCustomClaimsPrincipalToken(sessionSecurityToken);
base.SetPrincipalFromSessionToken(newToken);
//the following lines need to be set after the base method call, because the base method overwrites the Principal object
HttpContext.Current.User = newToken.ClaimsPrincipal;
Thread.CurrentPrincipal = newToken.ClaimsPrincipal;
}
The base class (SessionAuthenticationModule) implementation looks like the following. So there are a couple different ways you can achieve the overriding and getting the custom claims principal.
protected virtual void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
IClaimsPrincipal fromIdentities = ClaimsPrincipal.CreateFromIdentities(this.ValidateSessionToken(sessionSecurityToken));
HttpContext.Current.User = (IPrincipal) fromIdentities;
Thread.CurrentPrincipal = (IPrincipal) fromIdentities;
//tracing code removed
this.ContextSessionSecurityToken = sessionSecurityToken;
}
And just in case you're wondering, here's the base class implementation for SessionAuthenticationModule.ContextSessionSecurityToken.
public virtual SessionSecurityToken ContextSessionSecurityToken
{
get
{
return (SessionSecurityToken) HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName];
}
internal set
{
HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName] = (object) value;
}
}
You're correct in that HttpModules are the way to go in terms of extensibility, but make sure that whatever logic you implement doesn't inhibit the performance of your application. I've had websites go thoroughly berserk performance-wise after adding too many HttpModules to the application. It might be worth caching results of your queries, depending on what auth model you're using.
You need to figure out under what conditions you need to use your custom ClaimsPrincipal. Until you do this you're stabbing in the dark. Are there specific URLs for which you need claims authentication?

Categories

Resources