I'm trying to understand 100% how a Resource Server works, relaying the incoming token downstream to other services.
I have a microservice architecture with spring boot eureka, with Bearer authentication against an #EnableAuthorizationServer.
I use an Edge Service in zuul with #EnableZuulProxy and #EnableOAuth2Sso for request entry, and I wanted security to be centralized at that point, but of course, I can't leave the microservices without security and each of them is an #EnableResourceServer.
Everything works ok.
The question is:
Either with a security.oauth2.resource.user-info-uri pointing to the oauth server or to the edge service, that bearer token is always validated against the oauth server, i.e. if it passes through 10 microservices a request, will it validate the token 10 times against the oauth server?
Isn't there any way that I don't have to request 10 times to the oauth server if the token is valid?
All right,
It seems that for a Bearer token type, it is always necessary to authenticate on each resource server against the authentication server.
The solution is to use JWT tokens.
As explained in:
https://developer.okta.com/blog/2018/04/02/client-creds-with-spring-boot#extra-credit-reduce-the-number-of-calls-to-the-authorization-server
We use signed JWTs which means you can validate them locally instead of making an additional request from the API service to the authorization server on each request.
That's it.
Related
I'm developing a microservices application that has to authenticate users against an external Identity Provider using SAML2 protocol.
The architecture
The idea is to use a SPA running in the browser which only talks to the API Gateway and uses Cookies for authentication.
The gateway delegates the Authorization Server to check if each request is authenticated and initialize the SAML2 login if not.
Once the user authenticates, the Authorization server initializes a session and sends back the cookie straight to the browser.
The Authorization Server is actually an OAuth2 Auth Server as well as a SAML2 Service Provider.
For every request coming after the user authenticated, I want internal communications to use OAuth2.
Frameworks used
For the authorization server I'm using the Spring Authorization Server package as well as SAML2 Service Provider libraries of Spring Security.
Resource services would use Spring Boot OAuth2 Server library.
What's working
I managed to set up the SAML2 client so that the Authorization Server is already generating a Session for the user after IdP authentication and I'm capable of reading the authenticated principal.
The problem
For the upcoming requests I want the API Gateway to perform a token replacement by exchanging the Cookie for an OAuth2 access token before forwarding these requests to resource services. Each resource service will then validate these tokens against the authorization server.
What I'm trying to achieve here is to make the API Gateway as a Backend-for-Frontend but the I'm struggling to figure out which authorization flow to use given that:
the client is the API Gateway, so it can be considered confidential
user credentials are missing as they are provided to an external IdP and the principal comes from a SAML Response
the authorization server has already estabilished a session for the user
Basically I can't figure out how to exchange the JSessionID for an authorization code.
Any ideas?
You should not bother about the authentication-code, the BFF (gateway configured as OAuth2 client) should receive it and exchange it for tokens (access, ID and refresh) during login process and store those in session (which should be activated along with CSRF protection).
When requests land on the gateway, session is replaced with Bearer access-token (kept in session) before being forwarded to resource-server. This behavior is activated with the tokenRelay filter in route properties (if I remember well...)
I have some microservices in Spring Boot and my front end application is in angular. I am using OpenID Connect for authentication and authorization. Right now, in my application, when the angular app is loaded, it redirects the user to the authentication server and after login the token is received which is sent by the angular application in each HTTP request to the resource servers. Now I have a question. My microservices also communicate with each other but as each microservice is acting as a resource server and the Rest APIs are secure now, so microservices can not communicate. What I want to achieve is that the requests which are sent by the user from the angular app should contain a token and those requests should be verified but I want to bypass or disable OAuth security for inter service-service communication between microservices. Is there any way to achieve this in Spring Boot?
Do not disable OAuth2 security in your micro-services:
if the inter-services request has the context of user (issued to satisfy part of an authorized request) just forward the original access-token
if inter-services request is not originated by a user request / event / callback,... (scheduled task for instance), then it is possible to acquire an access-token using client credentials flow. Authorization-server should be configured to attach required roles to each client when it issues access-tokens with client credentials flow.
In first case, you can access bearer token from the Authentication in the security context. Add this Bearer string as Authorization header to the requests to other micro-services.
In second case configuring REST client (WebClient, RestTemplate, FeignClient, ...) with client credentials is usually enough for it to automatically fetch an access-token from the authorization-server and add it as bearer header before sending requests to the resource-server.
I have 2 secured resource microservices and 1 authentication service and another API Gateway.
Authentication service can generate JWT Token given username and password. It also can validate a JWT token.
So, I want to implement security at the API Gateway only such that on receiving a request, it will first fetch a bearer token from the authentication service and forward the request to the secured resource service. I would like to get some idea how to implement that in API Gateway. Should I make it just in an aggregate fashion, like it would be a sync call which will first make a request to auth service and next forward the request to resource service?
Now, if I want to add the support of OAuth as well, which I know the spring cloud API Gateway already has the support for this via global filters.
But, I am wondering about the legacy bearer token which is generated by the custom authentication service.. How do I ensure this?
Any suggestion would be appreciated.
Thanks in advance!
I want to use Keycloak in a microservices based environment, where authentication is based on OpenID endpoints REST calls ("/token", no redirection to keycloak login page), a flow that I thought of would be something like this:
1. Front-end SPA retrieves the tokens from the "/token" endpoint and stores in browser's localStorage, then sends it with every request.
2. Gateway-level authentication: Acess Token is passed from the front end to the gateway, gateway consults Keycloak server to check if the token is still valid (not invalidated by a logout end-point call).
3. Micro-service based authorization: Acess Token is passed from the Gateway to the microservices, using Spring Boot adapter the microservices check the signature of the token offline (bearer-only client?) then based on the role in the token do the authorization.
My questions are: Does this flow make sense or can you suggest another flow? What type of Keycloak clients to use? What's an ideal way to pass Tokens using Spring Boot Adapter, and should it be done like that in the first place? Please keep in mind that I am not a Keycloak expert, I've done my research but I still have doubts.
Your Front-end SPA should be public-client and springboot micro service should be Bearer only Client and Gateway could be Confidential Client.
You can check the Keycloak provided oidc adapters. For springboot you use the keycloak provided adapter
Similar solution using api gateway is discussed here
I am trying to implement the above architecture in the workflow with Spring Boot.
Web client makes a request to Resource Server (Microservices Endpoints) through Zuul Proxy.
Zuul Proxy redirects to oauth2 server for authentication.
Oauth2 redirects to Zuul Proxy if the request is authenticated or not.
If not authenticated, Zuul redirects Web client with an unauthenticated response.
If Authenticated, Zull proxy redirects to the requested microservice endpoint.
Microservice endpoint checks if the user is authorized (user level access) to access the resource or not.
Microservice also could make internal rest call to other microservice.
Finally, the requested resource is sent back to the client.
I want to make sure I am following the correct workflow.
I would like to know if there is any solution which has implemented a similar kind for securing microservices APIs.
I have confusion on:
How can we pass the user details to the microservices so that the microservices can do their own level of user authorization?
Should the OAuth2 Access Token header be passed to each microservices such that microservices can validate the token separately?
Should each Microservice use secret credentials to validate the access token so that the token cannot be forged along the request chain?
I know its a bit of lengthy question. But I have not found a proper solution to above architecture.
Unfortunately, I don't have complete answer, only some parts:
Once JWT token is available to the zuul proxy then every microservice can authorize requests by configuring its resource server, e.g.
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().access("#oauth2.hasScope('microserviceA.read')").and()
.csrf().disable()
.httpBasic().disable();
}
Scopes could be managed by the oauth microservice with a database - basing on the client credentials it will take the scopes info and encode into JWT token.
What I don't know at the moment - how to make the zuul proxy to use "web client" credentials to authorize itself by the oauth - I don't want to hard-code zuul proxy credentials because then the web-client creds won't be used.
I've just posted similar question on this topic:
Authorizing requests through spring gateway with zool via oauth server
update:
I've found article describing almost this configuration (without eureka, but it doesn't that add much complexity from my experience): https://www.baeldung.com/spring-security-zuul-oauth-jwt, there is github project with source code. The source code is unfortunately not polished as it's being used by the author for his commercial courses.
But I've managed to build from his examples working set.
Summary: in the described architecture every resource server (microservice A, B, ..) receive JWT token forwarded by the zuul proxy/gateway from the requesting client. The token is forwarded in a request header. If there is no valid token provided then the gateway will redirect the request to authorization page.
Also every resource server can check the token with the oauth service and if required do scope checking as I wrote above.
I've been struggling with same security design issue for microservice architecture based on spring cloud solution. I only find this article shedding some light on it: https://developer.okta.com/blog/2018/02/13/secure-spring-microservices-with-oauth
But it's pertaining to Okta sso service provider, not a generic solution to other oauth2 server like keycloak.
I also saw some solutions on how to protect gateway and microservice with oauth2 server like this one:
https://github.com/jgrandja/oauth2login-gateway
But it doesn't take into consideration the web client.
I am not sure whether you were able to resolve this, I can see this is not answered yet, but there is a way you can pass all information from JWT to all downstream microservices.
Write your own ZuulAuthenticationFilter, and then create below method
private void addClaimHeaders(RequestContext context, String token) {
try {
Map<String, Claim> claims = jwtTokenVerifier.getAllClaims(token);
claims.forEach((key, claim) -> {
context.addZuulRequestHeader("x-user-info-"+key, String.valueOf(claim.as(Object.class)));
});
}catch(Exception ex) {
log.error("Error in setting zuul header : "+ex.getMessage(), ex);
}
}
this way, you will get information from JWT in headers in each microservice, headers that starts with "x-user-info-" will have your JWT details
There is an implementation of the above architecture in following link:
https://www.baeldung.com/spring-security-zuul-oauth-jwt