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?
Related
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.
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
I am implementing a Spring Data REST based app and I would like to know if there is an elegant way to implement authentication and authorization rules using this framework or related frameworks.
All HTTP requests to the REST server must carry authentication headers, I need to check them and decide to authorize or not based on the HTTP method and the association of the authenticated user with the resource being requested. For example, (the app is the REST server of an e-learning system), the instructors can access only their own course sections, students can access only the courses sections they are subscribed, etc.
I would like to know if there is a default way to implement authorization in Spring Data REST. If the answer is no, could you make a suggestion for my issue? I am thinking about:
Servlet Filters
Spring Security
Spring Data REST Handlers (how to access the HTTP headers?)
The best bet for you is Spring Security.
That would help you achieve authorization is much simpler manner.
Spring Security would require you an implementation that looks at request headers and performs the log-in operation programmatically.
Refer the accepted answer here.. I had followed the same and implemented the security layer in front of my rest services ( which were build using RestEasy )
RESTful Authentication via Spring
There is an alternate method as well..
Refer
http://www.baeldung.com/spring-security-authentication-provider
In both cases you can disable the session creation by declaring the stateless authentication in spring security, this would help you improve the performance considerably when large volume of hits are made to the state-less REST services..
My application exposes a RESTful API which when called calls out to a mailbox server and fetches data. I want to be able disable the service during application runtime in the event of some outage on the mailbox server. I wanted to do this in a way that the logic of deciding whether or not to call the mailbox server was abstracted from the actual code that calls the mailbox server. Two options which seem to fit this scenario are filters and interceptors however I'm looking for advice on which one best suits this requirement and what are the difference between each?
Thanks
If you are using Spring MVC then you can use an interceptor, which is like a filter but that has access to the Spring context. If you are using Jersey then you can't use interceptors.
I need to use Concurrent Session Control features of Spring Security. I need to invalidate the previous session of the logged in user(single user sign in). I do not need the feature of authentication and authorization, since it was already implemented by the application using Servlet(Filter) which calls serice layer that calls dao layer(Hibernate).
Please guide me how to implement Concurrent Session Control without authentication and authorization.
Thanks,
balachandar
One option (hack) would be to use Spring's pre-authentication feature. i.e. you would perform your authentication in your filter and set an attribute on the request object which is the username. The request would then be passed down to Spring and Spring where the concurrent session control feature could be enabled.
But really the best option would be to implement concurrent session control in your filter. You could even "borrow" some code from the spring source.
Short answer: you can't unless you refactor your application to use spring-security fully.
Slightly longer answer: you can "fake" a Java EE container login (pre-authenticated). That would entail specifying a login-filter derived from AbstractPreAuthenticatedProcessingFilter in your spring security http configuration. For instance, you could wrap your request in your filter and add a header values and use the RequestHeaderAuthenticationFilter, or you could write your own that pulls the principal from a request attribute you set on the request in your own login filter. Combine with a PreAuthenticatedAuthenticationProvider.
Slightly longer answer #2: you could use an allow-all kind of setup where you configure spring-security with session concurrency as usual but set the access to permitAll for all URLs (is <intercept-url pattern="/*" access="permitAll" />). You would, however, have to implement essentially what the ConcurrentSessionControlStrategy does in your own login logic, to get the sessions registered into the spring security SessionRegistry. You will most likely run into any number of other snags along the way as well.
Note however that since spring-security works on the basis of a servlet filter (not a servlet like Spring MVC), you will need to refactor your own login as a filter and place it before the spring security filter in the chain, if you are to go with some combination of your own auth logic and spring security.
My advice, if you want to leverage spring-security for concurrent session control, you should really go all the way and build your auth on top of spring-security instead of some custom servlet. Don't fight the framework, use it as intended. Or, don't use it at all.