Use OAuth2 for authorization of session-authenticated users - spring

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...)

Related

Disable or bypass OAuth security for microservice-to-microservice communication in Spring Boot

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.

Spring Cloud - Micoservice Authentication propagation

I am building an application using microservice architecture. I am using Eureka for service discovery with Spring Cloud Gateway for request routing. For authentication mechanism I am issuing JWT tokens (in auth service). What is the best practice when it comes to propagating Authentication so I can get logged user information in each service which is after the gateway?
So far I've came up/found couple of possible solutions:
In gateway add headers for relevant user information, and in each service create filter which would take said headers and create Authentication object and store it into SecurityContextHolder. The downside of this approach is I can't just plug and play services outside my application.
Pass the token coming from the client through the gateway to the each service, where I would have JWTFilter which would validate token and extract the user information. Downside I see with this approach is I have to have jwt secret shared between each service or stored on each service, and I would have to implement JWT logic, producing duplicate code.
Final solution is having something like oAuth token introspection endpoint in auth service which would be called from each service (filter) once the request reaches it.
I implemented the filter logic for validating the user token in the gateway service, but I would like to use role based authorization on each endpoint (service) differently (ie. user service has endpoint for creating users (ADMIN), and for fetching user information (ANY ROLE)).
I opted for something like your option 2 and use spring-boot to configure JWT decoder from an OIDC authorization-server (Keycloak).
Configuring OpenID resource-servers is super easy (more options in parent folder), and authorization-server JWT public signing key is retrieved automatically by spring JWT decoder.
All that is required is ensuring that Authorization header with JWT bearer is correctly propagated between services.

Resource Owner Password Credentials with Spring Boot

I have a legacy desktop application that communicates with a Spring Boot server (latest version 2.2.2.RELEASE). I'm using OAuth2 for authentication (provided by spring-boot-starter-oauth2-client). I want to avoid changing the client because is a legacy application. It is capable of collecting the credentials and start the session via HTTP Basic Authentication, and then keep the cookies for the session in the following requests.
Given this scenario, I think best option is to make use the OAuth2 Resource Owner Password Credentials grant. With this, we can exchange the collected credentials by the OAuth2 Tokens. We have two options:
Option 1:
Modify the client application to use the access tokens via the Authorization header. This will require to make an initial call to the Authorization Provider to exchange the collected credentials by the tokens.
Option 2:
Keep using the Spring session and store the information about the OAuth client in the server.
I found this project ALMOST does that: https://github.com/jgrandja/spring-security-oauth-5-2-migrate. It has a client (messaging-client-password) defined with authorization-grant-type: password which will activate the OAuth2 Resource Owner Password Credentials grant in Spring Boot.
It creates an OAuth2 client and stores its information in the session, then Spring is able to use that client in further requests. The problem with this project is it seems to only work as when the OAuth client is used to make HTTP requests (e. g. an endpoint that makes a call to another service) and not provide authentication to the controller. You can find more information about this in here:
Spring Security 5.2 Password Flow
Github related issues: link1, link2, link3
Exception thrown when we try to use the password client as authentication
The natural idea to overcome this is to implement a proxy and use the OAuth2 client in the requests. Well, Spring already offers a proxy solution, the Spring Cloud Gateway. But I don't know to accomplish that with this setup.
Any insights? Am I thinking correctly or should I follow a different approach?

JWT with Spring OAuth2

I have created the Spring Authorization Server which issues JWT-s and a Resource Server which checks the JWT, its claims and permissions on the Authorization Server. To do so, I have followed this article.
My question is why I need to send the Authorization header with HTTP Basic authorization and Base64 encoded username/password (ClientId:ClientSecret) in get token request? I have seen JWT implementations where only username and password are required.
It is part of the specification, see RFC 6749:
2.3 Client Authentication
If the client type is confidential, the client and authorization server establish a client authentication method suitable for the security requirements of the authorization server. The authorization server MAY accept any form of client authentication meeting its security requirements.
Confidential clients are typically issued (or establish) a set of client credentials used for authenticating with the authorization server (e.g., password, public/private key pair).
The authorization server MAY establish a client authentication method with public clients. However, the authorization server MUST NOT rely on public client authentication for the purpose of identifying the client.
The client MUST NOT use more than one authentication method in each request.
By default Spring Security OAuth 2.0 protects the token endpoint, see OAuth 2 Developers Guide:
The token endpoint is protected for you by default by Spring OAuth in the #Configuration support using HTTP Basic authentication of the client secret.
But it seems, that you can disable the client authentication:
Spring Security OAuth 2.0 - client secret always required for authorization code grant
Is it possible to get an access_token from Spring OAuth2 server without client secret?
Spring Security OAuth 2.0 with no client_secret
That is the structure of the JWT token:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
As you are doing a JWT implementation all the 3 parts must be there: header.payload.secret
Maybe in the implementation you have seen - the server was working with Default Secret

Spring sso oauth2 client unable to request for access token

on spring boot 1.4, using #EnableOAuth2Sso for sso client and a kong third party authorization server, i'm able to receive the authorization code but unable to retrieve the access token.
the authorization code is part of the redirect url after which is there any configuration or a process for retrieving the access token?
Once you get the Authz code, you need to make a server side call(so that access token flow doesn't go through end user browser) to Authz Server for access_token, Look at this section of OAuth 2.0 Spec.

Resources