Grails 3 and Spring Security - authenticate user in filter - authentication

I'm developing a Grails 3 web-app powered with Spring Security plugin, which already makes large use of #Secured annotations to protect controllers and actions according to the privileges of single logged-in users.
The login is currently managed via the usual username/password pair.
Now a new requirement came up, involving a custom request header, having as value a sort of 'authorization token':
this token identifies a group of users (let's call it team)
if this token is recognized as valid, matching against DB, then the whole application should behave as a predefined user (let's call it John, part of the team) was logged-in. In this sense it should act as a pre-authentication. This user will have his own roles, so the application will respond accordingly, as if John would had logged in with his own username/password.
if the token is not recognized, 401 status must be returned.
if the token is not passed, the application must have its current behavior, to the token management should be considered optional must not impact the current implementation at all.
I considered defining a custom filter (I also took a look at this post, which however has different requirements), but I cannot even determine:
the feasibility of this task
whether or not filters are the best approach (but I guess so as Interceptors are triggered too late, and I need some additional logic to be evaluated before Spring Security comes into play)
possibly, the best filter to extend
So any suggestion is welcome! Thanks in advance

Not an expert on this, but I would implement a custom UserDetailsService and set the authorities based on the token condition. You might also be able to do it in an AuthenticationSuccessListener.

Related

Handling authorization with IdentityServer4

I'm extremely confused on how to use a centralized IDP with both authentication and authorization. The architecture for my project was to be a single web API and one React client. I wanted to keep things structured out into microservices just to try something more modern, but I'm having major issues with the centralized identity, as many others have.
My goal is fairly simple. User logs in, selects a tenant from a list of tenants that they have access to, and then they are redirected to the client with roles and a "tid" or tenant id claim which is just the GUID of the selected company.
The Microsoft prescribed way to add identity in my scenario is IdentityServer, so I started with that. Everything was smooth sailing until I discovered the inner workings of the tokens. While some others have issues adding permissions, the authorization logic in my application is very simple and roles would suffice. While I would initially be fine with roles refreshing naturally via expiration, they must immediately update whenever my users select a different tenant to "log in" to. However, the problem is that I cannot refresh these claims when the user changes tenants without logging out. Essentially, I tried mixing authorization with authentication and hit a wall.
It seems like I have two options:
Obtain the authorization information from a separate provider, or even an endpoint on the identity server itself, like /user-info but for authorization information. This ends up adding a huge overhead, but the actual boilerplate for the server and for the client is minimal. This is similar to how the OSS version of PolicyServer does it, although I do not know how their paid implementation is. My main problem here is that both the client and resource (API) will need this information. How could I avoid N requests per interaction (where N is the number of resources/clients)?
Implement some sort of custom state and keep a store of users who need their JWTs refreshed. Check these and return some custom response to the caller, which then uses custom js client code to refresh the token on this response. This is a huge theory and, even if it is plausible, still introduces state and kind of invalidates the point of JWTs while requiring a large amount of custom code.
So, I apologize for the long post but this is really irking me. I do not NEED to use IdentityServer or JWTs, but I would like to at least have a React front-end. What options do I have for up-to-date tenancy selection and roles? Right when I was willing to give in and implement an authorization endpoint that returns fresh data, I realized I'd be calling it both at the API and client every request. Even with cached data, that's a lot of overhead just in pure http calls. Is there some alternative solution that would work here? Could I honestly just use a cookie with authorization information that is secure and updated only when necessary?
It becomes confusing when you want to use IdentityServer as-is for user authorization. Keep concerns seperated.
As commented by Dominick Baier:
Yes – we recommend to use IdentityServer for end-user authentication,
federation and API access control.
PolicyServer is our recommendation for user authorization.
Option 1 seems the recommended option. So if you decide to go for option 1:
The OSS version of the PolicyServer will suffice for handling the requests. But instead of using a json config file:
// this sets up the PolicyServer client library and policy provider
// - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
get the information from an endpoint. Add caching to improve performance.
In order to allow centralized access, you can either create a seperate policy server or extend IdentityServer with user authorization endpoints. Use extension grants to access the user authorization endpoints, because you may want to distinguish between client and api.
The json configuration is local. The new endpoint will need it's own data store where it can read the user claims. In order to allow centralized information, add information about where the permissions can be used. Personally I use the scope to model the permissions, because both client and api know the scope.
Final step is to add admin UI or endpoints to maintain the user authorization.
I ended up using remote gRPC calls for the authorization. You can see more at https://github.com/Perustaja/PermissionServerDemo
I don't like to accept my own answer here but I think my solution and thoughts on it in the repository will be good for anyone thinking about possible solutions to handing stale JWT authorization information.

How can I define policies for my API for two types of access tokens, one with an identity (sub) and one without?

I am using IdentityServer4 via ASPNET Core, and I want users to access my API both by the web browser via their identity (Implicit and Hybrid), and by clients programatically (Client Credentials). I realize all I have to do is add AddIdentityServerAuthentication and I am done. However, that only solves the authentication aspect of this problem, not the authorization.
Authorization:
With ASPNET Core, you can just use Role based auth (or PolicyServer permissions which is similar) but only if you have an identity with role claims, that does not work for client credentials. So that brings us to needing to secure by role, or policies AND by scopes. How can I do this?
You cant have multiple policies, if you do, they both must pass.
You can't have multiple auth schemes, because my call to AddIdentityServerAuthentication will have to use the same authority, so how would IdentityServer4.AccessTokenValidation/JwtBearer know which you scheme challenge you are trying to pass?
Multiple requirements could work, but you need to add extra requirements on the condition that you are dealing with a non-identity access token. How can you detect what type of token you are dealing with? Is it safe to just say "If no sub, this is client creds."
Should I scrap this design and force device code flow on my users? Look at az cli it magically opens a browser, and then you can start scripting away to your hearts content. IS4 supports this with ease, especially with verficationUrlComplete
I think I have a working POC, but I am far from happy with it. https://gist.github.com/VictorioBerra/8c333a228c55d86a7c15f7f300284634
It involves basically re-implementing the default scope claim requirement handler and policyservers permission requirement handler. But thats the only way to conditionally apply the requirement handlers based on the token type.
There are at least a couple of ways of how to go around your problem of implementing role based authentication:
You might have misunderstood the fact that a client can have role claims in the client_credentials flow.
You could even have sub claim if you implemented client_credentials_custom flow and essentially bind a client to a particular user account (think of this as a service account)

asp.net core / openiddict & client spa Authorization with custom permissions

I need some help in understanding a basic thing or two with Token-based authentication.
My setup is a backend asp.net core app with openiddict for token auth. It's all working well so far - I now need to add user-permissions. I will have a lot of them (e.g. User can view xy, user can edit xy, user can delete xy, with many different xy-components). Backend is working well so far, my problem is now: How to get these permissions via token to my client side app..
As far as I understood these are not classical "claims" as a claim would describe "who" you are rather "what you are allowed to do" . Right?
But how can I pack them into my id_token/ How can I add them to my payload?
Second thing: Do I need to validate the token (signature) in my case? Every Api-request ist validated at server side, so basically I don't need to care if my client side permissions are tempered with, right? (As they are only for UI-Display purposes)
Thanks for your help!
As far as I understood these are not classical "claims" as a claim would describe "who" you are rather "what you are allowed to do" . Right?
In theory, nothing prevents you from representing permissions as claims, just like you'd do with roles or any other claim. In practice tho', it's rarely the best approach, because the number of actions a user can do is usually important (and often unlimited: can the user A update the product 124? And this other product?).
A possible alternative is to catch the 403 responses returned by your API when a user is not allowed to execute a specific action so you can display an adequate error message. Another one is to create an API endpoint that dynamically determines whether a user is allowed to execute the action, according to your own policy.
Second thing: Do I need to validate the token (signature) in my case? Every Api-request ist validated at server side, so basically I don't need to care if my client side permissions are tempered with, right? (As they are only for UI-Display purposes)
Both access tokens and identity tokens are digitally signed, so they can't be tempered with (at least, not easily). You don't need to validate signatures yourself, as it's already done by the validation/JWT middleware.

RESTful secure resources by user

I am building a SpringBoot RESTful api with OAuth2 as security component.
I am wondering how to protect my resources, but thinking more as business logic. For example, if I have a list of courses /rest/v1/courses, and this courses have a Supervisor and suppose that I logged as ROLE_SUPERVISOR (no admin access) and I make a call to /rest/v1/courses and as business logic I can only see the courses where I am supervisor.
1) Should I make a /rest/v1/courses?supervisor_id=2. Classic filter, it would be ok if I where an Admin, but anyone who is logged in, could see other data if trace the url and change the id.
2) Should I make a /rest/v1/courses and get the supervisor_id from the successful login? So I have to check every request against the login data.
I think this is the more secure approach, but it's sound a little tedious, and I could forget to perform security checks in any controller method.
3) Maybe there is a more generic solution and I couldn't find or think?
Thank you, and sorry for my english.
RESTful APIs are stateless. Therefore with every request you must validate the request's credentials, either immediately with a token or by checking with your OAuth service. If the supervisor_id is linked to the credentials (e.g. token value xyz implies supervisor_id = 2), and this ID determines access, then adding it as a request parameters is unnecessary. You would always be validating this parameter against the credentials anyway.
Now if "supervisor 2" can request information regarding "supervisor 1", then yes, you would want the ID as another request parameter. You will still need to check credentials to know "supervisor 2" is making the request and validate what they are allowed to query.
So I have to check every request against the login data. I think this is the more secure approach, but it's sound a little tedious, and I could forget to perform security checks in any controller method.
Basically anything identifying the requestor should be part of your authentication mechanism, separate from your specific API business logic. You'll find in many frameworks a workflow that processes authentication before URL routing. This includes providing your controllers with user information.

Spring data REST & data security

So I have a nice set of Spring Data REST repositories and they work great. Now I want to secure the data they produce. The URLs to the repositories are secure, in that, only an authenticated user has authorization to call them. However, only data in the database associated to the user should be sent to the client.
I have implemented an interceptor which gets called prior to the repository call which contains information about the logged in user, but I'm not sure how I can ensure only data produced by the REST call is data associated to the logged in user.
Obviously the client is coded to only make calls with links associated to the currently logged in user, but a user could simply change the URL to look at data they are not supposed to see.
Has anyone solved this issue?
Thanks,
Cory.
If you're using spring security, you can insert additional filters (ideally, based upon the url, or domain object.)
If you want object level security, you can still do the same thing, but you're going to have to somehow specify who/what role is allowed to access which domain object/id combinations, in either case, I don't think spring data rest handles (or should handle) any of that.
Spring Security's #PostFilter allows you to filter collection or arrays on the basis of authorization.
#PostFilter ("filterObject.owner == authentication.name")
public List<Book> getBooks();
Check these documented examples
https://github.com/spring-projects/spring-data-examples/tree/master/rest/security