From b5e32b2420e7a5b217eb99bcf514a18da0447989 Mon Sep 17 00:00:00 2001 From: mghilardelli Date: Mon, 15 Jul 2024 15:50:40 +0200 Subject: [PATCH] feat: multitenancy for token exchange --- .../DynamicClientRegistrationRepository.java | 35 +++++++++++++++++++ .../controller/CustomClaimController.java | 32 +++++++---------- .../src/main/resources/application.yaml | 15 +++----- 3 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 playground-backend/src/main/java/ch/sbb/playgroundbackend/config/DynamicClientRegistrationRepository.java diff --git a/playground-backend/src/main/java/ch/sbb/playgroundbackend/config/DynamicClientRegistrationRepository.java b/playground-backend/src/main/java/ch/sbb/playgroundbackend/config/DynamicClientRegistrationRepository.java new file mode 100644 index 00000000..c4818c5c --- /dev/null +++ b/playground-backend/src/main/java/ch/sbb/playgroundbackend/config/DynamicClientRegistrationRepository.java @@ -0,0 +1,35 @@ +package ch.sbb.playgroundbackend.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ClientRegistrations; +import org.springframework.security.oauth2.core.AuthorizationGrantType; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtClaimNames; + +@Configuration +public class DynamicClientRegistrationRepository implements ClientRegistrationRepository { + + @Value("${auth.exchange.client-id}") + private String clientId; + + @Value("${auth.exchange.client-secret}") + private String clientSecret; + + @Value("${auth.exchange.scope}") + private String scope; + + @Override + public ClientRegistration findByRegistrationId(String registrationId) { + String issuerUri = (String) ((Jwt) (SecurityContextHolder.getContext().getAuthentication().getPrincipal())).getClaims().get(JwtClaimNames.ISS); + return ClientRegistrations.fromIssuerLocation(issuerUri) + .authorizationGrantType(AuthorizationGrantType.JWT_BEARER) + .clientId(clientId) + .clientSecret(clientSecret) + .scope(scope) + .build(); + } +} diff --git a/playground-backend/src/main/java/ch/sbb/playgroundbackend/controller/CustomClaimController.java b/playground-backend/src/main/java/ch/sbb/playgroundbackend/controller/CustomClaimController.java index fb7c5935..42db2883 100644 --- a/playground-backend/src/main/java/ch/sbb/playgroundbackend/controller/CustomClaimController.java +++ b/playground-backend/src/main/java/ch/sbb/playgroundbackend/controller/CustomClaimController.java @@ -5,40 +5,35 @@ import ch.sbb.playgroundbackend.model.azure.TokenIssuanceStartRequest; import ch.sbb.playgroundbackend.model.azure.TokenIssuanceStartResponse; import ch.sbb.playgroundbackend.model.azure.TokenIssuanceStartResponseData; -import lombok.RequiredArgsConstructor; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.messaging.handler.annotation.Header; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @RestController @RequestMapping("customClaim") -@RequiredArgsConstructor public class CustomClaimController { private static final Logger log = LoggerFactory.getLogger(CustomClaimController.class); + private final Map tokenClaimDataMap = new HashMap<>(); private final OAuth2AuthorizedClientManager manager; - private final ClientRegistrationRepository clientRegistrationRepository; - public static final String SFERA_TOKEN_REGISTRATION = "sfera-token"; - private final Map tokenClaimDataMap = new HashMap<>(); + public CustomClaimController(@Qualifier("authorizedClientManager") OAuth2AuthorizedClientManager manager) { + this.manager = manager; + } @GetMapping("requestToken") String tokenRequest(Authentication authentication, String ru, String train, String role) { @@ -48,17 +43,14 @@ String tokenRequest(Authentication authentication, String ru, String train, Stri tokenClaimDataMap.put(userId, new Claims(ru, train, role)); - var clientRegistration = clientRegistrationRepository.findByRegistrationId(SFERA_TOKEN_REGISTRATION); - - OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId( - clientRegistration.getRegistrationId()) - .principal(authentication) - .build(); + OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("exchange") + .principal(authentication) + .build(); OAuth2AuthorizedClient client = manager.authorize(oAuth2AuthorizeRequest); if (client == null) { throw new IllegalStateException( - "failed to retrieve sfera-token failed, client is null"); + "failed to retrieve sfera-token failed, client is null"); } return client.getAccessToken().getTokenValue(); } diff --git a/playground-backend/src/main/resources/application.yaml b/playground-backend/src/main/resources/application.yaml index 51648857..9210aeb6 100644 --- a/playground-backend/src/main/resources/application.yaml +++ b/playground-backend/src/main/resources/application.yaml @@ -12,17 +12,6 @@ spring: security: oauth2: authorizationUrl: https://login.microsoftonline.com/common/oauth2/v2.0 - client: - provider: - azure-active-directory: - issuer-uri: https://login.microsoftonline.com/2cda5d11-f0ac-46b3-967d-af1b2e1bd01a/v2.0 - registration: - sfera-token: - provider: azure-active-directory - client-id: ${CLIENT_ID} - client-secret: ${CLIENT_SECRET} - authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer - scope: api://${SFERA_CLIENT_ID}/.default resourceserver: jwt: jwk-set-uri: https://login.microsoftonline.com/2cda5d11-f0ac-46b3-967d-af1b2e1bd01a/discovery/v2.0/keys @@ -78,3 +67,7 @@ auth: - name: issuer-uri: jwk-set-uri: + exchange: + client-id: ${CLIENT_ID} + client-secret: ${CLIENT_SECRET} + scope: api://${SFERA_CLIENT_ID}/.default