Spring security user based permission? (not role based) - spring

Assume I have a database composed of user and projects. A user has a one to many relationship with projects. The user can do operations using rest endpoints.
The problem is:
how can I verify that this user owns this resource?
I don't want a malicious user to change an id then suddenly he views another person's project details/images/etc. Think of it like a social media (my app is not a social media but trying to illustrate the issue): where you can view only your images but not another person's images despite having the same "status".
Most spring-security blogs online is using a role based approach. I have no idea what to even search for in this case (tried multiple search queries to no avail).
One option is to run some sort of multijoin query on every resource request/operation till I reach that resource id and check it's owning user to check if it is the logged in user. However, I am not sure if this way is efficient since there are multiple tables in a chain in the real app (could have a lot of joins if I go this way manually; example: user -> project -> tasklist-> ... -> Note; deleting a note would trigger a large chain) or how to make the "authorizer" use it.
what are my options?
In case it matters:
I am using spring-boot + hibernate/JPA + spring-security

Spring Security has the following concepts:
Authentication:
Proving the an actor is who it vouches to be. Authentication is done using credentials, where credentials can take any number of forms - username/password, token, hardware key, etc.
You can set up Spring Security with a set of acceptable authentication providers.
Authorization:
Given an authenticated user, deciding if that user has access to a given resource. Where the resource can be:
An HTTP endpoint.
An Java Method.
A property of an object.
What you want to do here is provide a custom authorization scheme.
You can read about Spring Security's authorization architecture here, including how to set up custom authorization. Once you're ready you might ask specific questions as you go.

Related

Spring boot MVC - Block users from seeing endpoints by changing id in url

I'm writing a pretty simple ecommerce app with spring boot and thymeleaf and I found out that users can see any order by changing the id in URL.
For example:
User placed an order with ID 5, so he can see his order on url: /order/details/5
But if the user changed url to f.e /order/details/4 he can see details of order that he shouldn't be able to see.
Is there a simple way to block it with Spring security?
First off, let's get some lingo out of the way:
Authentication - The act of proving someone's identity. E.g., you login with a username, but you need a password to prove that it's you.
Authorization - Is the act of granting a user permission to perform an action.
Those terms are important when reading the Spring Security Documentation.
I assume that you already authenticate user and now you want to authorize them to view, e.g., their own orders, but not those of other users.
But I guess the orders are stored in a database. So you'll probably have to authenticate in your service layer. Meaning Spring Security takes care of authentication and you have the user available. When you fetch some order, you also need to make sure that the authenticated user is the owner.
Another thing to consider is using UUIDs as primary key. That makes it much harder to guess an ID but this is absolutely no replacement for authorization! Seriously. It is not. Security by obscurity is broken.

Spring Security: Creating multiple entry point for securing different rest controllers

I'm exploring the Spring framework, and in particular I am working on a Cinema Management Application that will be connected to a React.JS SPA (Single Page Application).
The problem is the following. On my database I do have three different tables representing three different types of users, namely Admin, Customer, and Cinema_Employee.
For each type of user, I created a #RestController with a list of RequestMethods that a particular user is able to perform:
"/admin"
"/customer"
"/employee"
What I am trying to achieve now, it's to secure each endpoint offering three different login pages that will handle the authentication the respective type of user.
How can I set up three AuthenticationManager that handle different Authentication objects within a SecurityConfig class given these requirements, and most importantly, how can I override the Authorisation mindful that each user once has logged in, will have access only to the respective endpoint?
I looked carefully at other examples online, and most of them are radical different, following a pattern where the database has another additional 'Authorities' table aside the 'user' one that stores the credential. In my case this solution cannot be applied, not only because the whole design would become redundant, but also because the name of the table where the application will perform the authentication check against, explicitly imply the authorisation that a given user has inside the system.
Your design sounds strange to me.
A user should have a role, e.g. Admin, Customer, Employee and based on the user's role he gets access to methods or not. Have a look at role based access control concepts. For Spring Security there is for example this tutorial:
https://www.baeldung.com/role-and-privilege-for-spring-security-registration

Can multi-tenancy in Keycloak be done within a single realm?

First, I'm well aware of the multi-realm approach to multi-tenancy in Keycloak. I've taken over a legacy project where nobody thought of multi-tenancy. Now, two years later, suddenly, the customer needs this feature. Actually, the microservices are prepared for this scenario out-of-the-box.
The customer develops a mobile app that authenticates users via API on our keycloak instance with an account number (as username) and a password. Now, he'd like to add an tenant id to the login information.
The customer wants to avoid using several endpoints as a multi-realm solution would demand.
One first idea was to just concatenate tenant-id and account-id on registration. But that's a smelly approach.
So, my thought was that there may be a way to configure Keycloak in a way that I add a custom tenantid field together with username that acts just like a composite primary key in the database world.
Is such a configuration possible? Is there another way to achieve multi-tenancy behaviour using a single realm?
I can't say for sure, but after some research, I found this:
This website lists all of this together with more information:
https://lists.jboss.org/pipermail/keycloak-user/2017-June/010854.html
Check it out, it may help with your data organization in key-cloak.
Late to the party. But maybe for others who are interested. You could try the keycloak extension keycloak-orgs. I am currently building a test stack with it and I am pleased.
A tenant in keycloak-orgs is an organization. You can map organizations and their roles to token claims with a built-in mapper.
"organizations": {
"5aeb9aeb-97a3-4deb-af9f-516615b59a2d" : {
"name": "foo",
"roles": [ "admin", "viewer" ]
}
}
The extension comes w/ an admin interface. From there you can create organizations and assign users to it. There is also a well-documented REST API on the Phase Two homepage (the company who open-sourced the project).
The maintainers provide a keycloak docker image that has the relevant keycloak extensions installed.
If you want a single realm and singe client that serves many tenants, you can just use custom user attribute and e.g. add key(s) "tenant=MyTenant" and then add a client scope and a mapper to include user attributes that has key=tenant
Then the token will carry the user's tenant(s) and you can use that to filter data, add to newly created data etc.
It's only like 4 steps in Keycloak:
Add User attributes using a key-convention.
Add a Client scope that will represent tenants.
Add a mapper to extract the User attributes.
Add Client scope to the Client in use.
Wrote about it here: https://danielwertheim.se/keycloak-and-multi-tenancy-using-single-realm/

Separate access in one app with keycloak

I have the following setup - the Spring SAAS REST service, which allows different companies to manage different events. And there is a rest client (a mobile app) also, shipped separately for each company.
I want to use keycloak for security stuff, and I have a question of how to separate one company from another.
I need companyA to not be able to access companyB event, and also need different roles within the company - some can create events, some can only read it.
First I thought each company will have own realm created in keycloak, but I learned that realm actually specified in the spring boot REST service parameters like
keycloak.realm=demo-realm
Which means it is only one realm per REST application. And I don't want to configure REST service instance per client. I only want one REST rule them all.
Am I trying to use something which really doesn't fit my use case?
Will it be right way to have a keycloack Group configured for each company, and make a logic in such a way that users of one group won't have access to what is created by other group. But then it actually feels wrong, since as I understand group are supposed to be used in a different way - to have admin group and user group, etc, segregating users "vertically" by "privileges", and not "horizontally".
Can you please suggest a right approach for this problem?
I would implement a custom protocol mapper which loads extra user permissions for your application and stores them in a token. This way, you use a single realm and if there are more companies in the future it scales well. Here you've got an example of how to implement it.
Basically, the otherClaims field of the access token is a JSON field that allows a map of properties to be set. You could add a field here such as:
userAccessibleCompanyIds: [1,3,4]
How to load the company ids for the concrete user? You can access your application database from the mapper or get them using the REST API.
Then in your application you need to have a control of what the user accesses. What I do is decode the token and see if the user request suits. If not, return a 403 response.

Best practice in securing user creation for a REST API

I'm currently working on a iphone/android project where the mobile talk ta java backend server through REST API calls.
The Java backend is done using Spring and its Authentication system (with a JSESSION ID token)
I'm not an expert in security but I can see that if not implemented correctly there could be quite a lot of issues.
One of my biggest concern would be user creation for example.
When the app creates a user it simply makes a POST request to (url.com/rest/create)
How can I avoid, server side, that a malicious user puts this url in a loop and create thousands of users ?
What are common best practices to secure API calls ?
Is the Spring Authentication token enough ?
Thank you!
It's not really possible to prevent a client from making many calls to your server. A malicious user can create a script or application firing requests to your server.
The solution is to authenticate and authorize the calls to the server. You give certain users (for example administrators) the privilege to create users. You trust those users to behave in a correct manner. You have your users authenticate before they call the APIs on your server. Then, on the server side your check who the user is and what he/she is allowed to do.
If you are still concerned about privileged users not behaving, you can assign quota to each user on the actions they are allowed to perform.
The hightech solution (with as much framework fuctions as possible) would be
first: have a created-by and created-date field at the entity you want to protect (I recommend to use Spring-Data-JPA Auditing for that).
second: create a custom spring method (or web) expression method that is able to check how many items the current user has created in the (for example) last 10minutes and if this are more then (for examle) 20, then return false (or make them parameters of the method).
Then you can protect your method (or url) with that expression (#PreAuthorize("createsNotExeced(10, 20)"))
But this is the high tech solution - it would be quite intresstion implementing them when one wants to learn spring security. (and you would need to add some caching, but this is also a Spring feature).
The lowtech solution would be: put an list of timestamp in the users session, and add an new item to that array whenever the user creates an new item. When the last (for example) 20 timestamp enties are within the last (for example) 10 minutes, then throw an TooMuchHeavyUseRuntimeException or somthing else.

Resources