Caching support for mutitenant enviornment - spring

I have a use-case where I want to "partition" the cache. I've tried using spring annotation based caching. It works fine for a single tenant application.
E.g. The name of the cache in #Cachable is fine, but I want the interceptor to call a CacheResolver class which resolves the end-cache name based on some other contextual metadata I provide through my application.(For example tenant identifier)
The use-case for this is that I want several cache instances which cache the same info, but several different instances to have an isolated instance for each tenant (multitenant environment). This way I can size them suitable for each tenant - but still keep my code/metainfo quite so clean.
Any help would be greatly appreciated.

Related

Using Spring ACL in a complicated access setup for an entity

I am developing a spring boot application with spring-data-rest being one of the core dependencies. As such, in order to secure the auto generated and manual endpoints I have been using a role based approach and a custom PermissionEvaluator to handle object specific auth checks. This works but is too cumbersome and fails when I need a filtered and paginated response. So, I am planning to implement ACL. Now, I have a rather complicated flow of authorisation for an entity.
The users are mapped to a profile entity(MANY TO MANY). The target entity is also mapped to a separate profile entity(MANY TO MANY) and these 2 profile entities are mapped to each other(MANY TO MANY). To check if a particular user has permission over a target entity object, I need to go through the relationships in my application logic, in my PermissionEvaluator.
Now, if I decide to implement this in ACL only, I am confused as to how to best to do this. The preliminary idea that I had is to create the object list directly in the ACL tables for each user(principle). This would mean that I would need to update the ACL tables everytime with new objects if a permission is changed. Is this a correct approach? Is there a better way to do this? Is it even ok to modify the ACL tables frequently?
Summary: If the logic to check if a user has access over an object is complicated and requires data from other tables, how do I handle it efficiently using ACL?
I'm working on an ACL extension for Spring Data JPA/Rest which handles all of your problems - and many more. It take some time to learn how does it work, but it still needs much less time than creating all of these features for yourself.
You can set up the access rules using annotations in the entity classes - and that's all. it will affect the auto-generated and manual endpoints and even the Data JPA repository-methods.
Spring Data JPA ACL

Finer control over Spring Security on Spring Data REST

I have multiple closely related problems in Spring Security. I am developing using Spring Boot and am using Spring Data REST for creating REST endpoints directly from my repositories.
I have multiple entities and the requirement is to have all these entities as REST endpoints. I am letting spring-data-rest handle the creation of these endpoints and I am securing these endpoints by adding #PreAuthorize and #PostAuthorize to the entity repository methods as and where required. This works great when I am calling an endpoint like /entity/id.
But I am facing issues from here. Let's say I have 2 entities, Entity1 and Entity2 and they have a One to One relationship. Spring data rest allows me to fetch the related Entity2 data from Entity1 like /entity1/id/entity2. But I have different access rights over Entity1 and Entity2 and calling the above endpoint only checks the access rights as set up in the repository for Entity1 only. So, if a user has access to Entity1 table and no access to Entity2 table, he can still see some Entity2 data via the foreign key relationship of Entity1. Is this a correct design?
Moreover we have some custom API endpoints wherein we have to aggregate data from multiple entity repositories. Also, these endpoints themselves have to secured. So, I am using a #PreAuthorize over an endpoint method. This works as expected and the endpoint method is called only when the expression is valid. But, when a repository method is called (via a service class of course), the #PreAuthorize over that repository method is also evaluated. I would like to have the check done with at the beginning. Is it possible to do so?
Any suggestions to improving the design is also welcome.
There is no simple solution without massively modifying/overriding lots of default Spring DataRest features. I'm working such a package for years now and it's working quite well for me.
Although switching to this package might be a bit overkill for you, it could worth the trouble in the long run because it also a fixes a lot of problem you will meet only months later.
you can set up permisison rules via annotation directly in the domain objects.
it checks the permisisons in the DB side, so the traffic between the API and DB is heavily decreased (Only those objects are fetched form the DB which the current user has permission to)
you can set READ/UPDATE/DELETE/CREATE permissions separately for roles and/or certain users
you can use pagination on permission filtered collection
you can use pagination on property-collections too
(+ some extra features like flexible search on multiple properties)
here is the package (It's an extension of Spring Data JPA / Data Rest)

Spring session for session sharing(clustering) between servers

I'm trying to let two machines with the same base domain (subdomains differ) to share session.
spring-session-jdbc seems to be a solution I could use to achieve the goal.
When a user logs into server-a, session info is stored in SPRING_SESSION db.
What worries me is the fact that custom org.springframework.security.core.userdetails.UserDetails class is stored in that db as well.
When server-b tries to read session data from the db, it has to use the same custom subclass of the org.springframework.security.core.userdetails.UserDetails.
So I'm copying codes that relates to the UserDetails class from server-a to server-b.
I'm feeling a little awkward doing this, because server-a and server-b might want different UserDetails in general.
Is this really intended way of using spring-session-jdbc ?
Another question is, is it mandatory to use spring-security for both server-a and server-b?
Spring Session is meant to easily enable session clustering, i.e. have the multiple instances of the same app share the external session store therefore making it easier to scale your app.
For the problem you are trying to solve it might be a good idea to use an appropriate higher level protocol such as OAuth 2.0 and OpenID Connect and implement single sign-on without coupling you applications through the session store.
While the idea of sharing session store between different apps might seem convenient initially, such arrangement is usually very problematic, as you noted yourself with the UserDetails example.
In line with Vedran Pavic's answer it sounds like you should be using sso. That said there are instances where different code bases may want to share the same session such as in micro-service clusters. In this case you should simply put your UserDetails into a base jar/module that the other jar/module's are dependent upon. You can use a build automation tool to make this packaging easier to accomplish.
To answer your final question, if these two applications are regularly communicating with each other then I'd recommend either using spring security everywhere or nowhere.
Default mechanism to persist and load session is through the SecurityContextRepository (Spring Security) or SessionRepository (Spring Session).
If you use Redis for session sharing the repository implementation could be RedisSecurityContextRepository (spring-security-redis) or RedisIndexedSessionRepository (Spring Session).
The latter one for sure serialize UserDetails so you cannot share the session unless you use same Frameworks & user classes versions.
I would use custom SessionRepository and store shared user info in portable Json or XML, or whatever you like, not the Java object serialized ))

How to share bean INSTANCE across war in SPRING?

I want to share a singleton bean across multiple war. I know sharing ApplicaitonContext using parentContextKey attribute(Example, http://blog.springsource.org/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/)
But this way instance of bean created multiple (for 2 war, 2 instance). I want only 1 instance across 2 war.
Another way, If i set some value in any POJO, it should be accessible in another war.
Reason i need this is, there are some beans(like HibernateSessionFactory, Datasource etc which are expensive) which are created multiple times(n instance for n war). Whereas i want to utilize same instance instead of creating same in different war.
Can anyone provide me solution for this?
You could achieve this by binding the objects into the global JNDI tree. That means that both WARs would have references to an object looked up in JNDI.
Hibernate allows you to use the hibernate.session_factory_name property (this may well be a good starting point. Data sources should already be looked up from JNDI.
One thing, I would not class a session factory or a data source as expensive, so you may well be saving a miniscule amount of memory in exchange for a lot of additional complexity, so I would ask myself the question on whether this is worth the additional maintenance headaches.
Spring provide a way to expose any bean (service) and these bean can be access from any other web application or any standalone application.
please refer Remoting and Web Service using Spring to get more details.

Scope confusion regarding session beans, proxies, and singletons in a Spring 3 managed JSF app

This seems like it's basic Spring 101 stuff, but I can't seem to find the correct way to do this. The situation is as follows; in my web app there is a single entry point which is a controller that handles users coming from an outside system. The transfer is just a POST request with a bunch of associated information pertaining to that user. Apon entry, I need to create a new User bean and load it with that users information. Additionally, when the user hits a view which triggers some service, I need for that service to be able to access the appropriate User bean instance.
The first way to do this that came to mind was to have a UserManager service which would create a new instance of User, fill it w/ data, and then register it in the Spring container with the username as the bean name. Then when a service is invoked, the service would do something like Factory.getBean(username) to find the appropriate User instance. The problem I see here is that I'm losing the link between the user & which User bean belongs to them. Additionally, I'd like to avoid having the user carry the bean around in the session if at all possible. Is this where I am supposed to be using Spring AOP & proxies?
What is the typical Spring pattern for solving this type of situation?
So it is now many weeks later (since asking this question), and consequently my knowledge level has been expanding exponentially, so I figured I might as well answer my question for anyone who might find it helpful (not to mention the question wasn't very clear to begin with).
The basic answer is: use proxies. Since a singleton is only instantiate 1 time, you cant inject another class which has a shorter lifespan, eg. session scope. For those requiring more information, checkout stateful vs stateless beans. More or less what I ended up doing is this... the services contain STATELESS code for manipulating data (think verbs; RegisterUserSvc, AddPartSvc, etc). The data which these services manipulate is stateful. For instance, each user has a own copy of their own data object, lets say TodoListBean, which is in a different state for each user.
So how does a service, AddTodoItemService for instance, manipulate this data? This is where the proxy comes into play. When instantiated, the AddTodoItemService gets injected with a proxy for the TodoListBean, instead of the actual object. That way when the service needs to access the TodoListBean the container will serve up the a TodoListBean out of the current users session, and therefore the service will be operating on the correct bean (based on which user invoked the service), instead of doing something silly like having numerous copies of the service included in each users session scope.

Resources