I am working on two different spring boot services, that will need to access a common MongoRepository collection of Users.
For the sake of simplicity, we have SpringBootApp1:
User.java
#Document(collection = "user")
public class User {
#Id
private String id;
....
}
Then I get the repository as:
UserRepository.java
public interface UserRepository extends MongoRepository<User, String> {
}
Now I need another application, SpringBootApp2 that reads the Users. I was planning to do the same in the second service, but then I would have two versions of User object, one defined on each service and both of them trying to read from the same MongoRepository collection. If one User class is modified in one service, the other will not know and they will start being off-sync, on top of having repetition or code on both services.
What would be the best approach in this case?
Why you need SpringBootApp2 to read the User table again ? You can expose an API in SpringBootApp1 which will fetch you the desired data by calling from the App2 . All your database related operations you can keep in one micro service or one app, and if you need the data from the database just expose methods in App1 and call that from App2.
UPDATE :
As you said, App1 does READ-WRITE with the collection and grants access only to authenticated users, and App2 does a simple READ-ONLY activity, in that case, you can use the JPA repo interface in App2 with only the read from collection method implemented. You don't need any setters method for the Entity and no save/update method implemented for your interface. This design is harmless. You are just making a call to the same database from two different services. No harm in that. Anyways you are always making a fresh query to the collection from App2.
Else if you have concerns with this approach as well, and if you dont want to keep multiple DB read logics from different services, then (I do not know what else functionalities your App1 offers other than DB operations) I would like to suggest you to create App3 which is only for the sole purpose of DB operations.
In that case :
App1 will do security related operations + other services
Design App3 which does DB manipulation work, without any direct user credentials or security
App1 will perform authentication, and on success call App3 for any DB READ-WRITE work, App3 wont need any security
App2 will call App3 for any DB READ operations, App3 wont need any security
Related
I am writing a spring rest application, the problem is that I am not sure while I should use a repository or when a service interface together with implementation of it. Let's say that I have a repository that has a method findById I created a service interface that has the same method it returns the object and is called Object findById(Long id); and I wonder if I should create an implementation of that that's looks like that
public Object findById(Long id) {
repository.findById(id).orElseThrow(() -> new RuntimeException("message"));
}
but I could also do the same without this service class as the repository also returns a Optional so it could be also done in the controller
repository.findById(id).orElseThrow(() -> new RuntimeException("message"));
But it's hard to test repositories, better is to create an implementation of the service and then test the service. Anyway what's yours opinion about it, which one is better for you and why?
I think it's all about your project architecture. one of the classic, simplest and most favorite architectures is N-Layer architecture which normally is implemented with 3 main layers. Controllers, Services and Repositories.
Controllers are responsible for getting the requests from clients, updating the model usually with calling Services and returning a response for clients.
Services are where your business logic are implemented and where you should usually check for your transaction management and some security checking and etc.
and finally Repositories are where you interact with underlying systems like File System and Database to save the state of your application.
I have an application where single user can work in contexts of multiple companies. We call such a connection (user<->company) a permit. Every one of this permits can have different sets of permissions/roles. We want user to login just once and then he can simply change permits within application without need to enter password again.
Till now we had only one application and kept this whole permission model in our own DB. Unfortunately now we have to support second application which should inherit those permits. I was wondering wether is possible to move that model to keycloak so we don't have to replicate it to every single db and keep it in sync manually.
I have searched keycloak documentation regarding this topic but have found no information att all, which seems quite odd, because I don't think we are the first one working with multiple context application.
So now I'm asking is it possible to configure our model in keycloak and if so, how to do it? Eventually are there different options? I guess that I can provided that model as a claim with json structure but that doesn't feel right to me. I was thinking about custom IDP which could provide such claims based on DB so there no spelling errors and less repetition but I feel there should be a better way.
You could try to write your own Keycloak provider (SPI). There is a built in mechanism that allows you to expose REST endpoint on the Keycloak: https://github.com/keycloak/keycloak/tree/master/examples/providers/domain-extension
That REST could be called with authorized context only for example by passing Access-Token (Authorization header with Bearer value). On the provider level (through implementation of: org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider) you have access to user's Keycloak session and object UserModel like in the following code:
AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(keycloakSession, keycloakSession.getContext().getRealm());
UserModel userModel = authResult.getUser();
UserModel class has methods for getting and setting attributes, so some information that indicates the current permit/company ID can be stored there. You can use REST methods exposed on the Keycloak to modify the model within the 'session' (represented by Access-Token).
The Github example shows also how to use another Keycloak provider (ex. built-in JPA provider) from you custom provider's level, so using that approach you could try to connect to the database with your permits/company informations. Of course the datasource representing you database should also be registered as Keycloak datasource.
I have implemented a REST application with some complicated authorization requirements.
Here's a summary
My customers purchase a proxy device called Collector that enables their home automation control to be centralized. My customers also purchase multiple home automation devices (let's call them HADevices) that report their metrics through the collector to my REST application.
An admin(who is my customer service rep), with role ROLE_ADMIN, should be able to look at any data from any Collector or HADevice. A customer, with role ROLE_USER role, should only be able to view data about the Collector or an HADevice that s/he owns.
The Collector, with role ROLE_COLLECTOR is the only role authorized to insert data i.e. create or update a resource in my REST service. Let's call this url /deviceMetrics (POST). A Collector can insert metrics for any HADevice associated with the customer. HADevices have no role and do not interact with my REST application. A Collector can only insert records to HADevices that have the same customer as the Collector.
I am using spring security 4.0 for authentication and #Secured annotation for authorization. However, I find that my code is cluttered with repetitive permission validations which take up a majority of my logic. The basic insertions and retrievals are pretty straightforward.
I want to use a PermissionEvaluator to centralize Access Control. I have to secure the following urls
GET /collectors/{id}/deviceMetrics - I retrieve the user from the
Principal and verify that the Collector with id={id} in my spring
data repository belongs to the Principal and if not I send a 403
GET/hadevices/{id}/deviceMetrics - I retrieve the user from the
Principal and verify that the HADevice with id={id} in my spring data
repository belongs to the Principal and if not I send a 403.
POST /collectors/{id}/deviceMetrics - I retrieve the Collector uniqueId
from the Principal and make sure that the Collector's id matches the
{id} in the URL
POST /hadevice/{id}/deviceMetrics - I retrieve the
Collector uniqueId from the Principal and the associated Customer. I
also pull the Customer associated with HADevice with id={id} and
compare the two. If they are unequal, I send a 403.
My application is littered with such complex authorization requirements for each REST resource, and I want to use a custom org.springframework.security.access.PermissionEvaluator, specifically by implementing the following method.
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)
I'm planning to use a combination of targetType and request.getUrl() to get a specialized Evaluator for each url and resource.
Is there a better way to do this?
Your question is quite broad, but I think you can get away with quite simple logic for most cases.
GET /collectors/{id}/deviceMetrics
Given that you have a DeviceMetrics class with suitable properties, you can annotate your data repository with something like:
#PostAuthorize("hasRole('ROLE_ADMIN') or (hasRole('ROLE_USER') and returnObject.collector.owner = authentication.name)")
public DeviceMetrics getDeviceMetrics(long deviceId);
(This assumes that DeviceMetrics class has a property collector which has a property owner which is the username.)
That doesn't need a PermissionEvaluator at all. Maybe you need one for more complex cases:
POST /collectors/{id}/deviceMetrics
#PreAuthorize("hasRole('ROLE_COLLECTOR') and hasPermission(#collectorId, 'com.example.Collector', 'WRITE')")
public void saveDeviceMetrics(long collectorId, DeviceMetrics deviceMetrics);
You only need one PermissionEvaluator since you get all the information you need as method arguments.
For those who are wondering what my solution looks like, I borrowed from this example.
It's old and it's based on xml configuration which I am not particularly fond of. But the idea is to create a Map and initialize the custom PermissionValidator and to store the authorization logic in the Permission interface implementations.
The biggest pain point was injecting an autowired HashMap of tuples, but that's an implementation detail that reasonably experienced spring users can figure out.
With spring-data a #RepositoryRestResource allow me to perform CRUD operations for a given #Entity class. All is impressively magical but how can I add a security layer to prevent anybody to call a million times the insertion URL?
It seems, this problem is not specific to Spring Data REST. If you have any public interface that allows to add data to your database, you have the same problem.
However, regarding Spring Data REST, there are (at least) two possibilities:
Don't export the save(T) method
Use #RestResource(exported = false) to prevent Spring Data REST to export certain methods at all:
#RepositoryRestResource(path = "people", rel = "people")
interface PersonRepository extends CrudRepository<Person, Long> {
#Override
#RestResource(exported = false)
void save(Person person);
}
You can still use the save(T) method in your code, but it won't be available via REST. See the reference documentation for more details.
Secure your application with Spring Security
Require users to log in before they are allowed to save data. Spring Data REST provides an example that shows how to secure a Spring Data REST application in multiple ways with Spring Security: Spring Data REST + Spring Security
I am trying to create various services, such as:
UserService
UserPermissionService
AddressBookService
Which would access dao's such as:
UserDao
UserPermissionDao
AddressBookDao
CompanyDao
These will use Spring-Hibernate stack and be packaged in a backend jar for multiple webapps. I want the service functionality to be available depending on the permission of the calling user object. Also, Caller (user) object will have permissions of the calling user.
Query: Should I pass Caller to each Service method call and then check its permission? Or is there a better way using 'Spring/AOP' and/or 'Factory Pattern' where the Caller object can be available to the Service methods.
One of the patterns for this case is to store security token in a ThreadLocal and to require corresponding privilege from that token first thing in a service method.