From 579223596f72fc15f47bbe759a5f9198dd9750aa Mon Sep 17 00:00:00 2001 From: Fiete Ostkamp Date: Wed, 19 Jul 2023 09:12:31 +0000 Subject: Remove vavr from the bff - part 2 Issue-ID: PORTALNG-18 Signed-off-by: Fiete Ostkamp Change-Id: I54dece01debdc487bdc6c38df1141ddae1f2e97f --- build.gradle | 4 -- .../bff/config/IdTokenExchangeFilterFunction.java | 70 +++++++++++----------- .../portal/bff/config/clients/KeycloakConfig.java | 4 -- .../onap/portal/bff/services/KeycloakService.java | 46 +++++++------- 4 files changed, 61 insertions(+), 63 deletions(-) diff --git a/build.gradle b/build.gradle index 9ce6023..1f78aa7 100755 --- a/build.gradle +++ b/build.gradle @@ -11,8 +11,6 @@ buildscript { ext { springBootVersion = '2.7.3' springCloudVersion = '3.1.3' - vavrVersion = '0.10.4' - vavrJacksonVersion = '0.10.3' lombokVersion = '1.18.24' openapiVersion = '6.0.1' redocVersion = '2.0.0-rc.65' @@ -68,8 +66,6 @@ allprojects { } dependencies { - implementation "io.vavr:vavr:$vavrVersion" - implementation "io.vavr:vavr-jackson:$vavrJacksonVersion" implementation "org.springframework.boot:spring-boot-starter-logging" implementation "net.logstash.logback:logstash-logback-encoder:$logstashLogbackVersion" diff --git a/lib/src/main/java/org/onap/portal/bff/config/IdTokenExchangeFilterFunction.java b/lib/src/main/java/org/onap/portal/bff/config/IdTokenExchangeFilterFunction.java index be3493d..9cd8ac0 100644 --- a/lib/src/main/java/org/onap/portal/bff/config/IdTokenExchangeFilterFunction.java +++ b/lib/src/main/java/org/onap/portal/bff/config/IdTokenExchangeFilterFunction.java @@ -22,9 +22,10 @@ package org.onap.portal.bff.config; import com.nimbusds.jwt.JWTParser; -import io.vavr.control.Option; -import io.vavr.control.Try; +import java.text.ParseException; +import java.util.Collections; import java.util.List; +import java.util.Optional; import org.springframework.util.AntPathMatcher; import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientResponse; @@ -33,6 +34,7 @@ import org.springframework.web.reactive.function.client.ExchangeFunction; import org.springframework.web.server.ServerWebExchange; import org.zalando.problem.Problem; import org.zalando.problem.Status; +import reactor.core.Exceptions; import reactor.core.publisher.Mono; public class IdTokenExchangeFilterFunction implements ExchangeFilterFunction { @@ -61,13 +63,8 @@ public class IdTokenExchangeFilterFunction implements ExchangeFilterFunction { } return extractServerWebExchange(request) .flatMap(IdTokenExchangeFilterFunction::extractIdentityHeader) - .flatMap( - idToken -> { - final ClientRequest requestWithIdToken = - ClientRequest.from(request).header(X_AUTH_IDENTITY_HEADER, idToken).build(); - - return next.exchange(requestWithIdToken); - }) + .map(idToken -> ClientRequest.from(request).header(X_AUTH_IDENTITY_HEADER, idToken).build()) + .flatMap(requestWithIdToken -> next.exchange(requestWithIdToken)) .switchIfEmpty(Mono.defer(() -> next.exchange(request))); } @@ -78,11 +75,9 @@ public class IdTokenExchangeFilterFunction implements ExchangeFilterFunction { } private static Mono extractIdentityHeader(ServerWebExchange exchange) { - return io.vavr.collection.List.ofAll( - exchange.getRequest().getHeaders().getOrEmpty(X_AUTH_IDENTITY_HEADER)) - .headOption() - .map(Mono::just) - .getOrElse(Mono.error(Problem.valueOf(Status.FORBIDDEN, "ID token is missing"))); + return Mono.just(exchange) + .map(exch -> exch.getRequest().getHeaders().getOrEmpty(X_AUTH_IDENTITY_HEADER).get(0)) + .onErrorResume(ex -> Mono.error(Problem.valueOf(Status.FORBIDDEN, "ID token is missing"))); } private static Mono extractIdToken(ServerWebExchange exchange) { @@ -96,30 +91,35 @@ public class IdTokenExchangeFilterFunction implements ExchangeFilterFunction { return extractRoles(exchange) .map(roles -> roles.stream().anyMatch(rolesListForMethod::contains)) .flatMap( - match -> { - if (Boolean.TRUE.equals(match)) { - return Mono.empty(); - } else { - return Mono.error(Problem.valueOf(Status.FORBIDDEN)); - } - }); + match -> + Boolean.TRUE.equals(match) + ? Mono.empty() + : Mono.error(Problem.valueOf(Status.FORBIDDEN))); } private static Mono> extractRoles(ServerWebExchange exchange) { return extractIdToken(exchange) - .flatMap( - token -> - Try.of(() -> JWTParser.parse(token)) - .mapTry(jwt -> Option.of(jwt.getJWTClaimsSet())) - .map( - optionJwtClaimSet -> - optionJwtClaimSet - .flatMap( - jwtClaimSet -> - Option.of(jwtClaimSet.getClaim(CLAIM_NAME_ROLES))) - .map(obj -> (List) obj)) - .map(Mono::just) - .getOrElseGet(Mono::error)) - .map(optionRoles -> optionRoles.getOrElse(List.of())); + .map( + token -> { + try { + return JWTParser.parse(token); + } catch (ParseException e) { + throw Exceptions.propagate(e); + } + }) + .map( + jwt -> { + try { + return Optional.of(jwt.getJWTClaimsSet()); + } catch (ParseException e) { + throw Exceptions.propagate(e); + } + }) + .map( + optionalClaimsSet -> + optionalClaimsSet + .map(claimsSet -> claimsSet.getClaim(CLAIM_NAME_ROLES)) + .map(obj -> (List) obj)) + .map(roles -> roles.orElse(Collections.emptyList())); } } diff --git a/lib/src/main/java/org/onap/portal/bff/config/clients/KeycloakConfig.java b/lib/src/main/java/org/onap/portal/bff/config/clients/KeycloakConfig.java index 0935a00..168c350 100644 --- a/lib/src/main/java/org/onap/portal/bff/config/clients/KeycloakConfig.java +++ b/lib/src/main/java/org/onap/portal/bff/config/clients/KeycloakConfig.java @@ -24,7 +24,6 @@ package org.onap.portal.bff.config.clients; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import java.util.function.Function; -import lombok.extern.slf4j.Slf4j; import org.onap.portal.bff.config.BeansConfig; import org.onap.portal.bff.config.PortalBffConfig; import org.onap.portal.bff.exceptions.DownstreamApiProblemException; @@ -32,7 +31,6 @@ import org.onap.portal.bff.openapi.client_portal_keycloak.ApiClient; import org.onap.portal.bff.openapi.client_portal_keycloak.api.KeycloakApi; import org.onap.portal.bff.openapi.client_portal_keycloak.model.ErrorResponseKeycloakDto; import org.onap.portal.bff.openapi.server.model.ProblemApiDto; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,14 +39,12 @@ import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; -@Slf4j @Configuration public class KeycloakConfig extends AbstractClientConfig { private final ObjectMapper objectMapper; private final PortalBffConfig bffConfig; private final ExchangeFilterFunction oauth2ExchangeFilterFunction; - @Autowired public KeycloakConfig( @Qualifier(BeansConfig.OAUTH2_EXCHANGE_FILTER_FUNCTION) ExchangeFilterFunction oauth2ExchangeFilterFunction, diff --git a/lib/src/main/java/org/onap/portal/bff/services/KeycloakService.java b/lib/src/main/java/org/onap/portal/bff/services/KeycloakService.java index 88c25c2..765efa7 100644 --- a/lib/src/main/java/org/onap/portal/bff/services/KeycloakService.java +++ b/lib/src/main/java/org/onap/portal/bff/services/KeycloakService.java @@ -21,12 +21,11 @@ package org.onap.portal.bff.services; -import io.vavr.API; -import io.vavr.Tuple; -import io.vavr.Tuple2; import java.net.URI; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -44,6 +43,7 @@ import org.springframework.stereotype.Service; import org.zalando.problem.Status; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import reactor.util.function.Tuples; @Slf4j @RequiredArgsConstructor @@ -141,6 +141,21 @@ public class KeycloakService { log.debug("Get users from keycloak. page=`{}`, pageSize=`{}`", page, pageSize); final int first = (page - 1) * pageSize; + var userIdRoleMap = + listRoles(xRequestId) + .flatMap( + role -> + listUsersByRole(role.getName(), xRequestId) + .map(userResponse -> Tuples.of(role.getName(), userResponse))) + .collectList() + .map( + tupleList -> + tupleList.stream() + .collect( + Collectors.groupingBy( + tuple -> tuple.getT2().getId(), + Collectors.mapping(tuple -> tuple.getT1(), Collectors.toList())))); + return Mono.zip( keycloakApi.getUsersCount(null, null, null, null, null, null, null), keycloakApi @@ -148,31 +163,22 @@ public class KeycloakService { null, null, null, null, null, null, null, null, first, pageSize, null, null, null, null) .collectList(), - listRoles(xRequestId) - .flatMap( - role -> - listUsersByRole(role.getName(), xRequestId) - .map(user -> Tuple.of(user.getId(), role.getName()))) - .collectList() - .map(io.vavr.collection.List::ofAll) - .map(list -> list.groupBy(t -> t._1).map((k, v) -> Tuple.of(k, v.map(Tuple2::_2))))) + userIdRoleMap) .map( tuple -> { final UserListResponseApiDto result = new UserListResponseApiDto(); + Map> userRoleMap = tuple.getT3(); result.setTotalCount(tuple.getT1()); - result.setItems( - io.vavr.collection.List.ofAll(tuple.getT2()) + var roleList = + tuple.getT2().stream() .map( user -> usersMapper.convert( user, - tuple.getT3().getOrElse(user.getId(), API.List()).toJavaList())) - .toJavaList()); - // result.setItems( - // tuple.getT2().stream() - // .map(user -> usersMapper.convert(user,tuple.getT3())) - // .toList()); - + Optional.ofNullable(userRoleMap.get(user.getId())) + .orElse(Collections.emptyList()))) + .toList(); + result.setItems(roleList); return result; }) .onErrorResume( -- cgit 1.2.3-korg