From 1ea2342517e8d663f29f804cfac36d5a51b00b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristen=20H=C3=A6rum?= Date: Thu, 19 Dec 2024 13:45:46 +0100 Subject: [PATCH] Bugfix/altinn3 tilgang (#3700) Lagt til proxy for altinn3-tilgang-service i prod, oppdatert endepunkter for Altinn3-tilgang-service, oppdatert dolly-idporten frontend --------- Co-authored-by: stigus Co-authored-by: Cato Olsen --- .github/workflows/integration-tests.yml | 10 +- apps/altinn3-tilgang-service/README.md | 1 + apps/altinn3-tilgang-service/build.gradle | 1 + apps/altinn3-tilgang-service/config.dev.yml | 1 + apps/altinn3-tilgang-service/config.prod.yml | 1 + .../docker-compose.yml | 18 +++ apps/altinn3-tilgang-service/settings.gradle | 2 +- .../consumer/altinn/AltinnConsumer.java | 45 ++++--- .../CreateAccessListeMemberCommand.java | 10 +- .../DeleteAccessListMemberCommand.java | 8 +- .../command/GetAccessListMembersCommand.java | 8 +- .../command/GetAuthorizedPartiesCommand.java | 40 +++++++ .../consumer/altinn/dto/AccessToken.java | 0 ....java => AltinnAccessListResponseDTO.java} | 2 +- .../AltinnAuthorizedPartiesRequestDTO.java | 18 +++ .../altinn/dto/AuthorizedPartyDTO.java | 42 +++++++ .../domain/PersonRequest.java | 13 ++ .../AltinnBrukerTilgangController.java | 33 ++++++ ... AltinnOrganisasjonTilgangController.java} | 6 +- .../service/AltinnBrukerTilgangService.java | 112 ++++++++++++++++++ ... => AltinnOrganisasjonTilgangService.java} | 2 +- .../service/MiljoerOversiktService.java | 14 +-- .../src/main/resources/application-local.yml | 6 +- .../src/main/resources/application.yml | 3 +- apps/dolly-frontend/config.idporten.yml | 5 +- apps/dolly-frontend/config.test.yml | 2 - apps/dolly-frontend/config.unstable.yml | 2 - apps/dolly-frontend/config.yml | 2 - .../web/DollyFrontendApplicationStarter.java | 2 - .../no/nav/dolly/web/config/Consumers.java | 1 - ...inn3PersonOrganisasjonTilgangConsumer.java | 66 +++++++++++ .../PersonOrganisasjonTilgangConsumer.java | 62 ---------- ...PostPersonOrganisasjonTilgangCommand.java} | 24 ++-- .../consumers/dto/AltinnBrukerRequest.java | 11 ++ .../web/consumers/dto/OrganisasjonDTO.java | 12 -- .../provider/web/BrukerTilgangController.java | 29 +++++ .../web/provider/web/SessionController.java | 7 +- .../main/js/playwright/mocks/BasicMocks.tsx | 3 +- .../main/js/playwright/tests/Bankid.spec.ts | 2 +- .../src/main/js/proxy-routes.json | 7 +- .../PersonOrganisasjonTilgangService.tsx | 5 +- .../utils/hooks/useOrganisasjonTilgang.tsx | 2 +- .../src/main/resources/application-local.yml | 3 - .../src/main/resources/application.yml | 5 - .../src/main/resources/logback-spring.xml | 14 +-- .../libs/dto/altinn3/v1/OrganisasjonDTO.java | 17 +++ .../libs/dto/altinn3/v1/PersonDTO.java | 32 +++++ .../GetAuthenticatedResourceServerType.java | 16 ++- .../action/GetAuthenticatedToken.java | 27 ++++- .../action/GetAuthenticatedUserId.java | 20 +++- .../reactivesecurity/action/JwtResolver.java | 23 +--- .../action/Oauth2Resolver.java | 35 ++++++ 52 files changed, 618 insertions(+), 214 deletions(-) create mode 100644 apps/altinn3-tilgang-service/docker-compose.yml create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAuthorizedPartiesCommand.java delete mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AccessToken.java rename apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/{AltinnResponseDTO.java => AltinnAccessListResponseDTO.java} (95%) create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAuthorizedPartiesRequestDTO.java create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AuthorizedPartyDTO.java create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/domain/PersonRequest.java create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnBrukerTilgangController.java rename apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/{AltinnTilgangController.java => AltinnOrganisasjonTilgangController.java} (89%) create mode 100644 apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnBrukerTilgangService.java rename apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/{AltinnTilgangService.java => AltinnOrganisasjonTilgangService.java} (98%) create mode 100644 apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/Altinn3PersonOrganisasjonTilgangConsumer.java delete mode 100644 apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/PersonOrganisasjonTilgangConsumer.java rename apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/{GetPersonOrganisasjonTilgangCommand.java => PostPersonOrganisasjonTilgangCommand.java} (59%) create mode 100644 apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/AltinnBrukerRequest.java delete mode 100644 apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/OrganisasjonDTO.java create mode 100644 apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/BrukerTilgangController.java create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/OrganisasjonDTO.java create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/PersonDTO.java create mode 100644 libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/Oauth2Resolver.java diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 16c25d9ff37..9351999c60b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -3,7 +3,6 @@ on: push: paths: - 'apps/bruker-service/**' - - 'apps/person-organisasjon-tilgang-service/**' workflow_dispatch: jobs: @@ -14,11 +13,4 @@ jobs: working-directory: 'apps/bruker-service/' healthcheck: 'http://localhost:8002/internal/isAlive' secrets: - NAV_TOKEN: ${{ secrets.NAV_TOKEN }} - person-organisasjon-tilgang-service: - if: github.event.pull_request.draft == false - uses: ./.github/workflows/common.integration-test.yml - with: - working-directory: 'apps/person-organisasjon-tilgang-service/' - healthcheck: 'http://localhost:8001/internal/isAlive' - secrets: inherit \ No newline at end of file + NAV_TOKEN: ${{ secrets.NAV_TOKEN }} \ No newline at end of file diff --git a/apps/altinn3-tilgang-service/README.md b/apps/altinn3-tilgang-service/README.md index ad8b6f4dd72..baad90dca7e 100644 --- a/apps/altinn3-tilgang-service/README.md +++ b/apps/altinn3-tilgang-service/README.md @@ -10,3 +10,4 @@ Swagger finnes under [/swagger-ui.html](https://testnav-altinn3-tilgang-service. ## Lokal kjøring * [Generelt.](../../docs/local_general.md) * [Secret Manager.](../../docs/local_secretmanager.md) +* [Database i GCP.](../../docs/gcp_db.md) diff --git a/apps/altinn3-tilgang-service/build.gradle b/apps/altinn3-tilgang-service/build.gradle index 1ea7ae40843..cf1162f4ca0 100644 --- a/apps/altinn3-tilgang-service/build.gradle +++ b/apps/altinn3-tilgang-service/build.gradle @@ -10,6 +10,7 @@ sonarqube { } dependencies { + implementation "no.nav.testnav.libs:data-transfer-objects" implementation "no.nav.testnav.libs:reactive-core" implementation "no.nav.testnav.libs:reactive-security" diff --git a/apps/altinn3-tilgang-service/config.dev.yml b/apps/altinn3-tilgang-service/config.dev.yml index b9d45fba561..16511daa0a1 100644 --- a/apps/altinn3-tilgang-service/config.dev.yml +++ b/apps/altinn3-tilgang-service/config.dev.yml @@ -23,6 +23,7 @@ spec: consumes: - name: altinn:resourceregistry/accesslist.read - name: altinn:resourceregistry/accesslist.write + - name: altinn:accessmanagement/authorizedparties.resourceowner accessPolicy: inbound: rules: diff --git a/apps/altinn3-tilgang-service/config.prod.yml b/apps/altinn3-tilgang-service/config.prod.yml index f24efb9735e..2ea338b1fb7 100644 --- a/apps/altinn3-tilgang-service/config.prod.yml +++ b/apps/altinn3-tilgang-service/config.prod.yml @@ -23,6 +23,7 @@ spec: consumes: - name: altinn:resourceregistry/accesslist.read - name: altinn:resourceregistry/accesslist.write + - name: altinn:accessmanagement/authorizedparties.resourceowner accessPolicy: inbound: rules: diff --git a/apps/altinn3-tilgang-service/docker-compose.yml b/apps/altinn3-tilgang-service/docker-compose.yml new file mode 100644 index 00000000000..b0eb57bd211 --- /dev/null +++ b/apps/altinn3-tilgang-service/docker-compose.yml @@ -0,0 +1,18 @@ +services: + + cloud_sql_proxy: + image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.2 + network_mode: host + command: + - "dolly-dev-ff83:europe-north1:testnav-altinn3-tilgang-local" + - "--credentials-file=/application_default_credentials.json" + - "--run-connection-test" + volumes: + - type: bind + # Set a variable $DOLLY_APPLICATION_CREDENTIALS. We don't use + # GOOGLE_APPLICATION_CREDENTIALS, as this causes an extra step during login. + # + # - $HOME/.config/gcloud/application_default_credentials.json for Linux/macOS. + # - $APPDATA/gcloud/application_default_credentials.json for Windows. + source: $DOLLY_APPLICATION_CREDENTIALS + target: /application_default_credentials.json \ No newline at end of file diff --git a/apps/altinn3-tilgang-service/settings.gradle b/apps/altinn3-tilgang-service/settings.gradle index e7a413ca6d0..d7e1b8e69d7 100644 --- a/apps/altinn3-tilgang-service/settings.gradle +++ b/apps/altinn3-tilgang-service/settings.gradle @@ -6,9 +6,9 @@ rootProject.name = 'altinn3-tilgang-service' includeBuild "../../plugins/java" +includeBuild '../../libs/data-transfer-objects' includeBuild '../../libs/reactive-core' includeBuild '../../libs/reactive-security' -includeBuild '../../libs/vault' develocity { buildScan { diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/AltinnConsumer.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/AltinnConsumer.java index ae8f52b3b39..cf62199a355 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/AltinnConsumer.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/AltinnConsumer.java @@ -10,8 +10,11 @@ import no.nav.testnav.altinn3tilgangservice.consumer.altinn.command.CreateAccessListeMemberCommand; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.command.DeleteAccessListMemberCommand; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.command.GetAccessListMembersCommand; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.command.GetAuthorizedPartiesCommand; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.command.GetExchangeTokenCommand; -import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnResponseDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAccessListResponseDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAuthorizedPartiesRequestDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AuthorizedPartyDTO; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.BrregResponseDTO; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.OrganisasjonCreateDTO; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.OrganisasjonDeleteDTO; @@ -25,6 +28,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -76,7 +80,7 @@ public Flux delete(String organisasjonsnummer) { return Flux.from(getAccessListMembers() .flatMapMany(value -> Flux.fromIterable(value.getData())) - .map(AltinnResponseDTO.AccessListMembershipDTO::getIdentifiers) + .map(AltinnAccessListResponseDTO.AccessListMembershipDTO::getIdentifiers) .collectList() .map(data -> getIdentifier(data, organisasjonsnummer)) .map(identifier -> @@ -106,16 +110,16 @@ public Flux create(String organisasjonsnummer) { new OrganisasjonCreateDTO(organisasjonsnummer), altinnConfig).call()) .flatMapMany(response -> - isBlank(response.getFeilmelding()) ? - Flux.fromIterable(response.getData()) - .map(this::getOrgnummer) - .filter(organisasjonsnummer::equals) - .flatMap(brregConsumer::getEnheter) : - Mono.just(BrregResponseDTO.builder() - .organisasjonsnummer(organisasjonsnummer) - .feilmelding(response.getFeilmelding()) - .status(response.getStatus()) - .build())) + isBlank(response.getFeilmelding()) ? + Flux.fromIterable(response.getData()) + .map(this::getOrgnummer) + .filter(organisasjonsnummer::equals) + .flatMap(brregConsumer::getEnheter) : + Mono.just(BrregResponseDTO.builder() + .organisasjonsnummer(organisasjonsnummer) + .feilmelding(response.getFeilmelding()) + .status(response.getStatus()) + .build())) .map(response -> mapperFacade.map(response, Organisasjon.class)); } @@ -125,7 +129,18 @@ public Flux getOrganisasjoner() { .flatMapMany(this::convertToOrganisasjon); } - private Mono getAccessListMembers() { + public Flux getAuthorizedParties(String ident) { + + return maskinportenConsumer.getAccessToken() + .flatMap(this::exchangeToken) + .flatMap(exchangeToken -> new GetAuthorizedPartiesCommand(webClient, + new AltinnAuthorizedPartiesRequestDTO(ident), + exchangeToken).call()) + .map(Arrays::asList) + .flatMapIterable(list -> list); + } + + private Mono getAccessListMembers() { return maskinportenConsumer.getAccessToken() .flatMap(this::exchangeToken) @@ -135,7 +150,7 @@ private Mono getAccessListMembers() { altinnConfig).call()); } - private Flux convertToOrganisasjon(AltinnResponseDTO altInnResponse) { + private Flux convertToOrganisasjon(AltinnAccessListResponseDTO altInnResponse) { return Flux.fromIterable(altInnResponse.getData()) .map(this::getOrgnummer) @@ -155,7 +170,7 @@ private OrganisasjonDeleteDTO getIdentifier(List data, String organisa } @SneakyThrows - private String getOrgnummer(AltinnResponseDTO.AccessListMembershipDTO data) { + private String getOrgnummer(AltinnAccessListResponseDTO.AccessListMembershipDTO data) { return data.getIdentifiers() .get(ORGANISASJON_ID) diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/CreateAccessListeMemberCommand.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/CreateAccessListeMemberCommand.java index 997a7b65a70..d665fd9723d 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/CreateAccessListeMemberCommand.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/CreateAccessListeMemberCommand.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.altinn3tilgangservice.config.AltinnConfig; -import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnResponseDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAccessListResponseDTO; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.OrganisasjonCreateDTO; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.http.HttpHeaders; @@ -16,7 +16,7 @@ @Slf4j @RequiredArgsConstructor -public class CreateAccessListeMemberCommand implements Callable> { +public class CreateAccessListeMemberCommand implements Callable> { private static final String ALTINN_URL = "/resourceregistry/api/v1/access-lists/{owner}/{identifier}/members"; @@ -27,7 +27,7 @@ public class CreateAccessListeMemberCommand implements Callable call() { + public Mono call() { return webClient .post() @@ -37,14 +37,14 @@ public Mono call() { .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .retrieve() - .bodyToMono(AltinnResponseDTO.class) + .bodyToMono(AltinnAccessListResponseDTO.class) .doOnError(WebClientFilter::logErrorMessage) .doOnSuccess(value -> log.info("Altinn organisasjontilgang opprettet for {}", organisasjon.getData().stream() .map(data -> data.split(":")) .map(data -> data[data.length-1]) .collect(Collectors.joining()))) - .onErrorResume(throwable -> Mono.just(AltinnResponseDTO.builder() + .onErrorResume(throwable -> Mono.just(AltinnAccessListResponseDTO.builder() .status(WebClientFilter.getStatus(throwable)) .feilmelding(WebClientFilter.getMessage(throwable)) .build())); diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/DeleteAccessListMemberCommand.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/DeleteAccessListMemberCommand.java index ddaac4a82da..e685b681507 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/DeleteAccessListMemberCommand.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/DeleteAccessListMemberCommand.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.altinn3tilgangservice.config.AltinnConfig; -import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnResponseDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAccessListResponseDTO; import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.OrganisasjonDeleteDTO; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.http.HttpHeaders; @@ -19,7 +19,7 @@ @Slf4j @RequiredArgsConstructor -public class DeleteAccessListMemberCommand implements Callable> { +public class DeleteAccessListMemberCommand implements Callable> { private static final String ALTINN_URL = "/resourceregistry/api/v1/access-lists/{owner}/{identifier}/members"; @@ -30,7 +30,7 @@ public class DeleteAccessListMemberCommand implements Callable call() { + public Mono call() { return webClient .method(HttpMethod.DELETE) @@ -41,7 +41,7 @@ public Mono call() { .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .bodyValue(identifiers) .retrieve() - .bodyToMono(AltinnResponseDTO.class) + .bodyToMono(AltinnAccessListResponseDTO.class) .doOnSuccess(value -> log.info("Altinn organisasjontilgang slettet for {}", identifiers.getData().stream() .filter(data -> data.contains(ORGANISASJON_ID)) diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAccessListMembersCommand.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAccessListMembersCommand.java index 1c615118bf7..19f63d2f8db 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAccessListMembersCommand.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAccessListMembersCommand.java @@ -3,7 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.altinn3tilgangservice.config.AltinnConfig; -import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnResponseDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAccessListResponseDTO; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -14,7 +14,7 @@ @Slf4j @RequiredArgsConstructor -public class GetAccessListMembersCommand implements Callable> { +public class GetAccessListMembersCommand implements Callable> { private static final String ALTINN_URL = "/resourceregistry/api/v1/access-lists/{owner}/{identifier}/members"; @@ -23,7 +23,7 @@ public class GetAccessListMembersCommand implements Callable call() { + public Mono call() { return webClient .get() @@ -32,7 +32,7 @@ public Mono call() { .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .retrieve() - .bodyToMono(AltinnResponseDTO.class) + .bodyToMono(AltinnAccessListResponseDTO.class) .doOnError(WebClientFilter::logErrorMessage) .doOnSuccess(value -> log.info("Altinn-tilgang hentet")); } diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAuthorizedPartiesCommand.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAuthorizedPartiesCommand.java new file mode 100644 index 00000000000..d58693bacb2 --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/command/GetAuthorizedPartiesCommand.java @@ -0,0 +1,40 @@ +package no.nav.testnav.altinn3tilgangservice.consumer.altinn.command; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AltinnAuthorizedPartiesRequestDTO; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AuthorizedPartyDTO; +import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; + +@Slf4j +@RequiredArgsConstructor +public class GetAuthorizedPartiesCommand implements Callable> { + + private static final String ALTINN_URL = "/accessmanagement/api/v1/resourceowner/authorizedparties"; + + private final WebClient webClient; + private final AltinnAuthorizedPartiesRequestDTO request; + private final String token; + + @Override + public Mono call() { + + log.info("Spørring på bruker {}", request); + return webClient + .post() + .uri(builder -> builder.path(ALTINN_URL) + .build()) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .bodyValue(request) + .retrieve() + .bodyToMono(AuthorizedPartyDTO[].class) + .doOnError(WebClientFilter::logErrorMessage); + } +} \ No newline at end of file diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AccessToken.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AccessToken.java deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnResponseDTO.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAccessListResponseDTO.java similarity index 95% rename from apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnResponseDTO.java rename to apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAccessListResponseDTO.java index 720fec9136f..6521fa55049 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnResponseDTO.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAccessListResponseDTO.java @@ -17,7 +17,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class AltinnResponseDTO { +public class AltinnAccessListResponseDTO { private List data; private String feilmelding; diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAuthorizedPartiesRequestDTO.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAuthorizedPartiesRequestDTO.java new file mode 100644 index 00000000000..7e2eecded37 --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AltinnAuthorizedPartiesRequestDTO.java @@ -0,0 +1,18 @@ +package no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto; + +import lombok.Data; + +@Data +public class AltinnAuthorizedPartiesRequestDTO { + + private static final String IDENT_IDENTIFIKATOR = "urn:altinn:person:identifier-no"; + + private String type; + private String value; + + public AltinnAuthorizedPartiesRequestDTO(String ident) { + + this.type = IDENT_IDENTIFIKATOR; + this.value = ident; + } +} diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AuthorizedPartyDTO.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AuthorizedPartyDTO.java new file mode 100644 index 00000000000..0fe03486d57 --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/consumer/altinn/dto/AuthorizedPartyDTO.java @@ -0,0 +1,42 @@ +package no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.isNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizedPartyDTO { + + private String name; + private String organizationNumber; + private String unitType; + private Boolean isDeleted; + private List authorizedResources; + private List subunits; + + public List getAuthorizedResources() { + + if (isNull(authorizedResources)) { + authorizedResources = new ArrayList<>(); + } + return authorizedResources; + } + + public List getSubunits() { + + if (isNull(subunits)) { + subunits = new ArrayList<>(); + } + return subunits; + } +} + diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/domain/PersonRequest.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/domain/PersonRequest.java new file mode 100644 index 00000000000..40f9ef759f0 --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/domain/PersonRequest.java @@ -0,0 +1,13 @@ +package no.nav.testnav.altinn3tilgangservice.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PersonRequest { + + private String ident; +} diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnBrukerTilgangController.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnBrukerTilgangController.java new file mode 100644 index 00000000000..55893774beb --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnBrukerTilgangController.java @@ -0,0 +1,33 @@ +package no.nav.testnav.altinn3tilgangservice.provider; + +import lombok.RequiredArgsConstructor; +import no.nav.testnav.altinn3tilgangservice.domain.PersonRequest; +import no.nav.testnav.altinn3tilgangservice.service.AltinnBrukerTilgangService; +import no.nav.testnav.libs.dto.altinn3.v1.OrganisasjonDTO; +import no.nav.testnav.libs.dto.altinn3.v1.PersonDTO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RestController +@RequestMapping("/api/v1/brukertilgang") +@RequiredArgsConstructor +public class AltinnBrukerTilgangController { + + private final AltinnBrukerTilgangService brukerTilgangService; + + @PostMapping + public Flux getPersonOrganisasjonTilgang(@RequestBody PersonRequest request) { + + return brukerTilgangService.getPersonOrganisasjonTilgang(request.getIdent()); + } + + @PostMapping("/detaljert") + public Mono getPersonOrganisasjonDetaljertTilgang(@RequestBody PersonRequest request) { + + return brukerTilgangService.getPersonOrganisasjonDetaljertTilgang(request.getIdent()); + } +} diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnTilgangController.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnOrganisasjonTilgangController.java similarity index 89% rename from apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnTilgangController.java rename to apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnOrganisasjonTilgangController.java index 140f414c701..484700ce2d9 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnTilgangController.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/provider/AltinnOrganisasjonTilgangController.java @@ -4,7 +4,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.altinn3tilgangservice.domain.OrganisasjonResponse; -import no.nav.testnav.altinn3tilgangservice.service.AltinnTilgangService; +import no.nav.testnav.altinn3tilgangservice.service.AltinnOrganisasjonTilgangService; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -20,9 +20,9 @@ @RestController @RequestMapping("/api/v1/organisasjoner") @RequiredArgsConstructor -public class AltinnTilgangController { +public class AltinnOrganisasjonTilgangController { - private final AltinnTilgangService altinnTilgangService; + private final AltinnOrganisasjonTilgangService altinnTilgangService; @GetMapping @Operation(description = "Henter alle organisasjoner med Altinn-tilgang") diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnBrukerTilgangService.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnBrukerTilgangService.java new file mode 100644 index 00000000000..581ba8f8ff5 --- /dev/null +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnBrukerTilgangService.java @@ -0,0 +1,112 @@ +package no.nav.testnav.altinn3tilgangservice.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.AltinnConsumer; +import no.nav.testnav.altinn3tilgangservice.consumer.altinn.dto.AuthorizedPartyDTO; +import no.nav.testnav.altinn3tilgangservice.domain.Organisasjon; +import no.nav.testnav.libs.dto.altinn3.v1.OrganisasjonDTO; +import no.nav.testnav.libs.dto.altinn3.v1.PersonDTO; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; + +import java.util.List; + +import static org.apache.commons.lang3.BooleanUtils.isFalse; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AltinnBrukerTilgangService { + + private static final String DOLLY_RESOURCE = "nav_dolly_tilgang-samarbeidspartnere"; + private final AltinnConsumer altinnConsumer; + + public Flux getPersonOrganisasjonTilgang(String ident) { + + return Flux.zip( + altinnConsumer.getAuthorizedParties(ident), + altinnConsumer.getOrganisasjoner().collectList()) + .flatMap(this::getOrganisasjon); + } + + private Mono getOrganisasjon(Tuple2> organisasjoner) { + + return Mono.just(organisasjoner.getT1()) + .filter(party -> party.getAuthorizedResources().contains(DOLLY_RESOURCE)) + .filter(party -> organisasjoner.getT2().stream() + .anyMatch(organisasjon -> organisasjon.getOrganisasjonsnummer().equals(party.getOrganizationNumber()))) + .map(part -> OrganisasjonDTO.builder() + .navn(part.getName()) + .organisasjonsnummer(part.getOrganizationNumber()) + .organisasjonsform(part.getUnitType()) + .build()); + } + + public Mono getPersonOrganisasjonDetaljertTilgang(String ident) { + + return Mono.zip( + altinnConsumer.getAuthorizedParties(ident).collectList(), + altinnConsumer.getOrganisasjoner().collectList()) + .flatMapMany(this::getTilpassetOrganisasjon) + .collectList() + .map(organisasjoner -> PersonDTO.builder() + .ident(ident) + .organisasjoner(organisasjoner) + .build()); + } + + private Flux getTilpassetOrganisasjon(Tuple2, List> organisasjoner) { + + return Flux.fromIterable(organisasjoner.getT1()) + .filter(party -> isNotBlank(party.getOrganizationNumber()) && isNotBlank(party.getName())) + .filter(party -> isFalse(party.getIsDeleted())) + .map(party -> PersonDTO.OrganisasjonDTO.builder() + .navn(party.getName()) + .organisasjonsnummer(party.getOrganizationNumber()) + .organisasjonsform(party.getUnitType()) + .hasAltinnDollyTilgang(hasAltinnDollyTilgang(party)) + .hasDollyOrganisasjonTilgang(hasDollyOrganisasjonTilgang(organisasjoner.getT2(), party)) + .melding(getMelding(party.getName(), party.getOrganizationNumber(), + hasAltinnDollyTilgang(party), hasDollyOrganisasjonTilgang(organisasjoner.getT2(), party))) + .build()); + } + + private static boolean hasAltinnDollyTilgang(AuthorizedPartyDTO authorizedParty) { + + return authorizedParty.getAuthorizedResources().contains(DOLLY_RESOURCE); + } + + private static boolean hasDollyOrganisasjonTilgang(List organisasjoner, AuthorizedPartyDTO party) { + + return organisasjoner.stream() + .anyMatch(organisasjon -> organisasjon.getOrganisasjonsnummer().equals(party.getOrganizationNumber())); + } + + private static String getMelding(String orgnavn, String orgnummer, boolean hasAltinnDollyTilgang, boolean hasDollyOrganisasjonTilgang) { + + return new StringBuilder() + .append(!hasAltinnDollyTilgang ? + "Du mangler tilgang i Altinn på følgende tjenste: " + + "\"Tilgang til NAVs Dolly for samarbeidspartnere\" " + + "for organisasjon %s (med orgnummer %s)%n".formatted(orgnavn, orgnummer) : "") + .append(!hasAltinnDollyTilgang && !hasDollyOrganisasjonTilgang ? + " og %n" : "") + .append(!hasDollyOrganisasjonTilgang ? + "Organisasjon %s (med orgnummer %s) " .formatted(orgnavn, orgnummer) + + "mangler tilgang på Dolly syntetiske testdata selvbetjening%n" : "") + .append(!hasAltinnDollyTilgang || !hasDollyOrganisasjonTilgang ? + "Hvis du har til hensikt å bruke Dolly til å generere testdata, gjør følgende:%n" : "") + .append(!hasAltinnDollyTilgang ? + "- Ta kontakt med Altinn-ansvarlig i %s (med orgnummer %s) ".formatted(orgnavn, orgnummer) + + "og spør om vedkommene kan gi deg tilgang til tjenesten: " + + "\"Tilgang til NAVs Dolly for samarbeidspartnere\"%n" : "") + .append(!hasDollyOrganisasjonTilgang ? + "- Ta kontakt med NAV ved Anders Marstrander epost: anders.marstrander@nav.no, og spør om " + + "organisasjon med orgnr %s kan gis tilgang til Dolly syntetiske testdata selvbetjening%n".formatted(orgnummer) : "") + .toString(); + } +} diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnTilgangService.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnOrganisasjonTilgangService.java similarity index 98% rename from apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnTilgangService.java rename to apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnOrganisasjonTilgangService.java index d4151a28ecf..6dc40eb83fd 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnTilgangService.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/AltinnOrganisasjonTilgangService.java @@ -17,7 +17,7 @@ @Service @RequiredArgsConstructor -public class AltinnTilgangService { +public class AltinnOrganisasjonTilgangService { private static final String ORGANISASJON_TILGANG = "tilgang"; private final AltinnConsumer altinnConsumer; diff --git a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/MiljoerOversiktService.java b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/MiljoerOversiktService.java index 81202173881..3774737e83f 100644 --- a/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/MiljoerOversiktService.java +++ b/apps/altinn3-tilgang-service/src/main/java/no/nav/testnav/altinn3tilgangservice/service/MiljoerOversiktService.java @@ -4,7 +4,9 @@ import no.nav.testnav.altinn3tilgangservice.consumer.altinn.AltinnConsumer; import no.nav.testnav.altinn3tilgangservice.database.entity.OrganisasjonTilgang; import no.nav.testnav.altinn3tilgangservice.database.repository.OrganisasjonTilgangRepository; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; import reactor.core.publisher.Mono; import static org.apache.commons.lang3.BooleanUtils.isTrue; @@ -47,17 +49,13 @@ public Mono updateMiljoe(String orgnummer, String miljoe) { organisasjon.setMiljoe(miljoe); return organisasjonTilgangRepository.save(organisasjon); }) : - organisasjonTilgangRepository.save(OrganisasjonTilgang.builder() - .organisasjonNummer(orgnummer) - .miljoe(miljoe) - .build())); + + throwError(orgnummer)); } private static Mono throwError(String orgnummer) { - return Mono.just(OrganisasjonTilgang.builder() - .organisasjonNummer(orgnummer) - .feilmelding("404 Not found: Organisasjonsnummer %s ble ikke funnet".formatted(orgnummer)) - .build()); + throw new ResponseStatusException(HttpStatus.NOT_FOUND, + "Organisasjonsnummer %s ble ikke funnet".formatted(orgnummer)); } } diff --git a/apps/altinn3-tilgang-service/src/main/resources/application-local.yml b/apps/altinn3-tilgang-service/src/main/resources/application-local.yml index 7916eb7f7fa..b53b18bab13 100644 --- a/apps/altinn3-tilgang-service/src/main/resources/application-local.yml +++ b/apps/altinn3-tilgang-service/src/main/resources/application-local.yml @@ -1,9 +1,9 @@ -ALTINN_URL: https://tt02.altinn.no +ALTINN_URL: https://platform.tt02.altinn.no AZURE_APP_CLIENT_ID: ${sm://azure-app-client-id} AZURE_APP_CLIENT_SECRET: ${sm://azure-app-client-secret} -MASKINPORTEN_CLIENT_ID: dummy +MASKINPORTEN_CLIENT_ID: ef2960de-7fa6-4396-80a5-2eca00e4af28 MASKINPORTEN_CLIENT_JWK: dummy -MASKINPORTEN_SCOPES: dummy +MASKINPORTEN_SCOPES: altinn:resourceregistry/accesslist.read altinn:resourceregistry/accesslist.write altinn:accessmanagement/authorizedparties.resourceowner MASKINPORTEN_WELL_KNOWN_URL: https://test.maskinporten.no/.well-known/oauth-authorization-server TOKEN_X_ISSUER: dummy diff --git a/apps/altinn3-tilgang-service/src/main/resources/application.yml b/apps/altinn3-tilgang-service/src/main/resources/application.yml index 70a799743f3..16f513682d3 100644 --- a/apps/altinn3-tilgang-service/src/main/resources/application.yml +++ b/apps/altinn3-tilgang-service/src/main/resources/application.yml @@ -52,4 +52,5 @@ server: encoding: charset: UTF-8 error: - include-message: always \ No newline at end of file + include-message: always + include-stacktrace: never \ No newline at end of file diff --git a/apps/dolly-frontend/config.idporten.yml b/apps/dolly-frontend/config.idporten.yml index aed20782252..64f2ba53138 100644 --- a/apps/dolly-frontend/config.idporten.yml +++ b/apps/dolly-frontend/config.idporten.yml @@ -17,7 +17,7 @@ spec: tenant: nav.no replicas: min: 1 - max: 2 + max: 1 port: 8080 ingresses: - "https://dolly-idporten.ekstern.dev.nav.no" @@ -42,11 +42,8 @@ spec: - application: testnav-organisasjon-faste-data-service - application: testnav-organisasjon-forvalter - application: testnav-organisasjon-service - - application: testnav-organisasjon-tilgang-service - application: testnav-pdl-forvalter - application: testnav-person-faste-data-service - - application: testnav-person-organisasjon-tilgang-service - - application: testnav-person-organisasjon-tilgang-service-dev - application: testnav-person-search-service - application: testnav-person-service - application: testnav-skattekort-service diff --git a/apps/dolly-frontend/config.test.yml b/apps/dolly-frontend/config.test.yml index 260eafa9a3e..9494c59a1f0 100644 --- a/apps/dolly-frontend/config.test.yml +++ b/apps/dolly-frontend/config.test.yml @@ -46,10 +46,8 @@ spec: - application: testnav-organisasjon-faste-data-service - application: testnav-organisasjon-forvalter - application: testnav-organisasjon-service - - application: testnav-organisasjon-tilgang-service - application: testnav-pdl-forvalter-dev - application: testnav-person-faste-data-service - - application: testnav-person-organisasjon-tilgang-service-dev - application: testnav-person-search-service - application: testnav-person-service - application: testnav-sykemelding-api-dev diff --git a/apps/dolly-frontend/config.unstable.yml b/apps/dolly-frontend/config.unstable.yml index 7a6b3df1dba..19b2a8aa5cc 100644 --- a/apps/dolly-frontend/config.unstable.yml +++ b/apps/dolly-frontend/config.unstable.yml @@ -44,9 +44,7 @@ spec: - application: testnav-organisasjon-faste-data-service - application: testnav-organisasjon-forvalter - application: testnav-organisasjon-service - - application: testnav-organisasjon-tilgang-service - application: testnav-pdl-forvalter-dev - - application: testnav-person-organisasjon-tilgang-service-dev - application: testnav-person-search-service - application: testnav-person-service - application: testnav-tenor-search-service diff --git a/apps/dolly-frontend/config.yml b/apps/dolly-frontend/config.yml index f0429be6a19..2faeb17bc3a 100644 --- a/apps/dolly-frontend/config.yml +++ b/apps/dolly-frontend/config.yml @@ -51,10 +51,8 @@ spec: - application: testnav-organisasjon-faste-data-service - application: testnav-organisasjon-forvalter - application: testnav-organisasjon-service - - application: testnav-organisasjon-tilgang-service - application: testnav-pdl-forvalter - application: testnav-person-faste-data-service - - application: testnav-person-organisasjon-tilgang-service - application: testnav-person-search-service - application: testnav-person-service - application: testnav-skattekort-service diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/DollyFrontendApplicationStarter.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/DollyFrontendApplicationStarter.java index 2df2a6e90d0..d6bcdebdc7b 100644 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/DollyFrontendApplicationStarter.java +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/DollyFrontendApplicationStarter.java @@ -53,7 +53,6 @@ public class DollyFrontendApplicationStarter { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder .routes() .route(createRoute(consumers.getTestnavKontoregisterPersonProxy())) @@ -85,7 +84,6 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { .route(createRoute(consumers.getTestnavSigrunstubProxy())) .route(createRoute(consumers.getTestnavPdlForvalter(), "testnav-pdl-forvalter")) .route(createRoute(consumers.getTestnavPersonSearchService())) - .route(createRoute(consumers.getTestnavPersonOrganisasjonTilgangService(), "testnav-person-organisasjon-tilgang-service")) .route(createRoute(consumers.getTestnavSkjermingsregisterProxy())) .route(createRoute(consumers.getTestnavDokarkivProxy())) .route(createRoute(consumers.getTestnavArbeidsplassenCVProxy())) diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/config/Consumers.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/config/Consumers.java index c29e9a91726..86a118efec9 100644 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/config/Consumers.java +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/config/Consumers.java @@ -51,7 +51,6 @@ public class Consumers { private ServerProperties testnavOrganisasjonService; private ServerProperties testnavPdlForvalter; private ServerProperties testnavPensjonTestdataFacadeProxy; - private ServerProperties testnavPersonOrganisasjonTilgangService; private ServerProperties testnavPersonSearchService; private ServerProperties testnavPersonService; private ServerProperties testnavSigrunstubProxy; diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/Altinn3PersonOrganisasjonTilgangConsumer.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/Altinn3PersonOrganisasjonTilgangConsumer.java new file mode 100644 index 00000000000..50a38ef30f7 --- /dev/null +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/Altinn3PersonOrganisasjonTilgangConsumer.java @@ -0,0 +1,66 @@ +package no.nav.dolly.web.consumers; + +import lombok.extern.slf4j.Slf4j; +import no.nav.dolly.web.config.Consumers; +import no.nav.dolly.web.consumers.command.PostPersonOrganisasjonTilgangCommand; +import no.nav.dolly.web.service.AccessService; +import no.nav.testnav.libs.dto.altinn3.v1.OrganisasjonDTO; +import no.nav.testnav.libs.reactivesecurity.action.GetAuthenticatedUserId; +import no.nav.testnav.libs.securitycore.domain.ServerProperties; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Slf4j +@Component +public class Altinn3PersonOrganisasjonTilgangConsumer { + + private final WebClient webClient; + private final ServerProperties serverProperties; + private final AccessService accessService; + private final GetAuthenticatedUserId getAuthenticatedUserId; + + public Altinn3PersonOrganisasjonTilgangConsumer( + Consumers consumers, + AccessService accessService, + WebClient.Builder webClientBuilder, + GetAuthenticatedUserId getAuthenticatedUserId) { + + this.accessService = accessService; + serverProperties = consumers.getTestnavAltinn3TilgangService(); + + this.webClient = webClientBuilder + .baseUrl(serverProperties.getUrl()) + .build(); + this.getAuthenticatedUserId = getAuthenticatedUserId; + } + + public Mono hasAccess(String organisasjonsnummer, ServerWebExchange exchange) { + + return getAuthenticatedUserId + .call() + .flatMap(userId -> accessService.getAccessToken(serverProperties, exchange) + .flatMapMany(accessToken -> new PostPersonOrganisasjonTilgangCommand(webClient, userId, accessToken).call()) + .filter(organisasjonDTO -> organisasjonDTO.getOrganisasjonsnummer().equals(organisasjonsnummer)) + .onErrorResume( + WebClientResponseException.class::isInstance, + throwable -> { + log.warn("Person har ikke tilgang til organisasjon {}.", organisasjonsnummer); + return Mono.empty(); + }) + .reduce(Boolean.FALSE, (acc, value) -> Boolean.TRUE)); + } + + public Flux getOrganisasjoner(ServerWebExchange exchange) { + + return getAuthenticatedUserId + .call() + .flatMapMany(userId -> + accessService.getAccessToken(serverProperties, exchange) + .flatMapMany(accessToken -> new PostPersonOrganisasjonTilgangCommand(webClient, userId, accessToken).call())); + } +} + diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/PersonOrganisasjonTilgangConsumer.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/PersonOrganisasjonTilgangConsumer.java deleted file mode 100644 index cec7481322b..00000000000 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/PersonOrganisasjonTilgangConsumer.java +++ /dev/null @@ -1,62 +0,0 @@ -package no.nav.dolly.web.consumers; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import no.nav.dolly.web.config.Consumers; -import no.nav.dolly.web.consumers.command.GetPersonOrganisasjonTilgangCommand; -import no.nav.dolly.web.service.AccessService; -import no.nav.testnav.libs.securitycore.domain.ServerProperties; -import org.springframework.http.MediaType; -import org.springframework.http.codec.json.Jackson2JsonDecoder; -import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.ExchangeStrategies; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - -@Slf4j -@Component -public class PersonOrganisasjonTilgangConsumer { - private final WebClient webClient; - private final ServerProperties serverProperties; - - private final AccessService accessService; - - public PersonOrganisasjonTilgangConsumer( - Consumers consumers, - AccessService accessService, - ObjectMapper objectMapper, - WebClient.Builder webClientBuilder) { - - this.accessService = accessService; - serverProperties = consumers.getTestnavPersonOrganisasjonTilgangService(); - ExchangeStrategies jacksonStrategy = ExchangeStrategies.builder() - .codecs(config -> { - config.defaultCodecs() - .jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON)); - config.defaultCodecs() - .jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON)); - }).build(); - - this.webClient = webClientBuilder - .exchangeStrategies(jacksonStrategy) - .baseUrl(serverProperties.getUrl()) - .build(); - } - - public Mono hasAccess(String organisasjonsnummer, ServerWebExchange exchange) { - return accessService.getAccessToken(serverProperties, exchange) - .flatMap(accessToken -> new GetPersonOrganisasjonTilgangCommand(webClient, accessToken, organisasjonsnummer).call()) - .onErrorResume( - WebClientResponseException.class::isInstance, - throwable -> { - log.warn("Person har ikke tilgang til organisasjon {}.", organisasjonsnummer); - return Mono.empty(); - }) - .flatMap(value -> Mono.just(true)) - .switchIfEmpty(Mono.just(false)); - } -} - diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/GetPersonOrganisasjonTilgangCommand.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/PostPersonOrganisasjonTilgangCommand.java similarity index 59% rename from apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/GetPersonOrganisasjonTilgangCommand.java rename to apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/PostPersonOrganisasjonTilgangCommand.java index 3bdfb86c837..7b7e5ece269 100644 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/GetPersonOrganisasjonTilgangCommand.java +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/command/PostPersonOrganisasjonTilgangCommand.java @@ -2,11 +2,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import no.nav.dolly.web.consumers.dto.OrganisasjonDTO; +import no.nav.dolly.web.consumers.dto.AltinnBrukerRequest; +import no.nav.testnav.libs.dto.altinn3.v1.OrganisasjonDTO; import no.nav.testnav.libs.reactivecore.utils.WebClientFilter; import org.springframework.http.HttpHeaders; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; import reactor.util.retry.Retry; import java.time.Duration; @@ -14,21 +15,24 @@ @Slf4j @RequiredArgsConstructor -public class GetPersonOrganisasjonTilgangCommand implements Callable> { +public class PostPersonOrganisasjonTilgangCommand implements Callable> { + private final WebClient webClient; + private final String ident; private final String token; - private final String organisasjonsnummer; @Override - public Mono call() { + public Flux call() { + return webClient - .get() - .uri(builder -> builder.path("/api/v1/person/organisasjoner/{organisasjonsnummer}").build(organisasjonsnummer)) + .post() + .uri(builder -> builder.path("/api/v1/brukertilgang").build()) .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) + .bodyValue(new AltinnBrukerRequest(ident)) .retrieve() - .bodyToMono(OrganisasjonDTO.class) - .doOnError(error -> log.error("Feilet å hente organisasjon, status: {}, feilmelding: ", - WebClientFilter.getMessage(error), + .bodyToFlux(OrganisasjonDTO.class) + .doOnError(error -> log.error("Feilet å hente organisasjon, status: {}, feilmelding: {}", + WebClientFilter.getStatus(error), WebClientFilter.getMessage(error), error)) .retryWhen(Retry.backoff(3, Duration.ofSeconds(5)) diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/AltinnBrukerRequest.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/AltinnBrukerRequest.java new file mode 100644 index 00000000000..91dbb8b2a03 --- /dev/null +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/AltinnBrukerRequest.java @@ -0,0 +1,11 @@ +package no.nav.dolly.web.consumers.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class AltinnBrukerRequest { + + private String ident; +} diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/OrganisasjonDTO.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/OrganisasjonDTO.java deleted file mode 100644 index fdd85cd2839..00000000000 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/consumers/dto/OrganisasjonDTO.java +++ /dev/null @@ -1,12 +0,0 @@ -package no.nav.dolly.web.consumers.dto; - -import java.time.LocalDateTime; - -public record OrganisasjonDTO( - String navn, - String orgnisasjonsnummer, - String orgnisasjonsfrom, - LocalDateTime gyldigTil -) { -} - diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/BrukerTilgangController.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/BrukerTilgangController.java new file mode 100644 index 00000000000..829b41b4fab --- /dev/null +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/BrukerTilgangController.java @@ -0,0 +1,29 @@ +package no.nav.dolly.web.provider.web; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.dolly.web.consumers.Altinn3PersonOrganisasjonTilgangConsumer; +import no.nav.testnav.libs.dto.altinn3.v1.OrganisasjonDTO; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/altinn") +@RequiredArgsConstructor +public class BrukerTilgangController { + + private final Altinn3PersonOrganisasjonTilgangConsumer altinn3PersonOrganisasjonTilgangConsumer; + + @GetMapping("/organisasjoner") + public Mono> getOrganisasjoner(ServerWebExchange exchange) { + + return altinn3PersonOrganisasjonTilgangConsumer.getOrganisasjoner(exchange) + .collectList(); + } +} diff --git a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/SessionController.java b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/SessionController.java index 0652790796c..f6222576b25 100644 --- a/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/SessionController.java +++ b/apps/dolly-frontend/src/main/java/no/nav/dolly/web/provider/web/SessionController.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import no.nav.dolly.web.consumers.PersonOrganisasjonTilgangConsumer; +import no.nav.dolly.web.consumers.Altinn3PersonOrganisasjonTilgangConsumer; import no.nav.dolly.web.service.BrukerService; import no.nav.testnav.libs.securitycore.config.UserSessionConstant; import org.springframework.http.HttpStatus; @@ -24,7 +24,7 @@ public class SessionController { private final BrukerService brukerService; - private final PersonOrganisasjonTilgangConsumer personOrganisasjonTilgangConsumer; + private final Altinn3PersonOrganisasjonTilgangConsumer altinn3PersonOrganisasjonTilgangConsumer; /** * Ping endepunkt for aa holde sessionen aapen. @@ -44,7 +44,8 @@ public Mono> delete(ServerWebExchange exchange) { @PutMapping("/user") public Mono> addUserToSession(@RequestParam String organisasjonsnummer, ServerWebExchange exchange) { - return personOrganisasjonTilgangConsumer + + return altinn3PersonOrganisasjonTilgangConsumer .hasAccess(organisasjonsnummer, exchange) .doOnError(e -> log.error("Feil ved sjekk av tilgang til org {}", organisasjonsnummer, e)) .flatMap(hasAccess -> { diff --git a/apps/dolly-frontend/src/main/js/playwright/mocks/BasicMocks.tsx b/apps/dolly-frontend/src/main/js/playwright/mocks/BasicMocks.tsx index 7518f066e45..ce86904ffba 100644 --- a/apps/dolly-frontend/src/main/js/playwright/mocks/BasicMocks.tsx +++ b/apps/dolly-frontend/src/main/js/playwright/mocks/BasicMocks.tsx @@ -23,8 +23,7 @@ export const personOrgTilgangMock = [ { navn: 'testytest', organisasjonsnummer: '12345678', - organisasjonsfrom: 'BEDR', - gyldigTil: '2100-10-10T10:10:10.100Z', + organisasjonsform: 'BEDR', }, ] diff --git a/apps/dolly-frontend/src/main/js/playwright/tests/Bankid.spec.ts b/apps/dolly-frontend/src/main/js/playwright/tests/Bankid.spec.ts index 10d86341dca..f832c6a7883 100644 --- a/apps/dolly-frontend/src/main/js/playwright/tests/Bankid.spec.ts +++ b/apps/dolly-frontend/src/main/js/playwright/tests/Bankid.spec.ts @@ -11,7 +11,7 @@ test.describe('Bankid testing', () => { headers: { 'content-type': 'application/json' }, }) }) - await page.route(new RegExp(/testnav-person-organisasjon-tilgang-service/), async (route) => { + await page.route(new RegExp(/altinn\/organisasjoner/), async (route) => { await route.fulfill({ status: 200, body: JSON.stringify(personOrgTilgangMock), diff --git a/apps/dolly-frontend/src/main/js/proxy-routes.json b/apps/dolly-frontend/src/main/js/proxy-routes.json index 2b7e1cf21bb..ea55ec091c7 100644 --- a/apps/dolly-frontend/src/main/js/proxy-routes.json +++ b/apps/dolly-frontend/src/main/js/proxy-routes.json @@ -29,6 +29,10 @@ "/session/user": { "changeOrigin": false }, + "/altinn/organisasjoner": { + "target": "http://localhost:8020", + "secure": false + }, "/testnav-organisasjon-faste-data-service/api": { "changeOrigin": true }, @@ -113,9 +117,6 @@ "/testnav-person-search-service/api": { "changeOrigin": true }, - "/testnav-person-organisasjon-tilgang-service/api": { - "changeOrigin": true - }, "/testnav-pdl-forvalter/api": { "changeOrigin": true }, diff --git a/apps/dolly-frontend/src/main/js/src/service/services/personOrganisasjonTilgang/PersonOrganisasjonTilgangService.tsx b/apps/dolly-frontend/src/main/js/src/service/services/personOrganisasjonTilgang/PersonOrganisasjonTilgangService.tsx index c67a1f009c7..e079958b6b3 100644 --- a/apps/dolly-frontend/src/main/js/src/service/services/personOrganisasjonTilgang/PersonOrganisasjonTilgangService.tsx +++ b/apps/dolly-frontend/src/main/js/src/service/services/personOrganisasjonTilgang/PersonOrganisasjonTilgangService.tsx @@ -1,8 +1,7 @@ import Request from '@/service/services/Request' import logoutBruker from '@/components/utlogging/logoutBruker' -const personOrgTilgangServiceUrl = - '/testnav-person-organisasjon-tilgang-service/api/v1/person/organisasjoner' +const personOrgTilgangServiceUrl = '/altinn/organisasjoner' export default { getOrganisasjoner() { @@ -15,5 +14,5 @@ export default { .then((response) => { return response }) - }, + } } diff --git a/apps/dolly-frontend/src/main/js/src/utils/hooks/useOrganisasjonTilgang.tsx b/apps/dolly-frontend/src/main/js/src/utils/hooks/useOrganisasjonTilgang.tsx index 98f8d78bfb6..47969f3c8eb 100644 --- a/apps/dolly-frontend/src/main/js/src/utils/hooks/useOrganisasjonTilgang.tsx +++ b/apps/dolly-frontend/src/main/js/src/utils/hooks/useOrganisasjonTilgang.tsx @@ -3,7 +3,7 @@ import { fetcher } from '@/api' import { useBrukerProfil } from '@/utils/hooks/useBruker' const getOrganisasjonMiljoeUrl = (orgnummer: string) => - `/testnav-altinn3-tilgang-service/api/v1/miljoer/organisasjon/orgnummer?orgnummer=${orgnummer}` + `/testnav-altinn3-tilgang-service/api/v1/miljoer/organisasjon/${orgnummer}` const organisasjonTilgangUrl = `/testnav-altinn3-tilgang-service/api/v1/organisasjoner` diff --git a/apps/dolly-frontend/src/main/resources/application-local.yml b/apps/dolly-frontend/src/main/resources/application-local.yml index be0739b2cf1..48b781833ba 100644 --- a/apps/dolly-frontend/src/main/resources/application-local.yml +++ b/apps/dolly-frontend/src/main/resources/application-local.yml @@ -41,9 +41,6 @@ consumers: testnav-varslinger-service: name: testnav-varslinger-service-dev url: http://testnav-varslinger-service-dev.intern.dev.nav.no - testnav-person-organisasjon-tilgang-service: - name: testnav-person-organisasjon-tilgang-service-dev - url: https://testnav-person-organisasjon-tilgang-service.intern.dev.nav.no oppsummeringsdokument-service: url: https://testnav-oppsummeringsdokument-service.intern.dev.nav.no testnav-bruker-service: diff --git a/apps/dolly-frontend/src/main/resources/application.yml b/apps/dolly-frontend/src/main/resources/application.yml index 9653c61db58..1731e1a42b7 100644 --- a/apps/dolly-frontend/src/main/resources/application.yml +++ b/apps/dolly-frontend/src/main/resources/application.yml @@ -155,11 +155,6 @@ consumers: namespace: dolly name: testnorge-tilbakemelding-api url: http://testnorge-tilbakemelding-api.dolly.svc.cluster.local - testnav-person-organisasjon-tilgang-service: - cluster: dev-gcp - namespace: dolly - name: testnav-person-organisasjon-tilgang-service - url: http://testnav-person-organisasjon-tilgang-service.dolly.svc.cluster.local testnav-bruker-service: cluster: dev-gcp namespace: dolly diff --git a/apps/dolly-frontend/src/main/resources/logback-spring.xml b/apps/dolly-frontend/src/main/resources/logback-spring.xml index 966dbc796b2..b80ca79b071 100644 --- a/apps/dolly-frontend/src/main/resources/logback-spring.xml +++ b/apps/dolly-frontend/src/main/resources/logback-spring.xml @@ -3,17 +3,9 @@ - - true - 10280 - 20 - ^sun\.reflect\..*\.invoke - ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke - java\.util\.concurrent\..* - org\.apache\.catalina\..* - org\.apache\.coyote\..* - org\.apache\.tomcat\..* - + -1 + true + - diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/OrganisasjonDTO.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/OrganisasjonDTO.java new file mode 100644 index 00000000000..725ba98dfb4 --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/OrganisasjonDTO.java @@ -0,0 +1,17 @@ +package no.nav.testnav.libs.dto.altinn3.v1; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrganisasjonDTO { + + private String navn; + private String organisasjonsnummer; + private String organisasjonsform; +} \ No newline at end of file diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/PersonDTO.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/PersonDTO.java new file mode 100644 index 00000000000..c5a91530fda --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/altinn3/v1/PersonDTO.java @@ -0,0 +1,32 @@ +package no.nav.testnav.libs.dto.altinn3.v1; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PersonDTO { + + private String ident; + private List organisasjoner; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class OrganisasjonDTO { + + private String navn; + private String organisasjonsnummer; + private String organisasjonsform; + private Boolean hasAltinnDollyTilgang; + private Boolean hasDollyOrganisasjonTilgang; + private String melding; + } +} diff --git a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedResourceServerType.java b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedResourceServerType.java index a3596f957d2..b6b72f5802d 100644 --- a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedResourceServerType.java +++ b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedResourceServerType.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import no.nav.testnav.libs.securitycore.domain.ResourceServerType; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; @@ -30,11 +31,18 @@ private Optional getResourceTypeForm(JwtAuthenticationToken @Override public Mono call() { + return getJwtAuthenticationToken() .onErrorResume(JwtResolverException.class, throwable -> Mono.empty()) - .flatMap(token -> getResourceTypeForm(token) - .map(Mono::just) - .orElseGet(Mono::empty) - ); + .flatMap(authentication -> { + if (authentication instanceof JwtAuthenticationToken jwtAuthenticationTokentoken) { + return getResourceTypeForm(jwtAuthenticationTokentoken) + .map(Mono::just) + .orElseGet(Mono::empty); + } else if (authentication instanceof OAuth2AuthenticationToken) { + return Mono.just(ResourceServerType.TOKEN_X); + } + return Mono.empty(); + }); } } diff --git a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedToken.java b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedToken.java index bc5f09c71f3..0a5d4e957fd 100644 --- a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedToken.java +++ b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedToken.java @@ -1,11 +1,18 @@ package no.nav.testnav.libs.reactivesecurity.action; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.libs.securitycore.domain.Token; +import org.springframework.http.HttpStatus; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Component; +import org.springframework.web.server.ResponseStatusException; import reactor.core.publisher.Mono; +import java.time.Instant; import java.util.concurrent.Callable; @Component @@ -21,13 +28,21 @@ public Mono call() { .call() .flatMap(serverType -> switch (serverType) { case TOKEN_X -> getJwtAuthenticationToken() - .map(jwt -> Token.builder() - .clientCredentials(false) - .userId(jwt.getTokenAttributes().get("pid").toString()) - .accessTokenValue(jwt.getToken().getTokenValue()) - .expiresAt(jwt.getToken().getExpiresAt()) - .build()); + .map(OAuth2AuthenticationToken.class::cast) + .handle((oauth2, sink) -> { + try { + sink.next(Token.builder() + .clientCredentials(false) + .userId(oauth2.getPrincipal().getAttributes().get("pid").toString()) + .accessTokenValue(new ObjectMapper().writeValueAsString(oauth2)) + .expiresAt((Instant) oauth2.getPrincipal().getAttributes().get("exp")) + .build()); + } catch (JsonProcessingException e) { + sink.error(new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Feilet å konvertere token to string", e)); + } + }); case AZURE_AD -> getJwtAuthenticationToken() + .map(JwtAuthenticationToken.class::cast) .map(jwt -> Token.builder() .clientCredentials(jwt.getTokenAttributes().get("oid").equals(jwt.getTokenAttributes().get("sub"))) .userId(jwt.getTokenAttributes().get("oid").toString()) diff --git a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedUserId.java b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedUserId.java index 63193f44bcc..b0636ee9c7d 100644 --- a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedUserId.java +++ b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/GetAuthenticatedUserId.java @@ -1,11 +1,15 @@ package no.nav.testnav.libs.reactivesecurity.action; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; import java.util.concurrent.Callable; +@Slf4j @Component @RequiredArgsConstructor public class GetAuthenticatedUserId extends JwtResolver implements Callable> { @@ -23,6 +27,20 @@ public Mono call() { } private Mono getTokenAttribute(String attribute) { - return getJwtAuthenticationToken().map(value -> value.getTokenAttributes().get(attribute).toString()); + + return getJwtAuthenticationToken() + .map(authentication -> + + switch (authentication) { + + case JwtAuthenticationToken jwtAuthenticationToken -> + jwtAuthenticationToken.getTokenAttributes().get(attribute).toString(); + + case OAuth2AuthenticationToken oauth2AuthenticationToken -> + oauth2AuthenticationToken.getPrincipal().getAttributes().get("pid").toString(); + + default -> ""; + } + ); } } diff --git a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/JwtResolver.java b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/JwtResolver.java index 6f360743c2f..5b19c554aa1 100644 --- a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/JwtResolver.java +++ b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/JwtResolver.java @@ -1,34 +1,19 @@ package no.nav.testnav.libs.reactivesecurity.action; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import reactor.core.publisher.Mono; -import java.time.Instant; -import java.time.ZonedDateTime; - @Slf4j -@SuppressWarnings("java:S1610") abstract class JwtResolver { - Mono getJwtAuthenticationToken() { + Mono getJwtAuthenticationToken() { return ReactiveSecurityContextHolder .getContext() .switchIfEmpty(Mono.error(new JwtResolverException("ReactiveSecurityContext is empty"))) - .map(SecurityContext::getAuthentication) - .map(JwtAuthenticationToken.class::cast) - .doOnError(throwable -> log.warn("Klarte ikke hente Jwt Auth Token", throwable)) - .doOnSuccess(jwtAuthenticationToken -> { - Jwt credentials = (Jwt) jwtAuthenticationToken.getCredentials(); - Instant expiresAt = credentials.getExpiresAt(); - if (expiresAt == null || expiresAt.isBefore(ZonedDateTime.now().toInstant().plusSeconds(120))) { - throw new CredentialsExpiredException("Jwt er utløpt eller utløper innen kort tid"); - } - }); + .doOnNext(context -> log.info("JwtResolver context.authentication {} {}", context.getAuthentication().getClass().getCanonicalName(), context.getAuthentication())) + .map(SecurityContext::getAuthentication); } - } diff --git a/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/Oauth2Resolver.java b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/Oauth2Resolver.java new file mode 100644 index 00000000000..68dac390a55 --- /dev/null +++ b/libs/reactive-security/src/main/java/no/nav/testnav/libs/reactivesecurity/action/Oauth2Resolver.java @@ -0,0 +1,35 @@ +package no.nav.testnav.libs.reactivesecurity.action; + +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.CredentialsExpiredException; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.oauth2.jwt.Jwt; +import reactor.core.publisher.Mono; + +import java.time.Instant; +import java.time.ZonedDateTime; + +@Slf4j +@UtilityClass +public class Oauth2Resolver { + + public static Mono getOauth2AuthenticationToken() { + return ReactiveSecurityContextHolder + .getContext() + .switchIfEmpty(Mono.error(new JwtResolverException("ReactiveSecurityContext is empty"))) + .doOnNext(context -> log.info("Oauth2Resolver context.authentication {} {}", context.getAuthentication().getClass().getCanonicalName(), context.getAuthentication())) + .map(SecurityContext::getAuthentication) + .map(OAuth2AuthenticationToken.class::cast) + .doOnError(throwable -> log.warn("Klarte ikke hente Jwt Auth Token", throwable)) + .doOnSuccess(jwtAuthenticationToken -> { + Jwt credentials = (Jwt) jwtAuthenticationToken.getCredentials(); + Instant expiresAt = credentials.getExpiresAt(); + if (expiresAt == null || expiresAt.isBefore(ZonedDateTime.now().toInstant().plusSeconds(120))) { + throw new CredentialsExpiredException("Jwt er utløpt eller utløper innen kort tid"); + } + }); + } +}