I am using WIF and claims-based security in a MVC app and custom logic to create a ClaimsPrincipal with the appropriate claims after they authenticate. I assign some standard claims like Role and Name to the principal but also assign custom claims where applicable.
I modeled my custom claims after the standardized Role and Name claims using a URI, for example
new Claim("http://schemas.acme.com/2012/04/identity/claims/create", "http://schemas.acme.com/2012/04/identity/resources/customer")
Everything has been working very well. I use the SessionAuthenticationModule to store the users session in cookies and rehydrate it on each request.
I noticed today that my custom claims are not deserialized from the cookie after someone logs in with the same usertype. The standard claims (Name/Role) are present but the custom claims aren't.
Has anyone else ever seen this or know why this is happening?
Turns out I was adding the claims that were disappearing by reference. I had a class with static claims pre-defined that I would add to the ClaimsPrincipal as necessary. Any of the claims that I added this way were later removed when another user of that type logged in. My solution was to change the static properties to KeyValuePairs and create new claims for each user.
Related
I'm designing a system, where the admin will be able to login as a user to fix things on their behalf etc. I'd like it so they have an additional role during this period. Is there any way to add the role in memory or in a way that ends when they logout/close the browser. I could add the role from the admin screen and remove when that user logs in again but it could easily go wrong. Cheers.
This isn't about how to do impersonation. I've got that part working. I'd like to be able to add an additional role to the user but only when they are being impersonated (so there are a few extra diagnostic screens available). I think the person below is answering my question by explaining that when I add a claim, I'm adding it to the the cookie. I was thinking adding this information persisted back to the database. I will try that code tomorrow but I suspect it is the direction I need to go in. This is silly question but have the rules changed recently, I've noticed tonight people being a little enthusiastic to correct grammar etc.
ASP.NET Core 2.0 Identity uses claims based authentication. Each role is a claim. Claims are persisted for the session via several means but generally in the application cookie issued when they log in or JWT auth tokens (not in memory).
Using the SignInManager creating a user principal and adding an extra claim should be pretty trivial:
// create the user principal
var principal = await signInManager.CreateUserPrincipalAsync(user);
// add the extra role
principal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, SomeRole));
// issue the application cookie
await HttpContext.SignInAsync(principal)
Is there a way to add custom claim to my ClaimsPrincipal once the user is authenticated? When using ASP.NET identity for individual accounts, one could add custom claims to the ClaimsPrincipal when the principal was created but I can not find the way to do this when using the Organizational Accounts template.
For organizational account authentication, the templates setup HTTP handlers to handle authentication of your users. If you look in your web.config you will see two modules that were added to your project, which are the WSFederationAuthenticationModule and the SessionAuthenticationModule. As such, it's an entirely different authentication and authorization dance than what you are used to with cookie based authentication for individual accounts.
The extensibility point you are looking for is the Authenticate method of the ClaimsAuthenticationManager. Simply create a class that derives from this and override the Authenticate method. This will give you access to the ClaimsPrincipal object for the authenticated user where you can extend the claims collection for the user to whatever you want before your application code is invoked.
An example of how to set this up is here.
You do need to sign the user back in.
By default your claims are encrypted and stored as a single cookie in your browser. After you've manipulated your ClaimsPrincipal you need to persist the cookie back to the browser.
I agree the verbage is bad however you have to do the following
var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
var authenticationProperties = new AuthenticationProperties { IsPersistent = false };
authenticationManager.SignIn(authenticationProperties, myManipulatedClaimsIdentity);
I have an asp.net mvc webapi 2 project and I'm using the new asp.net identity infrastructure with owin and oauth and all its great features...
I'm using for authorization the token based system: app.UseOAuthBearerTokens(OAuthOptions);
Everything works great, the only issue that I have is the following - in my own OAuthAuthorizationServerProvider implementation, in the method GrantResourceOwnerCredentials (the one that gets called once an user wants to authenticate by visiting the /token url), after checking the user validity and other things, I need to call other methods (recalculate shopping cart, etc) but those methods (don't ask why) looks into the current context User to get the username and role of the user, but during the running of the GrantResourceOwnerCredentials method, the current context User is null (is somehow normal - I'm not asking why).
My question is: in order to not break any guidelines of using the oAuth bearer tokens authorization is it OK to manually set the user in this method like this?
context.Request.User = new ClaimsPrincipal(oAuthIdentity);
Thank you for your feedback.
in owin startup orders of bearer and authorization must be like this
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions());
Check out this answer
When I create a new entity I would like to grant ACL permissions (aka ACL entry) to this new entity. So far so easy :-)
The problem arises in the following scenario:
An end user can create the entity without being authenticated on the web site.
The service that persists this new entity hence runs without an authentication context.
But: to grant ACEs one needs to have an active authentication context.
Spring's JdbcMutableAclService uses SecurityContextHolder.getContext().getAuthentication() to obtain the current authentication, so there seems to be no way to circumvent this requirement.
Any ideas are greatly appreciated!
Found the answer myself:
In a web application there always is an authentication context. If a user is not authenticated the authentication is org.springframework.security.authentication.AnonymousAuthenticationToken which has a single granted authority: ROLE_ANONYMOUS.
Hence it is simple to grant this user the right to create ACLs. Just configure the PermissionGrantingStrategy to use this role to authorize requests.
The main answer does not work in the current version of Spring (5.3.22) and Spring Security (5.7.3). I doubt it even worked back in 2012, when the answer was posted since it does not make sense.
PermissionGrantingStrategy is a class that only contains the method bool isGranted(Acl, List<Permission>, List<Sid>, boolean) which decides if the principals in the List<Sid> can access the object with the corresponding Acl with any of permissions in List<Permission>.
This is the function that is called when a user want to access an object with a certain permission. This method determines if access is granted or denied.
This has nothing to do with allowing anonymous users to modify existing Acls. The actual problem comes from calling MutableAcl aclService.createAcl(ObjectIdentity) when the authentication context is empty. This is implemented by JdbcMutableAclService, provided by Spring. The problem is that MutableAcl JdbcMutableAclService.createAcl(ObjectIdentity) has this call Authentication auth = SecurityContextHolder.getContext().getAuthentication(); which forces the access to authorization context even though the Sid could be passed to the createAcl method, so the business logic would be able to createAcls for the chosen users passed in the arguments.
Instead, we have this call which makes it impossible to use Acls from an unauthenticated context if we want to keep using the Spring Classes.
So, the solution would be reimplement the JdbcMutableAclService so the createAcl method does not call the authentication context, instead it has an extra arguments to indicate the Sid of the user we want to create the Acls.
If anyone has any idea on how to do that it would be greatly appreciated.
I am trying to initialize my Acl tables programmatically when my web app starts, but I cannot do it because my initialization code does not have any authantication.
I want to use the the AuthorizeAttribute to control which users are allowed access to my actions. I just want to clarify that my logic is in order.
I create my own implementation of IPrincipal
I post a user's credentials to a login action of a security controller.
I validate the credentials with a UserService class and assign the IPrincipal returned from my UserService class to HttpContext.User
My WebAuthorizeAttribute, which inherits AuthorizeAttribute, checks the current HttpContext.User.Identity.IsAuthenticated and HttpContext.User.IsInRole to determine if the user has access to the action.
Is the the normal flow of things? I know I could inherit MembershipProvider, but I don't need all of the functionality there, really just the ability to login with two different roles.
You'll have to store IPrincipal somewhere and restore it with every request. If you'll use FormsAuthentication, this is good solution:
ASP.NET 2.0 Forms authentication - Keeping it customized yet simple
you can find other solutions here:
Where to store logged user information on ASP.NET MVC using Forms Authentication?
and propably in many other StackOverflow questions:)
EDIT
About MyBusinessLayerSecurityClass.CreatePrincipal(id, id.Name):
You should read this page:
http://msdn.microsoft.com/en-us/library/aa480476.aspx
Specially this:
The
FormsAuthenticationModule
class constructs a
GenericPrincipal
object and stores it in the HTTP
context. The
GenericPrincipal
object holds a reference to a
FormsIdentity
instance that represents the currently
authenticated user. You should allow
forms authentication to manage these
tasks for you. If your applications
have specific requirements, such as
setting the User
property to a custom class that
implements the
IPrincipal interface,
your application should handle the
PostAuthenticate
event. The
PostAuthenticate
event occurs after the
FormsAuthenticationModule
has verified the forms authentication
cookie and created the
GenericPrincipal and
FormsIdentity
objects. Within this code, you can
construct a custom
IPrincipal object
that wraps the
FormsIdentity object,
and then store it in the
HttpContext. User
property.
FormsIdentity is managed automatically after you set authentication cookie. All you have to do is wrap it up in your IPrincipal. All this happens when HttpContext.Current.User property is not null (it is GenericPrincipal, which you replace shortly after). When HttpContext.Current.User is null then there was no authentication cookie created earlier and user is not authenticated.
I believe the following is more typical:
I create my own implementation of IPrincipal
I post a user's credentials to a login action of a security controller.
I validate the credentials with a UserService class and construct a cookie that has some identifying information for this user. Typically FormsAuthentication.SetAuthCookie or some combination of that class's utility methods are used.
In the Application AuthenticateRequest event, inspect the cookie and assign Context.User. Note: This value is automatically assigned to Thread.CurrentPrincipal after the AuthenticateRequest event. This is a one-time assignment and these values are not automatically synchronized thereafter.
My WebAuthorizeAttribute, which inherits AuthorizeAttribute, checks the current HttpContext.User.Identity.IsAuthenticated and HttpContext.User.IsInRole to determine if the user has access to the action.