How to grant ACL in Spring Security without an explicit authentication? - spring-security

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.

Related

How [Authorize] attribute get to know that the user is authenticate in ASP.NET MVC, is it by using authentication token?

I would like to know that how [Authorize] attribute recognize that this user is authenticate?
If user is valid then we call FormsAuthentication.SetAuthCookie() method and as per MSDN this method:
Creates an authentication ticket for the supplied user name and adds it to the cookies collection of the response, or to the URL if you are using cookieless authentication.
Is [Authorize] attribute checks authentication ticket or cookies collection?
[Authorize] does not deal with any authentication mechanism itself. It merely looks in the users IIdentity for the IsAuthenticated flag. It will also look in the users IsMemberOf method, for authorization based on roles.
All the work to decode the authentication ticket is done in the early stages of the app pipeline, which sets those flags. By the time the Authorization Attribute methods are called, all that work has already been done and is stored in the users runtime data.
You can easily check the source code for the Authorize attribute, and you will see that it's quite simple in nature. It just returns true or false based on some simple lookups.
It's become more complicated in .net core, where it's based on policies and what not, but the original MVC implementation was quite simple.
My answer relates to ASP.NET Core I'm not sure if you asked about classic ASP.NET but this should be similar.
There's a middleware that you have to add for [Authorize] to work. ASP.NET Core provides this middleware out of the box and you can add your custom authentication handlers too.
You can check how it's implemented by reading: https://github.com/aspnet/Security/tree/dev/src
For example you want to use JWT bearer authentication, you have to add JWT bearer middleware, this is simply extension of AuthenticationBuilder: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerExtensions.cs which calls AddScheme under the hood.
You want to use cookie based authentication you just call AddCookie which is also extension that calls AddScheme under the hood: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieExtensions.cs
Usage of it is documented here: https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x?view=aspnetcore-2.1
See also Using the [Authorize] Attribute
Web API provides a built-in authorization filter, AuthorizeAttribute. This filter checks whether the user is authenticated. If not, it returns HTTP status code 401 (Unauthorized), without invoking the action.
If you are interested how this filter works under the hood you can check it here.
You must be authenticated before you can be authorized, this is the logic responsible for it: https://github.com/aspnet/Security/blob/644f34e90d35b369efdce9c11ab1db42e0a7f4a7/src/Microsoft.AspNetCore.Authorization.Policy/PolicyEvaluator.cs#L91
In summary
how [Authorize] attribute knows that this user is authenticated.
Authorize attribute alone doesn't know if this user is authenticated. This is handled by authentication middleware and depends stricly on the scheme it tries to authenticate with. It simply tries to authenticate with schemes you have added(cookie,jwt etc.) by calling HttpContext.AuthenticateAsync which is simply calling AuthenticationService.AuthenticateAsync under the hood and sets HttpContext.User from the result ClaimsPrincipal, which is simply result from schema handler like jwt handler for instance. I think this should give you more in-depth idea how this works.
Generally if you're starting new project I don't recommend using classic ASP.NET and prepare for the future with .NET Core as everything is now going in this direction. ASP.NET 5 ( I also refer to it as "classic") is pretty much dead now.

Asp.net Identity 2.0 - Add in memory role to user

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)

How to manually set the current user in the OAuthAuthorizationServerProvider' GrantResourceOwnerCredentials method?

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

How do the AuthorizeFilter and Authentication methods work under the hood?

I would like to understand briefly how the authorize filter and FormAuthentication.SetAuthCookie work under the hood. It's the only thing I find ambiguous after reading some books on the language.
I don't understand how the authorize filter knows where to look. And what about FormsAuthenticationTicket VS FormAuthentication ? And is cookie the most secure way, I mean I'm sure it's possible to export the cookie from a browser and use it somewhere else..?
You might find this question helpful.
If you're interested in how the Authorize filter works in more detail you can review the source code: AuthorizeAttribute
Briefly the Authorize filter will check whether the user has been authenticated by checking the HttpContext.User.Identity.IsAuthenticated property. The User property will have been set by the FormsAuthenticationModule in the case of Forms Authentication.
The FormsAuthentication.SetAuthCookie method creates a ticket for the authenticated user (assuming the user has provided the correct credentials) and adds it to the cookies collection of the response. Alternatively the module can be configured to use cookieless authentication if you want but the encrypted ticket is still sent with each HTTP request. Either way the client (browser) needs a way of telling the server that the requested is authenticated.
Regarding your concerns over security there are some ideas in this question.

ASP.NET MVC: A PreAuthorize-like event, Good throttle point for concurrent logons?

I want to allow a new login to 'kick' a prior login session by the same account, in ASP.NET MVC.
It seems pretty clear that I'll give each browser a cooking representing the session ID. I'll track the currently active session ID in a server-side cache. If an already-active user attempts to log in, I'll verify the business logic (username, password, has been at least 15 minutes since last activity), and then update the active session ID cached at the server.
Now my issue is, a browser is holding an invalid session ID. What is the best point for me to inject a rejection or redirect to sign-in for this scenario?
I could modify the AuthorizeAttribute, but it seems like there should be a cleaner place to do this that won't require me to search and replace all my Authorize attributes, for example via a Global.asax event, or a controller event (I've already extended Controller in my project).
For example, if PreAuthorize existed, I would write some code there to test the request's cookies for a valid user/session ID pair, and if it didn't exist, I could simply remove the authentication cookie from the request, which would result in a standard unauthorized redirection.
So after a bit of research, it seems that a custom AuthorizeAttribute would typically be the correct approach. However, in my case, since I already had a custom role provider implemented, it was just a line of code to do it there. This also benefited me because I only wanted session concurrency for a single role. A side effect is that any use of web.config to control access to static files by role is also in-effect for session concurrency.

Resources