How to propagate User's authentication (and authorization) to other microservices - spring-boot

I've created a microservice (using Spring boot) for landing page. User provides the credentials and upon successful login, he can see the dashboard. I've used RestTemplate in-order to traverse to other microservice from the dashboard. Below is the code snippets:
#Autowired
private RestTemplate restTemplate;
#GetMapping("/employeeCenter")
public String openEmployeeCenterApp() {
logger.info("Invoking EmployeeCenter micro-service");
return restTemplate.getForEntity("http://EMPLOYEE-SERVICE/empCenter/", String.class).getBody();
}
Which is working fine. But I would like to propagate the User's authentication (and authorization) to any other microservices; so that based on the user's privilage, I can show/hide stuffs. What would be the suitable way to do that?

There are many concerns here.
When a "landing page" service (let's call it "A") shows the dashboard for user with identity "Foo" and tries to contact an another service "B" which is an another process via Rest template, you should implement the identity propagation of "Foo", its not the job for the spring security. Spring security will help you in authentication / authorization of user "Foo" inside the service "A", but it has nothing to do with identity propagation.
After all, service "B" can be something not written with spring or java at all, or even some external system.
There are many approaches here depending on requirements that usually boil down to:
Rely on the fact that only landing page (service A) is your "gateway" to the outer world and hence on this service requires security
Protect all the services (like putting spring security or any other security component in each service)
Like "1" but differentiate between security gateway and landing page - have two microservices, so that gateway will be protected and will be "opened" to the end users but also to internal communication. The difference is that if you need to call service "B" from service "A" you can do it through the gateway and it will check the security
Another concern here is what exactly means the "act" of calling the service B from service A.
One thing is to tell "I'm user Foo (currently in a Service A) and I'm calling B as Foo.
Another thing is telling "I'm service A (that has its own identity) and I'm calling service B on behalf of user Foo".
All these question are in domain of security related architecture and many solutions can be adopted. If you have to do such an analysis (although its kind of out of scope for this question) make sure that you understand that performance implications of each approach:
- HTTP hops can be expensive
- DB hops (in case you have to turn to the database) are expensive
Apply caching wherever possible
Now, technically speaking, you should provide some Filter that will add Identity Headers taken from the Thread Local or similar solution if you run reactive stack.
So in the most simple situation you can put an identity object on some thread local and get it in the filter to add requests.
So that bottom line when you construct a request in a RestTemplate (that in turn relies on okHttp, Apache Http Client or whatever) it will have additional headers that will provide the identity information (and again its up to you to decide what exactly is an "identity" here).
The service "B" in turn should parse this object again in some kind of filter (ideally before it hits the rest controller if "B" is in spring as well) or even with spring security if you have it installed on Service B, and make its "protection decisions" based on that identity, then again, put it on thread local if B will query other services and so forth.

You can try using WebSecurityConfigurerAdapter and override the configuration of AuthenticationManagerBuilder bean which will let you set roles.
This article has a good example: https://www.journaldev.com/8748/spring-security-role-based-access-authorization-example

Related

Is it correct to make a call to another Spring microservice inside a filter?

I built a Spring authentication microservice that takes care of authenticating each REST request. The authentication mechanism has been built using JWT. Each request should present an Authentication: Bearer header.
I also built a gateway microservice that exposes some of the API of the back end microservices. Each request to the gateway should be authenticated. I was thinking about implementing a OncePerRequestFilter, from which I could call the authentication microservice.
#Component
public class AuthFilter extends OncePerRequestFilter {
#Autowired
private RestTemplate restTemplate;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// User restTemplate to call the authentication microservice and authenticate the request.
}
}
My question is probably a little too broad, but I wanted to try anyway.
Are there any issues on making a HTTP request inside a Spring filter? Could this lead to hangs or anything in some edge cases or is it just a poor design?
It is okay to call the external service inside a Filter. Spring Security also often does it in various cases (e.g. authenticate against LDAP, get JWK to verify JWT signature etc.) It may not call the external service directly inside the filter , but the filter will delegate to other object to call the external service. But the idea is the same, just make sure that you handle the case when the external service is not available such as setting a reasonable timeout on the HTTP request when calling the external service. Consider it as fail if it cannot receive the response from the external service after timeout.
P.S. Look like you are implementing your own authorization flow. If your authentication service support OAuth2 , you can consider to try Spring Security 5 's OAuth2 support which may make your life easier.
I agree with you that this approach is contradictory.
I see 2 main constraints in this approach:
this filter in request scope, so you can face with connection/read timeout;
more complex error handling (nested structure requires more accuracy in that).
If you can avoid these constraints, you can use this approach: RestTemplate is synchronous and blocking, so your filter will wait for results of RestTemplate call. With WebClient, such task could be unachievable.
Obviously that this implementation contradicts to SOLID, so better change your design/architecture.
It's a general practice to make HTTP calls from one microservice to another.
When dealing with authentication in REST API using JWT tokens it's a common practice to load cryptographic keys from a well known URL (https://YOUR_DOMAIN/.well-known/jwks.json) as JSON Web Key Set (JWKS).
According to SOLID principles, it's a good practice to create a dedicated class (Spring service) responsible for calling another service instead of injecting RestTemplate directly into the Filter.
The less responsibilities class has, the easier (less error-prone) it is to make changes to it in the future and cover code with unit tests. When all the logic is located in a single class, you have a lot of test cases and complicated mocking. When class has a single responsibility and calls another classes, it's easy to mock these classes and test only this single responsibility.
When a microservice calls another microservice via REST API, there are a few aspects that should be taken into account:
Failover - have multiple instances of the microservice to tolerate failure if a single instance
Scalability - dynamically start more microservice instances to handle growing load
Load balancing - route requests to different instances of the microservice
Service discovery - allow microservices to find each other by logical name instead of hard-coding host and port values
Timeouts - drop a request to a downstream microservice after exceeding timeout instead of waiting for the response forever
Retries - retry failed requests to a downstream microservice
Circuit breaker - prevent network or service failure from cascading to other services
These aspects are covered by Kubernetes + Istio or Spring Cloud stack.
If synchronous REST API calls between microservices are replaced with asynchronous messaging then almost all of these aspects are not so important.
For example, service A, instead of calling service B via REST API, subscribes on events emitted by service B to a Kafka topic. Every time event occurs, service A receives notification and persists the required data in own DB.
Such approach allows to achieve maximum decoupling between services but leads to eventual consistency. It means, it doesn't suit authentication and other strongly consistent cases. E.g. checking account balance is strongly consistent and should be done using synchronous call.

Where to manage session in microservices architecture with Spring Boot

I am fairly new in microservices architecture. I've been trying to build a microservices stack using Spring Boot, Spring Cloud and Netflix OSS libraries.
I want to know what is the correct way and place to store session.
Here is an overview of the infrastructure that I created:
OAuth2 backed Authorization/Authentication Server
UI Service (Spring Boot, Front end service)
Backend Service-1
Backend Service-2
Redis Server to store session and other cachable data
Discovery Server (eureka)
Currently, I'm trying to store session in Redis by configuring UI service to perform it. It seems to be working fine, although I haven't had the chance to try it for multiple service instances. However, I'm already having serialization/deserialization issues while developing.
By the way, trying to store the session on front end app is the correct place to do or it should be done in Authorization/Authentication service as authentication is processed in that service?
Here is my Session config in UI service (front end service)
#Configuration
#EnableRedisHttpSession
public class SessionConfig extends
AbstractHttpSessionApplicationInitializer {
public SessionConfig() {
super(RedisConfig.class);
}
}
To sum up, I'm expecting to achieve and use best practices on this project. Your kind assistance would be appreciated.
The idea of a general server side user session and a microservices style architecture don't go together well. The reason being that you are likely to break the separation of concern that you use separate the domain boundaries of your services.
Remember, every service is supposed to service a specific domain problem autonomously - including all required data persistence. So for example if there is anything to remember for a users connected devices you would do that in the one service that is responsible for those device connections and nowhere else. The service would be responsible for processing those request and persisting any status that the devices require. Similarly when there is anything to remember about he users authorization you would do that in the authorization service.
And regarding the question to use Redis or not - In a microservices architecture the choice of storage system would be up to the service architect. Maybe one service stores its data in a relational database, maybe another uses a key-value-store and yet another may use an event queue system or a time series database.
So in summary you have to ask yourself what your session really is used for and make the corresponding services responsible to persist that information in a domain specific way. (If you give some more details in your question about this, I can give you my opinion).

Spring Security - Method level security and non-authenticated invocations

I have a vanilla Spring Boot application that consists of a controller, a service and a DAO layer. The controller code calls the service code and so on.
To implement some semblance of security, I am currently using Spring Security 4.0.x's global method security annotations in combination with Spring Security ACL to lock down my service methods.
Requests that go through my controllers are auth-ed and authorized just fine because a principal / user is in context. HOWEVER, I also have some additional non-user facing code that listens for messages from an AWS queue. Within this listener code I invoke some secured services (to stay DRY and not duplicate business logic) but for this situation no user is in scope.
Generally speaking:
For a situation like the one I'm describing, what is a good / acceptable way to authenticate user-less method invocations e.g. ones that don't come through an HTTP request (or to bypass the check)? I am considering manually setting the SecurityContextHolder with a "system user" in my message listener code but this has some code smell.
Is method level security better applied at the controller level?

With Spring Security OAuth2, how do I limit a client to only allow certain user types

Scenario
We are using Spring Security 2 with OAuth2 integration in our system.
In the system there is different user types and different internal and external OAuth clients.
Some of these clients only want User type A to be allowed to log in while others only want to allow type B.
Question
I've been looking at different places to inject this logic and the only place I can see where one would get both username and client id is in the ApprovalStore interface which means I could potentially implement an ApprovalStore that return empty Approvals for the undesired combinations.
Is this the correct place or is there a better place to put this logic?

Securing microservices behind a entrypoint with Spring Security

Anyone know what the simples way to secure a microservice architecture that is behind a entrypoint?
The case is, we need a server that takes a TCP socket connection. The implementation to authenticate a user on this application is already implemented and it basically uses Spring Security with UserDetailsService and assigns the socket connection with the specific TCP connection.
But now we are considering going for a more microservices architecture, but we are having problems finding a good way to propagate the user to the different services.
E.g.:
User connects to TCP Socket server, authenticates.
User sends a request through the socket, the server propagates the call to another backing service (e.g. a Spring Data REST repository), but the call the client makes (e.g. a change request for a set of data) needs a specific user role. How can this role be checked?
So basically, the TCP server is issuing a service request on behalf of the user.
It depends on the authentication procedure. If you already use a Single Sign On capable authentication such as CAS 2, you can add Spring Security on your micro services using the proxy feature of CAS.
If you micro services are hidden behind your front end application, that is if no user can directly contact them, you can simply pass the user id in the request between front end and micro service. As the micro service can only be hit from a trusted application, you can directly use the user id.
If you want to make use of advanced spring-security features (#PreAuthorize, #PostFilter, ...) in the micro services, you can use a custom PreAuthenticatedAuthenticationFilter in the spring security configuration of the micro services, whatever the authentication procedure is. That filter would simply use the user id passed in the request to set the user authentication token.
All those solution allows not to cache the password in the front-end application, which is allways possible (in a session attribute) but looks as a bad security practice.
Anyway, you can use stateless security for the micro services part, since the frontend will always send a user id. According to Spring Security Reference Manual, it is as simple as adding an attribute to the http config : < http create-session=stateless> (this parameter exists since version 3.0)
If you use java configuration, you can do the same from a WebSecurityConfigurerAdapter :
class SecurityConf extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
...
}
...
}

Resources