-
Hi all! I'm trying to migrate a configuration for multitenant transparent login using Keycloak Adapters with Spring Boot 2 to simple Spring Security 6. I've implemented a solution based on an HeaderBasedConfigResolver that permits redirect to the correct keycloak realm URL, based on an header prevously set, following this article -> https://www.czetsuyatech.com/2020/11/spring-boot-multi-tenancy-with-keycloak.html With this implementation I implement an HeaderBasedConfigResolver that resolve the configuration based on a specific header so the Keycloak Adapter can redirect to the correct login URL (based on the realm name). Now, Keycloak Adapters doesn't work anymore with Spring Boot 3, so I was trying to find an alternative solution. I don't find anything that can fit my needs, but only a solution that prompts for the authorization server to use... So I'm asking an advice BR |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
If you are in the case of "static" mutli-tenancy (you know at startup which issuers you want to trust), a look at the BFF tutorial and more specifically at the GatewayController. The idea behind this implementation is that a REST endpoint exposes the list of URIs to initiate user authentication (DTO is composed of an URI and a This achieves what you want with just one small difference: the frontend uses a different URI for each issuer (provided by the Spring OAuth2 client) without any specific header, instead of a unique URI with a different header for each issuer. |
Beta Was this translation helpful? Give feedback.
-
@lucapino as a preamble, apparently, your Angular app is configured as a "public" OAuth2 client, which has been considered a worst practice for years. Spring Security team published about that 2-3 years ago and you might find posts from other security experts even before that. Requests from your Angular app should be authorized with sessions (and CSRF protection), not with tokens. You should probably use a middleware (a Backend For Frontend, aka BFF) between your Angular app and your Spring resource servers to translate from session based security to token based security. But all that is already explained in the tutorial I linked in my preceding comment. Back to your question: apparently you did not understand the solution in my preceding comment, so I'll try to be very specific with samples. Let's say that you host two sites:
Let's now say that each site has it's own realm with respectively as issuers:
Let's also say that, as BFF, you have a
user-name-attribute: preferred_username
luca-issuer: https://sso.lucapino.it/realms/luca
luca-client-id: luca-bff
luca-client-secret: change-me
tagliani-issuer: https://sso.lucapino.it/realms/tagliani
tagliani-client-id: tagliani-bff
tagliani-client-secret: change-me
spring:
security:
oauth2:
client:
provider:
luca:
issuer-uri: ${luca-issuer}
user-name-attribute: ${user-name-attribute}
tagliani:
issuer-uri: ${tagliani-issuer}
user-name-attribute: ${user-name-attribute}
registration:
luca:
provider: luca
client-id: ${luca-client-id}
client-secret: ${luca-client-secret}
authorization-grant-type: authorization_code
scope:
- openid
- offline_access
tagliani:
provider: tagliani
client-id: ${tagliani-client-id}
client-secret: ${tagliani-client-secret}
authorization-grant-type: authorization_code
scope:
- openid
- offline_access Last, let's consider that you have a reverse-proxy with following routing with a single BFF instance and 2 distinct Angular apps served from nginx containers or dev-servers or whatever:
Now, on the BFF (which holds the OAuth2 client configuration and is responsible for driving the authorization-code flow), you expose a {
"luca": "https://www.luca.it/oauth2/authorization/luca",
"tagliani": "https://www.tagliani.it/oauth2/authorization/tagliani"
} All the Of course, if you already have a header on the frontend with an identifier of the issuer or registration you want to use with that frontend, you can send it along with the In any case, your Angular app should be ready to get:
I hope you can adapt by yourself the use-case above if you prefer to use On the resource server side, this is just standard "static" multi-tenancy configuration: requests will arrive from the BFF with tokens containing either |
Beta Was this translation helpful? Give feedback.
Edit: my preceding answer probably better covers the subject.
The solution you request sticks to the Angular app being a public client. This is bad. Have you solely read the Final Recommendation from the 1st post in the thread I linked several times already? To be very clear your Angular app should not have access to tokens (which means that it should not be able to send tokens with request) and the OAuth2 client configuration resolution should not be done in Angular.
Appart from that: