From cfec4bd694cb4bf9b97b2ea9ebe65d664e692291 Mon Sep 17 00:00:00 2001 From: Giulia Tremolada <124147597+giulia-tremolada@users.noreply.github.com> Date: Thu, 9 May 2024 16:44:42 +0200 Subject: [PATCH] [SELC-4805] refactor: remove UserController, TokenController, ExchangeTokenService and related methods (#432) --- app/src/main/resources/swagger/api-docs.json | 934 +++-------------- .../web/config/SwaggerConfigTest.java | 7 - .../selfcare/dashboard/core/UserService.java | 20 - .../dashboard/core/UserServiceImpl.java | 101 -- .../dashboard/core/UserServiceImplTest.java | 259 ----- .../web/controller/ProductController.java | 30 - .../web/controller/TokenController.java | 85 -- .../web/controller/UserController.java | 132 --- .../web/security/ExchangeTokenService.java | 375 ------- .../web/security/ExchangeTokenServiceV2.java | 8 +- .../web/controller/ProductControllerTest.java | 43 +- .../web/controller/TokenControllerTest.java | 94 -- .../web/controller/TokenV2ControllerTest.java | 1 - .../web/controller/UserControllerTest.java | 180 ---- .../security/ExchangeTokenServiceTest.java | 943 ------------------ .../security/ExchangeTokenServiceV2Test.java | 26 +- 16 files changed, 158 insertions(+), 3080 deletions(-) delete mode 100644 core/src/main/java/it/pagopa/selfcare/dashboard/core/UserService.java delete mode 100644 core/src/main/java/it/pagopa/selfcare/dashboard/core/UserServiceImpl.java delete mode 100644 core/src/test/java/it/pagopa/selfcare/dashboard/core/UserServiceImplTest.java delete mode 100644 web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/TokenController.java delete mode 100644 web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/UserController.java delete mode 100644 web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenService.java delete mode 100644 web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenControllerTest.java delete mode 100644 web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/UserControllerTest.java delete mode 100644 web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceTest.java diff --git a/app/src/main/resources/swagger/api-docs.json b/app/src/main/resources/swagger/api-docs.json index 313c14432..196033cb6 100644 --- a/app/src/main/resources/swagger/api-docs.json +++ b/app/src/main/resources/swagger/api-docs.json @@ -1805,98 +1805,6 @@ } ] } }, - "/v1/products/{productId}/back-office" : { - "get" : { - "tags" : [ "products" ], - "summary" : "retrieveProductBackoffice", - "description" : "Service to trigger token exchange and redirect to product's back office URL", - "operationId" : "retrieveProductBackofficeUsingGET", - "parameters" : [ { - "name" : "productId", - "in" : "path", - "description" : "Product's unique identifier", - "required" : true, - "style" : "simple", - "schema" : { - "type" : "string" - } - }, { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "environment", - "in" : "query", - "description" : "Back Office environment", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "type" : "string", - "format" : "uri" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, "/v1/products/{productId}/brokers/{institutionType}" : { "get" : { "tags" : [ "products" ], @@ -2124,580 +2032,9 @@ } } } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v1/support" : { - "post" : { - "tags" : [ "external-v2", "support" ], - "summary" : "sendSupportRequest", - "description" : "Service to retrieve Support contact's form", - "operationId" : "sendSupportRequestUsingPOST", - "parameters" : [ { - "name" : "authenticated", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "boolean" - } - }, { - "name" : "authorities[0].authority", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "credentials", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "object" - } - }, { - "name" : "details", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "object" - } - }, { - "name" : "principal", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "object" - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SupportRequestDto" - } - } - } - }, - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/SupportResponse" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v1/token/exchange" : { - "get" : { - "tags" : [ "token" ], - "summary" : "exchange", - "description" : "Service create an 'Identity Token' based on a Self Care session token", - "operationId" : "exchangeUsingGET", - "parameters" : [ { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "productId", - "in" : "query", - "description" : "Product's unique identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "environment", - "in" : "query", - "description" : "Back Office environment", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/IdentityTokenResource" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v1/token/exchange/fatturazione" : { - "get" : { - "tags" : [ "token" ], - "summary" : "billingToken", - "description" : "Service to create a 'Billing Token' based on a Self Care session token", - "operationId" : "billingTokenUsingGET", - "parameters" : [ { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "environment", - "in" : "query", - "description" : "Back Office environment", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "type" : "string", - "format" : "uri" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v2/token/exchange" : { - "get" : { - "tags" : [ "token" ], - "summary" : "Service create an 'Identity Token' based on a Self Care session token", - "description" : "Service create an 'Identity Token' based on a Self Care session token", - "operationId" : "v2Exchange", - "parameters" : [ { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "productId", - "in" : "query", - "description" : "Product's unique identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "environment", - "in" : "query", - "description" : "Back Office environment", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/IdentityTokenResource" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v2/token/exchange/fatturazione" : { - "get" : { - "tags" : [ "token" ], - "summary" : "billingToken", - "description" : "Service to create a 'Billing Token' based on a Self Care session token", - "operationId" : "billingTokenUsingGET_1", - "parameters" : [ { - "name" : "authenticated", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "boolean" - } - }, { - "name" : "authorities[0].authority", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "credentials", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "details", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "object" - } - }, { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "name", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - }, { - "name" : "principal", - "in" : "query", - "required" : false, - "style" : "form", - "schema" : { - "type" : "object" - } - }, { - "name" : "environment", - "in" : "query", - "description" : "Back Office environment", - "required" : false, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "200" : { - "description" : "OK", - "content" : { - "application/json" : { - "schema" : { - "type" : "string", - "format" : "uri" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "500" : { - "description" : "Internal Server Error", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - } - }, - "/v1/users" : { - "post" : { - "tags" : [ "user" ], - "summary" : "saveUser", - "description" : "Save new user", - "operationId" : "saveUserUsingPOST", - "parameters" : [ { - "name" : "institutionId", - "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, - "style" : "form", - "schema" : { - "type" : "string" - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/UserDto" - } - } - } - }, - "responses" : { - "201" : { - "description" : "Created", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/UserIdResource" - } - } - } - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", + }, + "404" : { + "description" : "Not Found", "content" : { "application/problem+json" : { "schema" : { @@ -2722,27 +2059,58 @@ } ] } }, - "/v1/users/search" : { + "/v1/support" : { "post" : { - "tags" : [ "user" ], - "summary" : "search", - "description" : "Retrieve the user for a given fiscal code", - "operationId" : "searchUsingPOST", + "tags" : [ "external-v2", "support" ], + "summary" : "sendSupportRequest", + "description" : "Service to retrieve Support contact's form", + "operationId" : "sendSupportRequestUsingPOST", "parameters" : [ { - "name" : "institutionId", + "name" : "authenticated", "in" : "query", - "description" : "Institution's unique internal identifier", - "required" : true, + "required" : false, + "style" : "form", + "schema" : { + "type" : "boolean" + } + }, { + "name" : "authorities[0].authority", + "in" : "query", + "required" : false, "style" : "form", "schema" : { "type" : "string" } + }, { + "name" : "credentials", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "object" + } + }, { + "name" : "details", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "object" + } + }, { + "name" : "principal", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "object" + } } ], "requestBody" : { "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/SearchUserDto" + "$ref" : "#/components/schemas/SupportRequestDto" } } } @@ -2753,7 +2121,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/UserResource" + "$ref" : "#/components/schemas/SupportResponse" } } } @@ -2778,16 +2146,6 @@ } } }, - "404" : { - "description" : "Not Found", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, "500" : { "description" : "Internal Server Error", "content" : { @@ -2804,31 +2162,39 @@ } ] } }, - "/v1/users/{id}" : { + "/v2/token/exchange" : { "get" : { - "tags" : [ "user" ], - "summary" : "getUserByInternalId", - "description" : "Retrieve the user by internal id", - "operationId" : "getUserByInternalIdUsingGET", + "tags" : [ "token" ], + "summary" : "Service create an 'Identity Token' based on a Self Care session token", + "description" : "Service create an 'Identity Token' based on a Self Care session token", + "operationId" : "v2Exchange", "parameters" : [ { - "name" : "id", - "in" : "path", - "description" : "User's unique identifier", + "name" : "institutionId", + "in" : "query", + "description" : "Institution's unique internal identifier", "required" : true, - "style" : "simple", + "style" : "form", "schema" : { - "type" : "string", - "format" : "uuid" + "type" : "string" } }, { - "name" : "institutionId", + "name" : "productId", "in" : "query", - "description" : "Institution's unique internal identifier", + "description" : "Product's unique identifier", "required" : true, "style" : "form", "schema" : { "type" : "string" } + }, { + "name" : "environment", + "in" : "query", + "description" : "Back Office environment", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } } ], "responses" : { "200" : { @@ -2836,7 +2202,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/UserResource" + "$ref" : "#/components/schemas/IdentityTokenResource" } } } @@ -2885,21 +2251,45 @@ "security" : [ { "bearerAuth" : [ "global" ] } ] - }, - "put" : { - "tags" : [ "user" ], - "summary" : "updateUser", - "description" : "Update previously added user", - "operationId" : "updateUserUsingPUT", + } + }, + "/v2/token/exchange/fatturazione" : { + "get" : { + "tags" : [ "token" ], + "summary" : "billingToken", + "description" : "Service to create a 'Billing Token' based on a Self Care session token", + "operationId" : "billingTokenUsingGET", "parameters" : [ { - "name" : "id", - "in" : "path", - "description" : "User's unique identifier", - "required" : true, - "style" : "simple", + "name" : "authenticated", + "in" : "query", + "required" : false, + "style" : "form", "schema" : { - "type" : "string", - "format" : "uuid" + "type" : "boolean" + } + }, { + "name" : "authorities[0].authority", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "credentials", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + }, { + "name" : "details", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "object" } }, { "name" : "institutionId", @@ -2910,42 +2300,46 @@ "schema" : { "type" : "string" } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/UpdateUserDto" - } - } + }, { + "name" : "name", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" } - }, + }, { + "name" : "principal", + "in" : "query", + "required" : false, + "style" : "form", + "schema" : { + "type" : "object" + } + }, { + "name" : "environment", + "in" : "query", + "description" : "Back Office environment", + "required" : false, + "style" : "form", + "schema" : { + "type" : "string" + } + } ], "responses" : { - "204" : { - "description" : "No Content" - }, - "400" : { - "description" : "Bad Request", - "content" : { - "application/problem+json" : { - "schema" : { - "$ref" : "#/components/schemas/Problem" - } - } - } - }, - "401" : { - "description" : "Unauthorized", + "200" : { + "description" : "OK", "content" : { - "application/problem+json" : { + "application/json" : { "schema" : { - "$ref" : "#/components/schemas/Problem" + "type" : "string", + "format" : "uri" } } } }, - "500" : { - "description" : "Internal Server Error", + "400" : { + "description" : "Bad Request", "content" : { "application/problem+json" : { "schema" : { @@ -2953,34 +2347,9 @@ } } } - } - }, - "security" : [ { - "bearerAuth" : [ "global" ] - } ] - }, - "delete" : { - "tags" : [ "user" ], - "summary" : "deleteUserById", - "description" : "Delete user using internal id", - "operationId" : "deleteUserByIdUsingDELETE", - "parameters" : [ { - "name" : "id", - "in" : "path", - "description" : "User's unique identifier", - "required" : true, - "style" : "simple", - "schema" : { - "type" : "string", - "format" : "uuid" - } - } ], - "responses" : { - "204" : { - "description" : "No Content" }, - "400" : { - "description" : "Bad Request", + "401" : { + "description" : "Unauthorized", "content" : { "application/problem+json" : { "schema" : { @@ -2989,8 +2358,8 @@ } } }, - "401" : { - "description" : "Unauthorized", + "404" : { + "description" : "Not Found", "content" : { "application/problem+json" : { "schema" : { @@ -6083,31 +5452,6 @@ } } }, - "UserDto" : { - "title" : "UserDto", - "required" : [ "email", "fiscalCode", "name", "surname" ], - "type" : "object", - "properties" : { - "email" : { - "type" : "string", - "description" : "User's institutional email", - "format" : "email", - "example" : "email@example.com" - }, - "fiscalCode" : { - "type" : "string", - "description" : "User's fiscal code" - }, - "name" : { - "type" : "string", - "description" : "User's name" - }, - "surname" : { - "type" : "string", - "description" : "User's surname" - } - } - }, "UserGroupIdResource" : { "title" : "UserGroupIdResource", "required" : [ "id" ], diff --git a/app/src/test/java/it/pagopa/selfcare/dashboard/web/config/SwaggerConfigTest.java b/app/src/test/java/it/pagopa/selfcare/dashboard/web/config/SwaggerConfigTest.java index 44f579667..73f4d4ba5 100644 --- a/app/src/test/java/it/pagopa/selfcare/dashboard/web/config/SwaggerConfigTest.java +++ b/app/src/test/java/it/pagopa/selfcare/dashboard/web/config/SwaggerConfigTest.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import it.pagopa.selfcare.dashboard.core.*; import it.pagopa.selfcare.dashboard.web.model.mapper.*; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenServiceV2; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -50,15 +49,9 @@ class SwaggerConfigTest { @MockBean private ExchangeTokenServiceV2 exchangeTokenServiceV2Mock; - @MockBean - private ExchangeTokenService exchangeTokenServiceMock; - @MockBean private ProductService productServiceMock; - @MockBean - private UserService userServiceMock; - @MockBean private UserV2Service userServiceV2Mock; diff --git a/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserService.java b/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserService.java deleted file mode 100644 index 3512106c2..000000000 --- a/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserService.java +++ /dev/null @@ -1,20 +0,0 @@ -package it.pagopa.selfcare.dashboard.core; - -import it.pagopa.selfcare.dashboard.connector.model.user.*; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.UUID; - -public interface UserService { - - User search(String fiscalCode); - - void updateUser(UUID id, String institutionId, MutableUserFieldsDto userDto); - - User getUserByInternalId(UUID id); - - UserId saveUser(String institutionId, SaveUserDto userDto); - - void deleteById(String userId); -} diff --git a/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserServiceImpl.java b/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserServiceImpl.java deleted file mode 100644 index 479628f1f..000000000 --- a/core/src/main/java/it/pagopa/selfcare/dashboard/core/UserServiceImpl.java +++ /dev/null @@ -1,101 +0,0 @@ -package it.pagopa.selfcare.dashboard.core; - -import it.pagopa.selfcare.commons.base.logging.LogUtils; -import it.pagopa.selfcare.dashboard.connector.api.MsCoreConnector; -import it.pagopa.selfcare.dashboard.connector.api.UserRegistryConnector; -import it.pagopa.selfcare.dashboard.connector.exception.ResourceNotFoundException; -import it.pagopa.selfcare.dashboard.connector.model.institution.Institution; -import it.pagopa.selfcare.dashboard.connector.model.user.*; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; - -import java.util.Collection; -import java.util.EnumSet; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - -import static it.pagopa.selfcare.dashboard.connector.model.user.User.Fields.*; - -@Slf4j -@Service -public class UserServiceImpl implements UserService { - - private final UserRegistryConnector userConnector; - private final MsCoreConnector msCoreConnector; - - @Autowired - public UserServiceImpl(UserRegistryConnector userConnector, MsCoreConnector msCoreConnector) { - this.userConnector = userConnector; - this.msCoreConnector = msCoreConnector; - } - - @Override - public User search(String fiscalCode) { - log.trace("getUser start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUser externalId = {}", fiscalCode); - Assert.hasText(fiscalCode, "A TaxCode is required"); - User result = userConnector.search(fiscalCode, - EnumSet.of(name, familyName, email, workContacts)); - Optional.ofNullable(result) - .ifPresent(user -> user.setFiscalCode(fiscalCode)); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUser result = {}", result); - log.trace("getUser end"); - return result; - } - - @Override - public void updateUser(UUID id, String institutionId, MutableUserFieldsDto userDto) { - log.trace("updateUser start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "updateUser id = {}, institutionId = {}, userDto = {}", id, institutionId, userDto); - Assert.notNull(id, "UUID is required"); - Assert.hasText(institutionId, "An institutionId is required"); - Assert.notNull(userDto, "A userDto is required"); - Institution institution = msCoreConnector.getInstitution(institutionId); - if (institution == null) { - throw new ResourceNotFoundException("There are no institution for given institutionId"); - } - msCoreConnector.updateUser(id.toString(), institutionId); - userConnector.updateUser(id, userDto); - log.trace("updateUser end"); - } - - @Override - public User getUserByInternalId(UUID id) { - log.trace("getUserByInternalId start"); - log.debug("getUserByInternalId id = {}", id); - Assert.notNull(id, "UUID is required"); - User result = userConnector.getUserByInternalId(id.toString(), - EnumSet.of(name, familyName, email, fiscalCode, workContacts)); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserByInternalId result = {}", result); - log.trace("getUserByInternalId end"); - return result; - } - - @Override - public UserId saveUser(String institutionId, SaveUserDto userDto) { - log.trace("saveUser start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "saveUser institutionId = {}, userDto = {}", institutionId, userDto); - Assert.hasText(institutionId, "An institutionId is required"); - Assert.notNull(userDto, "A userDto is required"); - Institution institution = msCoreConnector.getInstitution(institutionId); - if (institution == null) { - throw new ResourceNotFoundException("There are no institution for given institutionId"); - } - UserId result = userConnector.saveUser(userDto); - log.debug("saveUser result = {}", result); - log.trace("saveUser end"); - return result; - } - - @Override - public void deleteById(String userId) { - log.trace("deleteById start"); - log.debug("deleteById userId = {}", userId); - Assert.hasText(userId, "A UUID is required"); - userConnector.deleteById(userId); - log.trace("deleteById end"); - } -} diff --git a/core/src/test/java/it/pagopa/selfcare/dashboard/core/UserServiceImplTest.java b/core/src/test/java/it/pagopa/selfcare/dashboard/core/UserServiceImplTest.java deleted file mode 100644 index cdc8fd352..000000000 --- a/core/src/test/java/it/pagopa/selfcare/dashboard/core/UserServiceImplTest.java +++ /dev/null @@ -1,259 +0,0 @@ -package it.pagopa.selfcare.dashboard.core; - -import it.pagopa.selfcare.dashboard.connector.api.MsCoreConnector; -import it.pagopa.selfcare.dashboard.connector.api.UserRegistryConnector; -import it.pagopa.selfcare.dashboard.connector.exception.ResourceNotFoundException; -import it.pagopa.selfcare.dashboard.connector.model.institution.Institution; -import it.pagopa.selfcare.dashboard.connector.model.user.*; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.function.Executable; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.*; - -import static it.pagopa.selfcare.commons.utils.TestUtils.mockInstance; -import static it.pagopa.selfcare.dashboard.connector.model.user.User.Fields.*; -import static java.util.UUID.randomUUID; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -@ExtendWith({MockitoExtension.class}) -class UserServiceImplTest { - - @Mock - private UserRegistryConnector userConnectorMock; - - @InjectMocks - private UserServiceImpl userRegistryService; - - @Mock - private MsCoreConnector msCoreConnectorMock; - - - @Test - void search() { - //given - String fiscalCode = "fiscalCode"; - User expectedUser = mockInstance(new User()); - when(userConnectorMock.search(any(), any())) - .thenReturn(expectedUser); - //when - User user = userRegistryService.search(fiscalCode); - //then - assertSame(expectedUser, user); - verify(userConnectorMock, times(1)) - .search(fiscalCode, EnumSet.of(name, familyName, email, workContacts)); - assertEquals(fiscalCode, user.getFiscalCode()); - verifyNoMoreInteractions(userConnectorMock); - } - - - @Test - void search_nullFiscalCode() { - //given - String fiscalCode = null; - //when - Executable executable = () -> userRegistryService.search(fiscalCode); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A TaxCode is required", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void getUserByInternalId_nullId() { - //given - //when - Executable executable = () -> userRegistryService.getUserByInternalId(null); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("UUID is required", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void getUserByInternalId() { - //given - UUID id = randomUUID(); - User userMock = mockInstance(new User()); - when(userConnectorMock.getUserByInternalId(any(), any())) - .thenReturn(userMock); - //when - User user = userRegistryService.getUserByInternalId(id); - //then - assertSame(userMock, user); - verify(userConnectorMock, times(1)) - .getUserByInternalId(id.toString(), EnumSet.of(name, familyName, email, fiscalCode, workContacts)); - verifyNoMoreInteractions(userConnectorMock); - } - - - @Test - void updateUser() { - //given - String institutionId = "institutionId"; - UUID id = randomUUID(); - MutableUserFieldsDto user = mockInstance(new MutableUserFieldsDto(), "setWorkContacts"); - WorkContact workContact = mockInstance(new WorkContact()); - user.setWorkContacts(Map.of(institutionId, workContact)); - Institution institutionMock = mockInstance(new Institution()); - when(msCoreConnectorMock.getInstitution(Mockito.anyString())) - .thenReturn(institutionMock); - //when - Executable executable = () -> userRegistryService.updateUser(id, institutionId, user); - //then - assertDoesNotThrow(executable); - verify(msCoreConnectorMock, times(1)) - .getInstitution(institutionId); - verify(userConnectorMock, times(1)) - .updateUser(id, user); - verify(msCoreConnectorMock, times(1)).updateUser(id.toString(), institutionId); - verifyNoMoreInteractions(userConnectorMock, msCoreConnectorMock); - } - - @Test - void updateUser_nullInstitution() { - //given - String institutionId = "institutionId"; - UUID id = randomUUID(); - MutableUserFieldsDto user = mockInstance(new MutableUserFieldsDto(), "setWorkContacts"); - //when - Executable executable = () -> userRegistryService.updateUser(id, institutionId, user); - //then - ResourceNotFoundException e = assertThrows(ResourceNotFoundException.class, executable); - assertEquals("There are no institution for given institutionId", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void updateUser_nullInstitutionId() { - //given - String institutionId = null; - UUID id = randomUUID(); - MutableUserFieldsDto user = mockInstance(new MutableUserFieldsDto(), "setWorkContacts"); - //when - Executable executable = () -> userRegistryService.updateUser(id, institutionId, user); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("An institutionId is required", e.getMessage()); - verifyNoInteractions(userConnectorMock, msCoreConnectorMock); - } - - @Test - void updateUser_nullUUID() { - //given - String institutionId = "institutionId"; - UUID id = null; - MutableUserFieldsDto user = mockInstance(new MutableUserFieldsDto(), "setWorkContacts"); - //when - Executable executable = () -> userRegistryService.updateUser(id, institutionId, user); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("UUID is required", e.getMessage()); - verifyNoInteractions(userConnectorMock, msCoreConnectorMock); - } - - @Test - void updateUser_nullDto() { - //given - String institutionId = "institutionId"; - UUID id = randomUUID(); - MutableUserFieldsDto user = null; - //when - Executable executable = () -> userRegistryService.updateUser(id, institutionId, user); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A userDto is required", e.getMessage()); - verifyNoInteractions(userConnectorMock, msCoreConnectorMock); - } - - @Test - void saveUser_nullInstitutionId() { - //given - String institutionId = null; - SaveUserDto user = mockInstance(new SaveUserDto(), "setWorkContacts"); - //when - Executable executable = () -> userRegistryService.saveUser(institutionId, user); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("An institutionId is required", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void saveUser_nullDto() { - //given - String institutionId = "institutionId"; - SaveUserDto user = null; - //when - Executable executable = () -> userRegistryService.saveUser(institutionId, user); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A userDto is required", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void saveUser_institutionNotFound() { - //given - String institutionId = "institutionId"; - SaveUserDto user = mockInstance(new SaveUserDto(), "setWorkContacts"); - //when - Executable executable = () -> userRegistryService.saveUser(institutionId, user); - //then - ResourceNotFoundException e = assertThrows(ResourceNotFoundException.class, executable); - assertEquals("There are no institution for given institutionId", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void saveUser() { - //given - String institutionId = "institutionId"; - UserId userId = mockInstance(new UserId()); - SaveUserDto user = mockInstance(new SaveUserDto(), "setWorkContacts"); - WorkContact workContact = mockInstance(new WorkContact()); - user.setWorkContacts(Map.of(institutionId, workContact)); - when(userConnectorMock.saveUser(any())) - .thenReturn(userId); - Institution institutionMock = mockInstance(new Institution()); - when(msCoreConnectorMock.getInstitution(Mockito.anyString())) - .thenReturn(institutionMock); - //when - UserId id = userRegistryService.saveUser(institutionId, user); - //then - assertEquals(userId, id); - verify(msCoreConnectorMock, times(1)) - .getInstitution(institutionId); - verify(userConnectorMock, times(1)) - .saveUser(user); - verifyNoMoreInteractions(userConnectorMock, msCoreConnectorMock); - } - - @Test - void deleteById_nullId() { - //given - //when - Executable exe = () -> userRegistryService.deleteById(null); - //then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, exe); - assertEquals("A UUID is required", e.getMessage()); - verifyNoInteractions(userConnectorMock); - } - - @Test - void deleteById() { - //given - String userId = randomUUID().toString(); - //when - userRegistryService.deleteById(userId); - //then - verify(userConnectorMock, times(1)) - .deleteById(userId); - } -} \ No newline at end of file diff --git a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/ProductController.java b/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/ProductController.java index 1dc36276a..6fb0a3ba0 100644 --- a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/ProductController.java +++ b/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/ProductController.java @@ -7,23 +7,18 @@ import it.pagopa.selfcare.dashboard.connector.model.backoffice.BrokerInfo; import it.pagopa.selfcare.dashboard.core.BrokerService; import it.pagopa.selfcare.dashboard.core.ProductService; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; import it.pagopa.selfcare.dashboard.web.model.mapper.BrokerResourceMapper; import it.pagopa.selfcare.dashboard.web.model.mapper.ProductsMapper; import it.pagopa.selfcare.dashboard.web.model.product.BrokerResource; import it.pagopa.selfcare.dashboard.web.model.product.ProductRoleMappingsResource; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.net.URI; import java.util.Collection; import java.util.List; -import java.util.Optional; @Slf4j @RestController @@ -32,18 +27,15 @@ public class ProductController { private final ProductService productService; - private final ExchangeTokenService exchangeTokenService; private final BrokerService brokerService; private final BrokerResourceMapper brokerResourceMapper; private static final String PAGO_PA_PRODUCT_ID = "prod-pagopa"; @Autowired public ProductController(ProductService productService, - ExchangeTokenService exchangeTokenService, BrokerService brokerService, BrokerResourceMapper brokerResourceMapper) { this.productService = productService; - this.exchangeTokenService = exchangeTokenService; this.brokerService = brokerService; this.brokerResourceMapper = brokerResourceMapper; } @@ -63,28 +55,6 @@ public Collection getProductRoles(@ApiParam("${swag return result; } - @GetMapping(value = "/{productId}/back-office", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "", notes = "${swagger.dashboard.product.api.retrieveProductBackoffice}") - @PreAuthorize("hasPermission(new it.pagopa.selfcare.dashboard.web.security.ProductAclDomain(#institutionId, #productId), 'ANY')") - public URI retrieveProductBackoffice(@ApiParam("${swagger.dashboard.products.model.id}") - @PathVariable("productId") - String productId, - @ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam("institutionId") - String institutionId, - @ApiParam("${swagger.dashboard.product-backoffice-configurations.model.environment}") - @RequestParam(value = "environment", required = false) - Optional environment) { - log.trace("accessProductBackoffice start"); - log.debug("accessProductBackoffice institutionId = {}, productId = {}", institutionId, productId); - final ExchangedToken exchangedToken = exchangeTokenService.exchange(institutionId, productId, environment); - final URI location = URI.create(exchangedToken.getBackOfficeUrl().replace("", exchangedToken.getIdentityToken())); - log.trace("accessProductBackoffice end"); - return location; - - } - @GetMapping(value = "/{productId}/brokers/{institutionType}", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @ApiOperation(value = "", notes = "${swagger.dashboard.product.api.getProductBrokers}") diff --git a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/TokenController.java b/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/TokenController.java deleted file mode 100644 index 989708364..000000000 --- a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/TokenController.java +++ /dev/null @@ -1,85 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.controller; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import it.pagopa.selfcare.commons.base.logging.LogUtils; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; -import it.pagopa.selfcare.dashboard.web.model.IdentityTokenResource; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import java.net.URI; -import java.util.Optional; - -@Slf4j -@RestController -@RequestMapping(value = "/v1/token", produces = MediaType.APPLICATION_JSON_VALUE) -@Api(tags = "token") -public class TokenController { - - private final ExchangeTokenService exchangeTokenService; - - - @Autowired - public TokenController(ExchangeTokenService exchangeTokenService) { - this.exchangeTokenService = exchangeTokenService; - } - - - @GetMapping(value = "exchange", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "", notes = "${swagger.dashboard.token.api.exchange}") - @PreAuthorize("hasPermission(new it.pagopa.selfcare.dashboard.web.security.ProductAclDomain(#institutionId, #productId), 'ANY')") - public IdentityTokenResource exchange(@ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam("institutionId") - String institutionId, - @ApiParam("${swagger.dashboard.products.model.id}") - @RequestParam("productId") - String productId, - @ApiParam("${swagger.dashboard.product-backoffice-configurations.model.environment}") - @RequestParam(value = "environment", required = false) - Optional environment) { - - log.trace("exchange start"); - log.debug("exchange institutionId = {}, productId = {}", institutionId, productId); - - String token = exchangeTokenService.exchange(institutionId, productId, environment).getIdentityToken(); - IdentityTokenResource identityToken = new IdentityTokenResource(); - identityToken.setToken(token); - - - log.debug(LogUtils.CONFIDENTIAL_MARKER, "exchange result = {}", identityToken); - log.trace("exchange end"); - - return identityToken; - } - - @GetMapping(value = "exchange/fatturazione", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "", notes = "${swagger.dashboard.token.api.billingToken}") - @PreAuthorize("hasPermission(#institutionId, 'InstitutionResource', 'ANY')") - public URI billingToken(@ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam("institutionId") - String institutionId, - @ApiParam("${swagger.dashboard.product-backoffice-configurations.model.environment}") - @RequestParam(value = "environment", required = false) - Optional environment) { - - log.trace("billing exchange start"); - log.debug("billing exchange institutionId = {}", institutionId); - log.info("env parameter: {}", environment); - final ExchangedToken exchangedToken = exchangeTokenService.retrieveBillingExchangedToken(institutionId); - final URI location = URI.create(exchangedToken.getBackOfficeUrl().replace("", exchangedToken.getIdentityToken())); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "billing exchange result = {}", location); - log.trace("billing exchange end"); - - return location; - } - -} diff --git a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/UserController.java b/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/UserController.java deleted file mode 100644 index ca534a0c6..000000000 --- a/web/src/main/java/it/pagopa/selfcare/dashboard/web/controller/UserController.java +++ /dev/null @@ -1,132 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.controller; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import it.pagopa.selfcare.commons.base.logging.LogUtils; -import it.pagopa.selfcare.commons.web.model.Problem; -import it.pagopa.selfcare.dashboard.connector.model.user.User; -import it.pagopa.selfcare.dashboard.connector.model.user.UserId; -import it.pagopa.selfcare.dashboard.core.UserService; -import it.pagopa.selfcare.dashboard.web.model.SearchUserDto; -import it.pagopa.selfcare.dashboard.web.model.UpdateUserDto; -import it.pagopa.selfcare.dashboard.web.model.mapper.UserMapper; -import it.pagopa.selfcare.dashboard.web.model.user.UserDto; -import it.pagopa.selfcare.dashboard.web.model.user.UserIdResource; -import it.pagopa.selfcare.dashboard.web.model.user.UserResource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.UUID; - -@Slf4j -@RestController -@RequestMapping(value = "/v1/users", produces = MediaType.APPLICATION_JSON_VALUE) -@Api(tags = "user") -public class UserController { - - private final UserService userService; - - @Autowired - public UserController(UserService userService) { - this.userService = userService; - } - - @PostMapping(value = "/search", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "", notes = "${swagger.dashboard.user.api.search}") - @ApiResponse(responseCode = "404", - description = "Not Found", - content = { - @Content(mediaType = MediaType.APPLICATION_PROBLEM_JSON_VALUE, - schema = @Schema(implementation = Problem.class)) - }) - public UserResource search(@ApiParam("${swagger.dashboard.user.model.searchUserDto}") - @RequestBody - @Valid - SearchUserDto searchUserDto, - @ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam(value = "institutionId") - String institutionId) { - log.trace("getUserByExternalId start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserByExternalId searchUserDto = {}", searchUserDto); - User user = userService.search(searchUserDto.getFiscalCode()); - UserResource result = UserMapper.toUserResource(user, institutionId); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "getUserByExternalId result = {}", result); - log.trace("getUserByExternalId end"); - return result; - } - - @PutMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.NO_CONTENT) - @ApiOperation(value = "", notes = "${swagger.dashboard.user.api.updateUserById}") - public void updateUser(@ApiParam("${swagger.dashboard.user.model.id}") - @PathVariable("id") - UUID id, - @ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam(value = "institutionId") - String institutionId, - @RequestBody - @Valid - UpdateUserDto updateUserDto) { - log.trace("updateUser start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "id = {}, institutionId = {}, userDto = {}", id, institutionId, updateUserDto); - userService.updateUser(id, institutionId, UserMapper.fromUpdateUser(updateUserDto, institutionId)); - log.trace("updateUser end"); - } - - @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.CREATED) - @ApiOperation(value = "", notes = "${swagger.dashboard.user.api.saveUser}") - public UserIdResource saveUser(@ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam(value = "institutionId") - String institutionId, - @RequestBody - @Valid - UserDto userDto) { - log.trace("saveUser start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "saveUser userDto = {}", userDto); - UserId id = userService.saveUser(institutionId, UserMapper.map(userDto, institutionId)); - UserIdResource result = UserMapper.toIdResource(id); - log.debug("saveUser result = {}", result); - log.trace("saveUser end"); - return result; - } - - @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.OK) - @ApiOperation(value = "", notes = "${swagger.dashboard.user.api.getUserByInternalId}") - public UserResource getUserByInternalId(@ApiParam("${swagger.dashboard.user.model.id}") - @PathVariable("id") UUID id, - @ApiParam("${swagger.dashboard.institutions.model.id}") - @RequestParam(value = "institutionId") - String institutionId) { - log.trace("getUserByInternalId start"); - log.debug("getUserByInternalId id = {}, institutionId = {}", id, institutionId); - User user = userService.getUserByInternalId(id); - UserResource result = UserMapper.toUserResource(user, institutionId); - log.debug("getUserByInternalId result = {}", result); - log.trace("getUserByInternalId end"); - return result; - } - - @DeleteMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(HttpStatus.NO_CONTENT) - @ApiOperation(value = "", notes = "${swagger.dashboard.user.api.deleteUserById}") - public void deleteUserById(@ApiParam("${swagger.dashboard.user.model.id}") - @PathVariable("id") UUID id) { - - log.trace("deleteUserById start"); - log.debug("deleteUserById id = {}", id); - userService.deleteById(id.toString()); - log.trace("deleteUserById end"); - } - -} diff --git a/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenService.java b/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenService.java deleted file mode 100644 index 7e4b78ecc..000000000 --- a/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenService.java +++ /dev/null @@ -1,375 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.security; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.jsonwebtoken.*; -import io.jsonwebtoken.impl.DefaultClaims; -import it.pagopa.selfcare.commons.base.logging.LogUtils; -import it.pagopa.selfcare.commons.base.security.PartyRole; -import it.pagopa.selfcare.commons.base.security.ProductGrantedAuthority; -import it.pagopa.selfcare.commons.base.security.SelfCareGrantedAuthority; -import it.pagopa.selfcare.commons.base.security.SelfCareUser; -import it.pagopa.selfcare.commons.web.security.JwtService; -import it.pagopa.selfcare.dashboard.connector.api.ProductsConnector; -import it.pagopa.selfcare.dashboard.connector.model.groups.UserGroupInfo; -import it.pagopa.selfcare.dashboard.connector.model.institution.InstitutionInfo; -import it.pagopa.selfcare.dashboard.connector.model.user.User; -import it.pagopa.selfcare.dashboard.core.InstitutionService; -import it.pagopa.selfcare.dashboard.core.UserGroupService; -import it.pagopa.selfcare.dashboard.core.UserService; -import it.pagopa.selfcare.dashboard.web.config.ExchangeTokenProperties; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; -import it.pagopa.selfcare.product.entity.Product; -import lombok.Data; -import lombok.ToString; -import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.asn1.pkcs.RSAPrivateKey; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; - -import java.io.Serializable; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.time.Duration; -import java.util.*; -import java.util.stream.Stream; - -@Slf4j -@Service -public class ExchangeTokenService { - - private static final String PRIVATE_KEY_HEADER_TEMPLATE = "-----BEGIN %s-----"; - private static final String PRIVATE_KEY_FOOTER_TEMPLATE = "-----END %s-----"; - - private final String billingUrl; - private final String billingAudience; - private final PrivateKey jwtSigningKey; - private final JwtService jwtService; - private final Duration duration; - private final String kid; - private final InstitutionService institutionService; - private final UserGroupService groupService; - public final UserService userService; - private final ProductsConnector productsConnector; - private final String issuer; - - public ExchangeTokenService(JwtService jwtService, - InstitutionService institutionService, - UserGroupService groupService, - ProductsConnector productConnector, - ExchangeTokenProperties properties, - UserService userService) throws InvalidKeySpecException, NoSuchAlgorithmException { - this.billingUrl = properties.getBillingUrl(); - this.billingAudience = properties.getBillingAudience(); - this.jwtService = jwtService; - this.productsConnector = productConnector; - this.institutionService = institutionService; - this.groupService = groupService; - this.jwtSigningKey = getPrivateKey(properties.getSigningKey()); - this.issuer = properties.getIssuer(); - this.duration = Duration.parse(properties.getDuration()); - this.kid = properties.getKid(); - this.userService = userService; - } - - - public ExchangedToken exchange(String institutionId, String productId, Optional environment) { - log.trace("exchange start"); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "exchange institutionId = {}, productId = {}", institutionId, productId); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null) { - throw new IllegalStateException("Authentication is required"); - } - - List> productGrantedAuthorityMap = retrieveProductGrantedAuthorityMap(authentication, institutionId); - final ProductGrantedAuthority productGrantedAuthority = productGrantedAuthorityMap.stream() - .filter(map -> map.containsKey(productId)) - .map(map -> map.get(productId)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException(String.format("A Product Granted SelfCareAuthority is required for product '%s' and institution '%s'", productId, institutionId))); - - Institution institution = retrieveInstitution(institutionId, List.of(productGrantedAuthority), false); - SelfCareUser principal = (SelfCareUser) authentication.getPrincipal(); - retrieveAndSetGroups(institution, institutionId, productId, principal); - TokenExchangeClaims claims = retrieveAndSetClaims(authentication.getCredentials().toString(), institution, principal); - - Product product = productsConnector.getProduct(productId); - - environment.ifPresentOrElse(env -> claims.setAudience(product.getBackOfficeEnvironmentConfigurations().get(env).getIdentityTokenAudience()) - , () -> claims.setAudience(product.getIdentityTokenAudience())); - - log.debug(LogUtils.CONFIDENTIAL_MARKER, "Exchanged claims = {}", claims); - String jwts = createJwts(claims); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "Exchanged token = {}", jwts); - - final String urlBO = environment.map(env -> product.getBackOfficeEnvironmentConfigurations().get(env).getUrl()) - .orElse(product.getUrlBO()); - - log.trace("exchange end"); - return new ExchangedToken(jwts, urlBO); - } - - public ExchangedToken retrieveBillingExchangedToken(String institutionId) { - - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null) { - throw new IllegalStateException("Authentication is required"); - } - - List invoiceableProductList = retrieveInvoiceableProductList(); - - final List productGrantedAuthorities = new ArrayList<>(); - - List> productGrantedAuthorityMap = retrieveProductGrantedAuthorityMap(authentication, institutionId); - productGrantedAuthorityMap.forEach(stringProductGrantedAuthorityMap -> addProductIfIsInvoiceable(stringProductGrantedAuthorityMap, invoiceableProductList, productGrantedAuthorities)); - - Institution institution = retrieveInstitution(institutionId, productGrantedAuthorities, true); - SelfCareUser principal = (SelfCareUser) authentication.getPrincipal(); - retrieveAndSetGroups(institution, institutionId, null, principal); - - TokenExchangeClaims claims = retrieveAndSetClaims(authentication.getCredentials().toString(), institution, principal); - claims.setAudience(billingAudience); - - log.debug(LogUtils.CONFIDENTIAL_MARKER, "Exchanged claims = {}", claims); - String jwts = createJwts(claims); - log.debug(LogUtils.CONFIDENTIAL_MARKER, "Exchanged token = {}", jwts); - log.trace("exchange end"); - - return new ExchangedToken(jwts, billingUrl); - } - - private List retrieveInvoiceableProductList() { - return productsConnector.getProductsTree() - .stream() - .flatMap(productTree -> { - Stream nodeStream = Stream.of(productTree.getNode()); - Stream childrenStream = productTree.getChildren() != null - ? productTree.getChildren().stream() - : Stream.empty(); - return Stream.concat(nodeStream, childrenStream); - }) - .filter(Product::isInvoiceable) - .map(Product::getId) - .toList(); - } - - private TokenExchangeClaims retrieveAndSetClaims(String credential, Institution institution, SelfCareUser principal) { - Claims selcClaims = jwtService.getClaims(credential); - Assert.notNull(selcClaims, "Session token claims is required"); - TokenExchangeClaims claims = new TokenExchangeClaims(selcClaims); - claims.setId(UUID.randomUUID().toString()); - claims.setIssuer(issuer); - User user = userService.getUserByInternalId(UUID.fromString(principal.getId())); - - String email = Optional.ofNullable(user.getWorkContact(institution.getId())) - .map(workContract -> Objects.nonNull(workContract.getEmail()) - ? workContract.getEmail().getValue() - : "" - ) - .orElse(null); - - claims.setEmail(email); - claims.setInstitution(institution); - claims.setDesiredExpiration(claims.getExpiration()); - claims.setIssuedAt(new Date()); - claims.setExpiration(Date.from(claims.getIssuedAt().toInstant().plus(duration))); - - return claims; - } - - - private List> retrieveProductGrantedAuthorityMap(Authentication authentication, String institutionId) { - return authentication.getAuthorities() - .stream() - .filter(grantedAuthority -> SelfCareGrantedAuthority.class.isAssignableFrom(grantedAuthority.getClass())) - .map(SelfCareGrantedAuthority.class::cast) - .filter(grantedAuthority -> institutionId.equals(grantedAuthority.getInstitutionId())) - .map(SelfCareGrantedAuthority::getRoleOnProducts) - .toList(); - } - - - private String createJwts(TokenExchangeClaims claims) { - return Jwts.builder() - .setClaims(claims) - .signWith(SignatureAlgorithm.RS256, jwtSigningKey) - .setHeaderParam(JwsHeader.KEY_ID, kid) - .setHeaderParam(Header.TYPE, Header.JWT_TYPE) - .compact(); - } - - private void retrieveAndSetGroups(Institution institution, String institutionId, String productId, SelfCareUser principal) { - Page groupInfos = groupService.getUserGroups(Optional.of(institutionId), - Optional.ofNullable(productId), - Optional.of(UUID.fromString(principal.getId())), - Pageable.ofSize(100));// 100 is a reasonably safe number to retrieve all groups related to a generic user - if (groupInfos.hasNext()) { - log.warn(String.format("Current user (%s) is member of more than 100 groups related to institution %s and product %s. The Identity Token will contain only the first 100 records", - principal.getId(), - institutionId, - productId)); - } - if (!groupInfos.isEmpty()) { - institution.setGroups(groupInfos.stream() - .map(UserGroupInfo::getId) - .toList()); - } - } - - private Institution retrieveInstitution(String institutionId, List productGrantedAuthorities, boolean isBillingToken) { - InstitutionInfo institutionInfo = institutionService.getInstitution(institutionId); - Assert.notNull(institutionInfo, "Institution info is required"); - Institution institution = new Institution(); - institution.setId(institutionId); - institution.setName(institutionInfo.getDescription()); - institution.setTaxCode(institutionInfo.getTaxCode()); - institution.setSubUnitType(institutionInfo.getSubunitType()); - institution.setSubUnitCode(institutionInfo.getSubunitCode()); - institution.setAooParent(institutionInfo.getAooParentCode()); - institution.setParentDescription(institutionInfo.getParentDescription()); - RootParent rootParent = new RootParent(); - rootParent.setId(institutionInfo.getRootParentId()); - rootParent.setDescription(institutionInfo.getParentDescription()); - institution.setRootParent(rootParent); - institution.setOriginId(institutionInfo.getOriginId()); - institution.setRoles(retrieveInstitutionRoles(productGrantedAuthorities, isBillingToken)); - return institution; - } - - private List retrieveInstitutionRoles(List productGrantedAuthorities, boolean isBillingToken) { - List roles = new ArrayList<>(); - - for (ProductGrantedAuthority authority : productGrantedAuthorities) { - roles.addAll(constructRole(authority, isBillingToken)); - } - return roles; - } - - private List constructRole(ProductGrantedAuthority productGrantedAuthority, boolean isBillingToken) { - return productGrantedAuthority.getProductRoles().stream() - .map(productRoleCode -> { - Role role = new Role(); - role.setPartyRole(productGrantedAuthority.getPartyRole()); - role.setProductRole(productRoleCode); - if (isBillingToken) { - role.setProductId(productGrantedAuthority.getProductId()); - } - return role; - }).toList(); - } - - private void addProductIfIsInvoiceable(Map map, List productList, List productGrantedAuthorities) { - map.keySet() - .forEach(key -> productList.stream().filter(key::equalsIgnoreCase) - .findFirst() - .ifPresent(productId -> productGrantedAuthorities.add(map.get(key)))); - } - - - private PrivateKey getPrivateKey(String signingKey) throws NoSuchAlgorithmException, InvalidKeySpecException { - boolean isRsa = signingKey.contains("RSA"); - String privateKeyEnvelopName = (isRsa ? "RSA " : "") + "PRIVATE KEY"; - String privateKeyPEM = signingKey - .replace("\r", "") - .replace("\n", "") - .replace(String.format(PRIVATE_KEY_HEADER_TEMPLATE, privateKeyEnvelopName), "") - .replace(String.format(PRIVATE_KEY_FOOTER_TEMPLATE, privateKeyEnvelopName), ""); - - byte[] encoded = Base64.getDecoder().decode(privateKeyPEM); - - KeySpec keySpec; - if (isRsa) { - RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(encoded); - keySpec = new RSAPrivateCrtKeySpec( - rsaPrivateKey.getModulus(), - rsaPrivateKey.getPublicExponent(), - rsaPrivateKey.getPrivateExponent(), - rsaPrivateKey.getPrime1(), - rsaPrivateKey.getPrime2(), - rsaPrivateKey.getExponent1(), - rsaPrivateKey.getExponent2(), - rsaPrivateKey.getCoefficient()); - - } else { - keySpec = new PKCS8EncodedKeySpec(encoded); - } - - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - return keyFactory.generatePrivate(keySpec); - } - - - @Data - @ToString - @JsonInclude(JsonInclude.Include.NON_NULL) - static class Institution implements Serializable { - private String id; - @JsonProperty("fiscal_code") - private String taxCode; - private String name; - private List roles; - @JsonInclude(JsonInclude.Include.NON_NULL) - private List groups; - private String subUnitCode; - private String subUnitType; - private String aooParent; - @Deprecated - private String parentDescription; - @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = RootParent.class) - private RootParent rootParent; - @JsonProperty("ipaCode") - private String originId; - } - - @Data - static class RootParent implements Serializable { - private String id; - private String description; - } - - @Data - @JsonInclude(JsonInclude.Include.NON_NULL) - static class Role implements Serializable { - private PartyRole partyRole; - @JsonProperty("role") - private String productRole; - private String productId; - } - - - static class TokenExchangeClaims extends DefaultClaims { - public static final String DESIRED_EXPIRATION = "desired_exp"; - public static final String INSTITUTION = "organization"; - public static final String EMAIL = "email"; - - public TokenExchangeClaims(Map map) { - super(map); - } - - public Claims setDesiredExpiration(Date desiredExp) { - setDate(DESIRED_EXPIRATION, desiredExp); - return this; - } - - public Claims setInstitution(Institution institution) { - setValue(INSTITUTION, institution); - return this; - } - - public Claims setEmail(String email) { - setValue(EMAIL, email); - return this; - } - - } - -} diff --git a/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2.java b/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2.java index a99852bce..d80d529ab 100644 --- a/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2.java +++ b/web/src/main/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2.java @@ -18,7 +18,7 @@ import it.pagopa.selfcare.dashboard.connector.model.user.UserInstitution; import it.pagopa.selfcare.dashboard.core.InstitutionService; import it.pagopa.selfcare.dashboard.core.UserGroupService; -import it.pagopa.selfcare.dashboard.core.UserService; +import it.pagopa.selfcare.dashboard.core.UserV2Service; import it.pagopa.selfcare.dashboard.web.config.ExchangeTokenProperties; import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; import it.pagopa.selfcare.dashboard.web.model.mapper.InstitutionResourceMapper; @@ -63,7 +63,7 @@ public class ExchangeTokenServiceV2 { private final String kid; private final InstitutionService institutionService; private final UserGroupService groupService; - public final UserService userService; + public final UserV2Service userService; public final UserApiConnector userApiConnector; private final ProductsConnector productsConnector; @@ -76,7 +76,7 @@ public ExchangeTokenServiceV2(JwtService jwtService, UserGroupService groupService, ProductsConnector productConnector, ExchangeTokenProperties properties, - UserService userService, + UserV2Service userService, UserApiConnector userApiConnector, InstitutionResourceMapper institutionResourceMapper) throws InvalidKeySpecException, NoSuchAlgorithmException { @@ -190,7 +190,7 @@ private TokenExchangeClaims retrieveAndSetClaims(String credential, Institution TokenExchangeClaims claims = new TokenExchangeClaims(selcClaims); claims.setId(UUID.randomUUID().toString()); claims.setIssuer(issuer); - User user = userService.getUserByInternalId(UUID.fromString(userId)); + User user = userService.getUserById(userId, null, null); String email = Optional.ofNullable(user.getWorkContact(userMailUuid)) .map(workContract -> Objects.nonNull(workContract.getEmail()) diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/ProductControllerTest.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/ProductControllerTest.java index b57549fcc..8a084e278 100644 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/ProductControllerTest.java +++ b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/ProductControllerTest.java @@ -6,11 +6,9 @@ import it.pagopa.selfcare.dashboard.core.BrokerService; import it.pagopa.selfcare.dashboard.core.ProductService; import it.pagopa.selfcare.dashboard.web.config.WebTestConfig; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; import it.pagopa.selfcare.dashboard.web.model.mapper.BrokerResourceMapperImpl; import it.pagopa.selfcare.dashboard.web.model.product.BrokerResource; import it.pagopa.selfcare.dashboard.web.model.product.ProductRoleMappingsResource; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; import it.pagopa.selfcare.onboarding.common.PartyRole; import it.pagopa.selfcare.product.entity.ProductRoleInfo; import org.junit.jupiter.api.Test; @@ -24,13 +22,12 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import java.net.URI; import java.util.Collection; import java.util.EnumMap; import java.util.List; -import java.util.Optional; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -54,10 +51,6 @@ class ProductControllerTest { @MockBean private BrokerService brokerServiceMock; - @MockBean - private ExchangeTokenService exchangeTokenServiceMock; - - @Test void getProductRoles() throws Exception { // given @@ -82,36 +75,6 @@ void getProductRoles() throws Exception { verify(productServiceMock, times(1)) .getProductRoles(productId); verifyNoMoreInteractions(productServiceMock); - verifyNoInteractions(exchangeTokenServiceMock); - } - - - @Test - void retrieveProductBackoffice() throws Exception { - // given - String productId = "prod1"; - String institutionId = "inst1"; - final String identityToken = "identityToken"; - final String backOfficeUrl = "back-office-url#token="; - when(exchangeTokenServiceMock.exchange(any(), any(), any())) - .thenReturn(new ExchangedToken(identityToken, backOfficeUrl + "")); - // when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .get(BASE_URL + "/{productId}/back-office", productId) - .queryParam("institutionId", institutionId) - .contentType(APPLICATION_JSON_VALUE) - .accept(APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()) - .andReturn(); - // then - URI response = objectMapper.readValue(result.getResponse().getContentAsString(), URI.class); - assertTrue(response.toString().contains(identityToken)); - assertTrue(response.toString().contains(backOfficeUrl)); - - verify(exchangeTokenServiceMock, times(1)) - .exchange(institutionId, productId, Optional.empty()); - verifyNoMoreInteractions(exchangeTokenServiceMock); - verifyNoInteractions(productServiceMock); } @Test @@ -147,7 +110,6 @@ void getProductBrokers() throws Exception { verify(brokerServiceMock, times(1)) .findAllByInstitutionType(institutionType); verifyNoMoreInteractions(brokerServiceMock); - verifyNoInteractions(exchangeTokenServiceMock); } @Test @@ -162,7 +124,6 @@ void getProductBrokersForUnsupportedType() throws Exception { // then assertEquals(400, result.getResponse().getStatus()); Mockito.verifyNoInteractions(brokerServiceMock); - Mockito.verifyNoInteractions(exchangeTokenServiceMock); } } diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenControllerTest.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenControllerTest.java deleted file mode 100644 index 2a8c0b085..000000000 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenControllerTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import it.pagopa.selfcare.dashboard.web.config.WebTestConfig; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; -import it.pagopa.selfcare.dashboard.web.model.IdentityTokenResource; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; - -import java.net.URI; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -@WebMvcTest(value = {TokenController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) -@ContextConfiguration(classes = {TokenController.class, WebTestConfig.class}) -class TokenControllerTest { - - private static final String BASE_URL = "/v1/token"; - - @Autowired - protected MockMvc mvc; - - @Autowired - protected ObjectMapper objectMapper; - - @MockBean - private ExchangeTokenService exchangeTokenServiceMock; - - - @Test - void exchange() throws Exception { - // given - String institutionId = "inst1"; - String productId = "prod1"; - Mockito.when(exchangeTokenServiceMock.exchange(anyString(), anyString(), any())) - .thenReturn(new ExchangedToken("token", "urlBO")); - // when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .get(BASE_URL + "/exchange") - .param("institutionId", institutionId) - .param("productId", productId) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().is2xxSuccessful()) - .andReturn(); - // then - IdentityTokenResource resource = objectMapper.readValue(result.getResponse().getContentAsString(), IdentityTokenResource.class); - assertNotNull(resource); - assertNotNull(resource.getToken()); - verify(exchangeTokenServiceMock, Mockito.times(1)) - .exchange(institutionId, productId, Optional.empty()); - verifyNoMoreInteractions(exchangeTokenServiceMock); - } - - @Test - void billingExchange() throws Exception { - // given - String institutionId = "inst1"; - Mockito.when(exchangeTokenServiceMock.retrieveBillingExchangedToken(anyString())) - .thenReturn(new ExchangedToken("token", "urlBO")); - // when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .get(BASE_URL + "/exchange/fatturazione") - .param("institutionId", institutionId) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(MockMvcResultMatchers.status().is2xxSuccessful()) - .andReturn(); - // then - URI resource = objectMapper.readValue(result.getResponse().getContentAsString(), URI.class); - assertNotNull(resource); - verify(exchangeTokenServiceMock, Mockito.times(1)) - .retrieveBillingExchangedToken(institutionId); - verifyNoMoreInteractions(exchangeTokenServiceMock); - } - - -} \ No newline at end of file diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenV2ControllerTest.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenV2ControllerTest.java index d2a80034d..08080398b 100644 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenV2ControllerTest.java +++ b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/TokenV2ControllerTest.java @@ -4,7 +4,6 @@ import it.pagopa.selfcare.dashboard.web.config.WebTestConfig; import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; import it.pagopa.selfcare.dashboard.web.model.IdentityTokenResource; -import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenService; import it.pagopa.selfcare.dashboard.web.security.ExchangeTokenServiceV2; import org.junit.jupiter.api.Test; import org.mockito.Mockito; diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/UserControllerTest.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/UserControllerTest.java deleted file mode 100644 index e9834f148..000000000 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/controller/UserControllerTest.java +++ /dev/null @@ -1,180 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import it.pagopa.selfcare.commons.utils.TestUtils; -import it.pagopa.selfcare.dashboard.connector.model.user.*; -import it.pagopa.selfcare.dashboard.core.UserService; -import it.pagopa.selfcare.dashboard.web.config.WebTestConfig; -import it.pagopa.selfcare.dashboard.web.model.SearchUserDto; -import it.pagopa.selfcare.dashboard.web.model.user.UserResource; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.core.io.Resource; -import org.springframework.http.MediaType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import static org.hamcrest.Matchers.emptyString; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - - -@WebMvcTest(value = {UserController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) -@ContextConfiguration(classes = {UserController.class, WebTestConfig.class}) -class UserControllerTest { - - private static final String BASE_URL = "/v1/users"; - private static final User USER_RESOURCE; - - static { - USER_RESOURCE = TestUtils.mockInstance(new User()); - USER_RESOURCE.setId(UUID.randomUUID().toString()); - Map workContacts = new HashMap<>(); - WorkContact workContact = TestUtils.mockInstance(new WorkContact()); - workContact.getEmail().setCertification(Certification.SPID); - workContacts.put("institutionId", workContact); - USER_RESOURCE.setWorkContacts(workContacts); - } - - @Autowired - protected MockMvc mvc; - - @Autowired - protected ObjectMapper mapper; - - @MockBean - private UserService userServiceMock; - - - @Test - void search_notNull() throws Exception { - //given - String externalId = "externalId"; - String institutionId = "institutionId"; - SearchUserDto externalIdDto = new SearchUserDto(); - externalIdDto.setFiscalCode(externalId); - Mockito.when(userServiceMock.search(Mockito.anyString())) - .thenReturn(USER_RESOURCE); - //when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .post(BASE_URL + "/search") - .queryParam("institutionId", institutionId) - .content(mapper.writeValueAsString(externalIdDto)) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()) - .andReturn(); - //then - UserResource userResponse = mapper.readValue(result.getResponse().getContentAsString(), UserResource.class); - assertNotNull(userResponse); - Mockito.verify(userServiceMock, Mockito.times(1)) - .search(externalId); - Mockito.verifyNoMoreInteractions(userServiceMock); - } - - @Test - void updateUser(@Value("classpath:stubs/updateUserDto.json") Resource updateUserDto) throws Exception { - //given - UUID id = UUID.randomUUID(); - String institutionId = "institutionId"; - //when - mvc.perform(MockMvcRequestBuilders - .put(BASE_URL + "/{id}", id) - .queryParam("institutionId", institutionId) - .content(updateUserDto.getInputStream().readAllBytes()) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isNoContent()) - .andExpect(content().string(emptyString())); - //then - verify(userServiceMock, times(1)) - .updateUser(eq(id), eq(institutionId), any(MutableUserFieldsDto.class)); - Mockito.verifyNoMoreInteractions(userServiceMock); - } - - - @Test - void getUserByInternalId() throws Exception { - //given - UUID id = UUID.randomUUID(); - String institutionId = "institutionId"; - Mockito.when(userServiceMock.getUserByInternalId(Mockito.any())) - .thenReturn(USER_RESOURCE); - //when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .get(BASE_URL + "/{id}", id) - .queryParam("institutionId", institutionId) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()) - .andReturn(); - //then - UserResource userResponse = mapper.readValue(result.getResponse().getContentAsString(), UserResource.class); - assertNotNull(userResponse); - assertEquals(USER_RESOURCE.getWorkContacts().get(institutionId).getEmail().getValue(), userResponse.getEmail().getValue()); - Mockito.verify(userServiceMock, Mockito.times(1)) - .getUserByInternalId(id); - Mockito.verifyNoMoreInteractions(userServiceMock); - } - - @Test - void saveUser(@Value("classpath:stubs/userDto.json") Resource userDto) throws Exception { - //given - String institutionId = "institutionId"; - UserId id = TestUtils.mockInstance(new UserId()); - Mockito.when(userServiceMock.saveUser(Mockito.anyString(), Mockito.any())) - .thenReturn(id); - //when - mvc.perform(MockMvcRequestBuilders - .post(BASE_URL + "/") - .content(userDto.getInputStream().readAllBytes()) - .queryParam("institutionId", institutionId) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isCreated()) - .andExpect(content().contentType(APPLICATION_JSON)) - .andExpect(jsonPath("$.id", is(id.getId().toString()))); - //then - verify(userServiceMock, times(1)) - .saveUser(eq(institutionId), any(SaveUserDto.class)); - Mockito.verifyNoMoreInteractions(userServiceMock); - } - - - @Test - void deleteUserById() throws Exception { - //given - UUID id = UUID.randomUUID(); - //when - MvcResult result = mvc.perform(MockMvcRequestBuilders - .delete(BASE_URL + "/{id}", id) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isNoContent()) - .andReturn(); - //then - assertEquals(0, result.getResponse().getContentLength()); - Mockito.verify(userServiceMock, Mockito.times(1)) - .deleteById(id.toString()); - Mockito.verifyNoMoreInteractions(userServiceMock); - } - -} \ No newline at end of file diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceTest.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceTest.java deleted file mode 100644 index e86561b93..000000000 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceTest.java +++ /dev/null @@ -1,943 +0,0 @@ -package it.pagopa.selfcare.dashboard.web.security; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; -import io.jsonwebtoken.Jwts; -import it.pagopa.selfcare.commons.base.security.ProductGrantedAuthority; -import it.pagopa.selfcare.commons.base.security.SelfCareGrantedAuthority; -import it.pagopa.selfcare.commons.base.security.SelfCareUser; -import it.pagopa.selfcare.commons.web.security.JwtService; -import it.pagopa.selfcare.dashboard.connector.api.ProductsConnector; -import it.pagopa.selfcare.dashboard.connector.model.groups.UserGroupInfo; -import it.pagopa.selfcare.dashboard.connector.model.institution.InstitutionInfo; -import it.pagopa.selfcare.dashboard.connector.model.product.ProductTree; -import it.pagopa.selfcare.dashboard.connector.model.user.CertifiedField; -import it.pagopa.selfcare.dashboard.connector.model.user.User; -import it.pagopa.selfcare.dashboard.connector.model.user.UserInfo; -import it.pagopa.selfcare.dashboard.connector.model.user.WorkContact; -import it.pagopa.selfcare.dashboard.core.InstitutionService; -import it.pagopa.selfcare.dashboard.core.UserGroupService; -import it.pagopa.selfcare.dashboard.core.UserService; -import it.pagopa.selfcare.dashboard.web.config.ExchangeTokenProperties; -import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; -import it.pagopa.selfcare.onboarding.common.PartyRole; -import it.pagopa.selfcare.product.entity.Product; -import it.pagopa.selfcare.product.entity.ProductRole; -import it.pagopa.selfcare.product.entity.ProductRoleInfo; -import lombok.Getter; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.function.Executable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.Pageable; -import org.springframework.security.authentication.TestingAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.test.context.TestSecurityContextHolder; -import org.springframework.util.ResourceUtils; -import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; -import uk.org.webcompere.systemstubs.jupiter.SystemStub; -import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; - -import java.io.File; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.security.KeyFactory; -import java.security.PublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.time.Instant; -import java.util.*; - -import static it.pagopa.selfcare.commons.base.security.PartyRole.MANAGER; -import static it.pagopa.selfcare.commons.utils.TestUtils.checkNotNullFields; -import static it.pagopa.selfcare.commons.utils.TestUtils.mockInstance; -import static java.util.Collections.emptyList; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.springframework.data.support.PageableExecutionUtils.getPage; - -@ExtendWith({MockitoExtension.class, SystemStubsExtension.class}) -class ExchangeTokenServiceTest { - - @SystemStub - private EnvironmentVariables environmentVariables; - - - @BeforeEach - void cleanContext() { - TestSecurityContextHolder.clearContext(); - environmentVariables.set("TOKEN_EXCHANGE_BILLING_URL", "http://localhost:8080/#selfcareToken="); - environmentVariables.set("TOKEN_EXCHANGE_BILLING_AUDIENCE", "test"); - } - - - @Test - void exchange_illegalBase64Signature() { - // given - String jwtSigningKey = "invalid signature"; - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - // when - Executable executable = () -> new ExchangeTokenService(null, null, null, null, properties, null); - // then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertTrue(e.getMessage().startsWith("Illegal base64")); - } - - - @Test - void exchange_cannotParsePKCS8Key() { - // given - String jwtSigningKey = "-----BEGIN PRIVATE KEY-----" - + Base64.getEncoder().encodeToString("invalid signature".getBytes()) - + "-----END PRIVATE KEY-----"; - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - // when - Executable executable = () -> new ExchangeTokenService(null, null, null, null, properties, null); - // then - assertThrows(InvalidKeySpecException.class, executable); - } - - - @Test - void exchange_cannotParsePKCS1Key() { - // given - String jwtSigningKey = "-----BEGIN RSA PRIVATE KEY-----" - + Base64.getEncoder().encodeToString("invalid signature".getBytes()) - + "-----END RSA PRIVATE KEY-----"; - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - // when - Executable executable = () -> new ExchangeTokenService(null, null, null, null, properties, null); - // then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertTrue(e.getMessage().startsWith("failed to construct sequence from byte[]")); - } - - - @Test - void exchange_noAuth() throws Exception { - // given - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, null, null, null, properties, null); - // when - Executable executable = () -> exchangeTokenService.exchange(null, null, null); - // then - IllegalStateException e = assertThrows(IllegalStateException.class, executable); - assertEquals("Authentication is required", e.getMessage()); - verifyNoInteractions(jwtServiceMock); - } - - - @Test - void exchange_noSelfCareAuth() throws Exception { - // given - String institutionId = null; - String productId = null; - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - JwtService jwtServiceMock = mock(JwtService.class); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, null, null, null, properties, null); - TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", "password"); - TestSecurityContextHolder.setAuthentication(authentication); - // when - Executable executable = () -> exchangeTokenService.exchange(institutionId, productId, null); - // then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A Product Granted SelfCareAuthority is required for product '" + productId + "' and institution '" + institutionId + "'", e.getMessage()); - verifyNoInteractions(jwtServiceMock); - } - - - @Test - void exchange_SelfCareAuthOnDifferentInstId() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - JwtService jwtServiceMock = mock(JwtService.class); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, null, null, null, properties, null); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", productId)); - List authorities = List.of(new SelfCareGrantedAuthority("differentInstitutionId", roleOnProducts)); - TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - // when - Executable executable = () -> exchangeTokenService.exchange(institutionId, productId, null); - // then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A Product Granted SelfCareAuthority is required for product '" + productId + "' and institution '" + institutionId + "'", e.getMessage()); - verifyNoInteractions(jwtServiceMock); - } - - - @Test - void exchange_SelfCareAuthOnDifferentProductId() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - JwtService jwtServiceMock = mock(JwtService.class); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, null, null, null, properties, null); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", "differentProductId")); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - // when - Executable executable = () -> exchangeTokenService.exchange(institutionId, productId, null); - // then - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("A Product Granted SelfCareAuthority is required for product '" + productId + "' and institution '" + institutionId + "'", e.getMessage()); - verifyNoInteractions(jwtServiceMock); - } - - - @Test - void exchange_noSessionTokenClaims() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(null); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - - InstitutionService institutionServiceMock = mock(InstitutionService.class); - InstitutionInfo institutionInfo = mockInstance(new InstitutionInfo()); - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - final Pageable pageable = Pageable.ofSize(100); - UserGroupService groupServiceMock = mock(UserGroupService.class); - UserGroupInfo groupInfo = mockInstance(new UserGroupInfo()); - UserInfo user = mockInstance(new UserInfo()); - user.setId(userId.toString()); - groupInfo.setMembers(List.of(user)); - final List groupInfos = new ArrayList<>(pageable.getPageSize()); - for (int i = 0; i < pageable.getPageSize(); i++) { - groupInfos.add(groupInfo); - } - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(groupInfos, invocation.getArgument(3, Pageable.class), () -> pageable.getPageSize() + 1)); - - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, null, properties, null); - - // when - Executable executable = () -> exchangeTokenService.exchange(institutionId, productId, null); - // then - RuntimeException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("Session token claims is required", e.getMessage()); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verifyNoMoreInteractions(jwtServiceMock); - } - - - @Test - void exchange_noInstitutionInfo() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - String jti = "id"; - String sub = "subject"; - Date iat = Date.from(Instant.now().minusSeconds(1)); - Date exp = Date.from(iat.toInstant().plusSeconds(5)); - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - UserGroupService groupServiceMock = mock(UserGroupService.class); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, null); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - // when - Executable executable = () -> exchangeTokenService.exchange(institutionId, productId, null); - // then - RuntimeException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("Institution info is required", e.getMessage()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock); - } - - @ParameterizedTest - @EnumSource(PrivateKey.class) - void exchange_nullGroupInfo(PrivateKey privateKey) throws Exception { - // given - String realm = "identityTokenAudienceFromProduct"; - String jti = "id"; - String sub = "subject"; - Date iat = Date.from(Instant.now().minusSeconds(1)); - Date exp = Date.from(iat.toInstant().plusSeconds(5)); - String institutionId = "institutionId"; - String productId = "productId"; - String productRole = "productRole"; - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, productRole, productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - Product product = new Product(); - ProductRoleInfo productRoleInfo = new ProductRoleInfo(); - ProductRole productRole1 = mockInstance(new ProductRole(), 1, "setCode"); - productRole1.setCode(productRole); - productRoleInfo.setRoles(List.of(productRole1)); - EnumMap roleMappings = new EnumMap<>(PartyRole.class); - roleMappings.put(PartyRole.OPERATOR, productRoleInfo); - product.setRoleMappings(roleMappings); - product.setIdentityTokenAudience(realm); - when(productsConnectorMock.getProduct(Mockito.anyString())) - .thenReturn(product); - - TestSecurityContextHolder.setAuthentication(authentication); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(Jwts.claims() - .setId(jti) - .setSubject(sub) - .setIssuedAt(iat) - .setExpiration(exp)); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - InstitutionInfo institutionInfo = new InstitutionInfo(); - institutionInfo.setDescription("description"); - institutionInfo.setTaxCode("taxCode"); - institutionInfo.setSubunitCode("subunitCode"); - institutionInfo.setSubunitType("subunitType"); - institutionInfo.setAooParentCode("AOO"); - institutionInfo.setParentDescription("parentDescription"); - institutionInfo.setOriginId("id"); - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - UserGroupService groupServiceMock = mock(UserGroupService.class); - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(emptyList(), invocation.getArgument(3, Pageable.class), () -> 0L)); - File file = ResourceUtils.getFile(privateKey.getResourceLocation()); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - String kid = "kid"; - properties.setDuration("PT5S"); - properties.setKid(kid); - environmentVariables.set("JWT_TOKEN_EXCHANGE_ISSUER", "https://dev.selfcare.pagopa.it"); - String issuer = "https://dev.selfcare.pagopa.it"; - properties.setIssuer(issuer); - UserService userService = mock(UserService.class); - User user = new User(); - user.setId(UUID.randomUUID().toString()); - Map workContactMap = new HashMap<>(); - WorkContact contact = new WorkContact(); - CertifiedField email = new CertifiedField<>(); - email.setValue("email"); - contact.setEmail(email); - workContactMap.put(institutionId, contact); - user.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(user); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService); - // when - final ExchangedToken exchangedToken = exchangeTokenService.exchange(institutionId, productId, Optional.empty()); - // then - assertEquals(product.getUrlBO(), exchangedToken.getBackOfficeUrl()); - assertNotNull(exchangedToken.getIdentityToken()); - Jws claimsJws = Jwts.parser() - .setSigningKey(loadPublicKey()) - .parseClaimsJws(exchangedToken.getIdentityToken()); - assertNotNull(claimsJws); - assertNotNull(claimsJws.getHeader()); - assertEquals(kid, claimsJws.getHeader().getKeyId()); - TestTokenExchangeClaims exchangedClaims = new TestTokenExchangeClaims(claimsJws.getBody()); - assertNotEquals(jti, exchangedClaims.getId()); - assertNotEquals(0, exp.compareTo(exchangedClaims.getExpiration())); - assertEquals(sub, exchangedClaims.getSubject()); - assertEquals(issuer, exchangedClaims.getIssuer()); - assertEquals(realm, exchangedClaims.getAudience()); - // https://github.com/jwtk/jjwt/issues/122: - // The JWT RFC *mandates* NumericDate values are represented as seconds. - // Because java.util.Date requires milliseconds, we need to multiply by 1000: - assertEquals(exp.toInstant().getEpochSecond(), exchangedClaims.getDesiredExpiration().toInstant().getEpochSecond()); - assertTrue(exchangedClaims.getIssuedAt().after(iat)); - assertTrue(exchangedClaims.getExpiration().after(exp)); - assertTrue(exchangedClaims.getExpiration().after(exchangedClaims.getIssuedAt())); - ExchangeTokenService.Institution institution = exchangedClaims.getInstitution(); - assertNotNull(institution); - assertNull(institution.getGroups()); - assertEquals(institutionId, institution.getId()); - assertEquals(institutionInfo.getTaxCode(), institution.getTaxCode()); - assertNotNull(institution.getRoles()); - assertEquals(1, institution.getRoles().size()); - assertFalse(exchangedClaims.containsKey("groups")); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verify(groupServiceMock, times(1)) - .getUserGroups(Optional.of(institutionId), Optional.of(productId), Optional.of(userId), Pageable.ofSize(100)); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock, groupServiceMock); - } - - - @ParameterizedTest - @EnumSource(PrivateKey.class) - void exchange_ok(PrivateKey privateKey) throws Exception { - // given - String realm = "identityTokenAudienceFromProduct"; - String jti = "id"; - String sub = "subject"; - Date iat = Date.from(Instant.now().minusSeconds(1)); - Date exp = Date.from(iat.toInstant().plusSeconds(5)); - String institutionId = "institutionId"; - String productId = "productId"; - String productRole = "productRole"; - final Pageable pageable = Pageable.ofSize(100); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, productRole, productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(Jwts.claims() - .setId(jti) - .setSubject(sub) - .setIssuedAt(iat) - .setExpiration(exp)); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - UserService userService = mock(UserService.class); - InstitutionInfo institutionInfo = new InstitutionInfo(); - institutionInfo.setDescription("description"); - institutionInfo.setTaxCode("taxCode"); - institutionInfo.setSubunitCode("subunitCode"); - institutionInfo.setSubunitType("subunitType"); - institutionInfo.setAooParentCode("AOO"); - institutionInfo.setParentDescription("parentDescription"); - institutionInfo.setOriginId("id"); - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - UserGroupService groupServiceMock = mock(UserGroupService.class); - UserGroupInfo groupInfo = new UserGroupInfo(); - groupInfo.setId("id"); - UserInfo user = new UserInfo(); - user.setId(userId.toString()); - groupInfo.setMembers(List.of(user)); - final List groupInfos = new ArrayList<>(pageable.getPageSize()); - for (int i = 0; i < pageable.getPageSize(); i++) { - groupInfos.add(groupInfo); - } - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(groupInfos, invocation.getArgument(3, Pageable.class), () -> pageable.getPageSize() + 1)); - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - Product product = new Product(); - ProductRoleInfo productRoleInfo = new ProductRoleInfo(); - ProductRole productRole1 = new ProductRole(); - productRole1.setCode(productRole); - productRoleInfo.setRoles(List.of(productRole1)); - EnumMap roleMappings = new EnumMap<>(PartyRole.class); - roleMappings.put(PartyRole.OPERATOR, productRoleInfo); - product.setRoleMappings(roleMappings); - product.setIdentityTokenAudience(realm); - when(productsConnectorMock.getProduct(Mockito.anyString())) - .thenReturn(product); - File file = ResourceUtils.getFile(privateKey.getResourceLocation()); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - String kid = "kid"; - environmentVariables.set("JWT_TOKEN_EXCHANGE_ISSUER", "https://dev.selfcare.pagopa.it"); - String issuer = "https://dev.selfcare.pagopa.it"; - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setKid(kid); - properties.setDuration("PT5S"); - properties.setIssuer(issuer); - User pdvUser = new User(); - pdvUser.setId(UUID.randomUUID().toString()); - Map workContactMap = new HashMap<>(); - WorkContact contact = new WorkContact(); - CertifiedField email = new CertifiedField<>(); - email.setValue("email"); - contact.setEmail(email); - workContactMap.put(institutionId, contact); - pdvUser.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(pdvUser); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService); - // when - final ExchangedToken exchangedToken = exchangeTokenService.exchange(institutionId, productId, Optional.empty()); - // then - assertEquals(product.getUrlBO(), exchangedToken.getBackOfficeUrl()); - assertNotNull(exchangedToken.getIdentityToken()); - Jws claimsJws = Jwts.parser() - .setSigningKey(loadPublicKey()) - .parseClaimsJws(exchangedToken.getIdentityToken()); - assertNotNull(claimsJws); - assertNotNull(claimsJws.getHeader()); - assertEquals(kid, claimsJws.getHeader().getKeyId()); - TestTokenExchangeClaims exchangedClaims = new TestTokenExchangeClaims(claimsJws.getBody()); - assertNotEquals(jti, exchangedClaims.getId()); - assertNotEquals(0, exp.compareTo(exchangedClaims.getExpiration())); - assertEquals(sub, exchangedClaims.getSubject()); - assertEquals(issuer, exchangedClaims.getIssuer()); - assertEquals(realm, exchangedClaims.getAudience()); - // https://github.com/jwtk/jjwt/issues/122: - // The JWT RFC *mandates* NumericDate values are represented as seconds. - // Because java.util.Date requires milliseconds, we need to multiply by 1000: - assertEquals(exp.toInstant().getEpochSecond(), exchangedClaims.getDesiredExpiration().toInstant().getEpochSecond()); - assertTrue(exchangedClaims.getIssuedAt().after(iat)); - assertTrue(exchangedClaims.getExpiration().after(exp)); - assertTrue(exchangedClaims.getExpiration().after(exchangedClaims.getIssuedAt())); - ExchangeTokenService.Institution institution = exchangedClaims.getInstitution(); - assertNotNull(institution); - assertEquals(institutionInfo.getDescription(), institution.getName()); - assertEquals(institutionId, institution.getId()); - checkNotNullFields(institution); - assertEquals(1, institution.getRoles().size()); - List groups = institution.getGroups(); - assertEquals(pageable.getPageSize(), groups.size()); - assertTrue(groups.stream().allMatch(groupId -> groupId.equals(groupInfo.getId()))); - assertEquals(institutionInfo.getTaxCode(), institution.getTaxCode()); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verify(groupServiceMock, times(1)) - .getUserGroups(Optional.of(institutionId), Optional.of(productId), Optional.of(userId), Pageable.ofSize(100)); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock, groupServiceMock); - } - - @Test - void billingExchange_noAuth() throws Exception { - // given - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, null, null, null, properties, null); - // when - Executable executable = () -> exchangeTokenService.retrieveBillingExchangedToken(null); - // then - IllegalStateException e = assertThrows(IllegalStateException.class, executable); - assertEquals("Authentication is required", e.getMessage()); - verifyNoInteractions(jwtServiceMock); - } - - @Test - void billingExchange_noSessionTokenClaims() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(null); - ProductsConnector productsConnector = mock(ProductsConnector.class); - ProductTree productTree = new ProductTree(); - Product product = new Product(); - product.setId("prod-io"); - productTree.setNode(product); - when(productsConnector.getProductsTree()).thenReturn(List.of(productTree)); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - InstitutionInfo institutionInfo = mockInstance(new InstitutionInfo()); - UserGroupService groupServiceMock = mock(UserGroupService.class); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - - UserGroupInfo groupInfo = mockInstance(new UserGroupInfo()); - UserInfo user = mockInstance(new UserInfo()); - user.setId(userId.toString()); - groupInfo.setMembers(List.of(user)); - final Pageable pageable = Pageable.ofSize(100); - final List groupInfos = new ArrayList<>(pageable.getPageSize()); - for (int i = 0; i < pageable.getPageSize(); i++) { - groupInfos.add(groupInfo); - } - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(groupInfos, invocation.getArgument(3, Pageable.class), () -> pageable.getPageSize() + 1)); - - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnector, properties, null); - - Executable executable = () -> exchangeTokenService.retrieveBillingExchangedToken(institutionId); - // then - RuntimeException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("Session token claims is required", e.getMessage()); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verifyNoMoreInteractions(jwtServiceMock); - } - - - @Test - void billingExchange_noInstitutionInfo() throws Exception { - // given - String institutionId = "institutionId"; - String productId = "productId"; - - File file = ResourceUtils.getFile("classpath:certs/PKCS8key.pem"); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setDuration("PT5S"); - JwtService jwtServiceMock = mock(JwtService.class); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - UserGroupService groupServiceMock = mock(UserGroupService.class); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, null); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, "productRole", productId)); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - // when - Executable executable = () -> exchangeTokenService.retrieveBillingExchangedToken(institutionId); - // then - RuntimeException e = assertThrows(IllegalArgumentException.class, executable); - assertEquals("Institution info is required", e.getMessage()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock); - } - - @ParameterizedTest - @EnumSource(PrivateKey.class) - void billingExchange_nullGroupInfo(PrivateKey privateKey) throws Exception { - // given - String jti = "id"; - String sub = "subject"; - Date iat = Date.from(Instant.now().minusSeconds(1)); - Date exp = Date.from(iat.toInstant().plusSeconds(5)); - String institutionId = "institutionId"; - String productRole = "productRole"; - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, productRole, "productId")); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - Product product = new Product(); - ProductRoleInfo productRoleInfo = new ProductRoleInfo(); - ProductRole productRole1 = new ProductRole(); - productRole1.setCode(productRole); - productRoleInfo.setRoles(List.of(productRole1)); - EnumMap roleMappings = new EnumMap<>(PartyRole.class); - roleMappings.put(PartyRole.OPERATOR, productRoleInfo); - product.setRoleMappings(roleMappings); - ProductTree productTree = new ProductTree(); - productTree.setNode(product); - when(productsConnectorMock.getProductsTree()).thenReturn(List.of(productTree)); - - TestSecurityContextHolder.setAuthentication(authentication); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(Jwts.claims() - .setId(jti) - .setSubject(sub) - .setIssuedAt(iat) - .setExpiration(exp)); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - InstitutionInfo institutionInfo = new InstitutionInfo(); - institutionInfo.setDescription("description"); - institutionInfo.setTaxCode("taxCode"); - institutionInfo.setSubunitCode("subunitCode"); - institutionInfo.setSubunitType("subunitType"); - institutionInfo.setAooParentCode("AOO"); - institutionInfo.setParentDescription("parentDescription"); - institutionInfo.setOriginId("id"); - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - UserGroupService groupServiceMock = mock(UserGroupService.class); - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(emptyList(), invocation.getArgument(3, Pageable.class), () -> 0L)); - File file = ResourceUtils.getFile(privateKey.getResourceLocation()); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - String kid = "kid"; - properties.setDuration("PT5S"); - properties.setKid(kid); - environmentVariables.set("JWT_TOKEN_EXCHANGE_ISSUER", "https://dev.selfcare.pagopa.it"); - environmentVariables.set("TOKEN_EXCHANGE_BILLING_URL", "http://localhost:8080/#selfcareToken="); - environmentVariables.set("TOKEN_EXCHANGE_BILLING_AUDIENCE", "test"); - String issuer = "https://dev.selfcare.pagopa.it"; - properties.setIssuer(issuer); - properties.setBillingUrl("http://localhost:8080/#selfcareToken="); - UserService userService = mock(UserService.class); - User user = new User(); - user.setId(UUID.randomUUID().toString()); - Map workContactMap = new HashMap<>(); - WorkContact contact = new WorkContact(); - CertifiedField email = new CertifiedField<>(); - email.setValue("email"); - contact.setEmail(email); - workContactMap.put(institutionId, contact); - user.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(user); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService); - // when - final ExchangedToken exchangedToken = exchangeTokenService.retrieveBillingExchangedToken(institutionId); - // then - assertNotNull(exchangedToken.getIdentityToken()); - Jws claimsJws = Jwts.parser() - .setSigningKey(loadPublicKey()) - .parseClaimsJws(exchangedToken.getIdentityToken()); - assertNotNull(claimsJws); - assertNotNull(claimsJws.getHeader()); - assertEquals(kid, claimsJws.getHeader().getKeyId()); - TestTokenExchangeClaims exchangedClaims = new TestTokenExchangeClaims(claimsJws.getBody()); - assertNotEquals(jti, exchangedClaims.getId()); - assertNotEquals(0, exp.compareTo(exchangedClaims.getExpiration())); - assertEquals(sub, exchangedClaims.getSubject()); - assertEquals(issuer, exchangedClaims.getIssuer()); - // https://github.com/jwtk/jjwt/issues/122: - // The JWT RFC *mandates* NumericDate values are represented as seconds. - // Because java.util.Date requires milliseconds, we need to multiply by 1000: - assertEquals(exp.toInstant().getEpochSecond(), exchangedClaims.getDesiredExpiration().toInstant().getEpochSecond()); - assertTrue(exchangedClaims.getIssuedAt().after(iat)); - assertTrue(exchangedClaims.getExpiration().after(exp)); - assertTrue(exchangedClaims.getExpiration().after(exchangedClaims.getIssuedAt())); - ExchangeTokenService.Institution institution = exchangedClaims.getInstitution(); - assertNotNull(institution); - assertNull(institution.getGroups()); - assertEquals(institutionId, institution.getId()); - assertEquals(institutionInfo.getTaxCode(), institution.getTaxCode()); - assertNotNull(institution.getRoles()); - assertFalse(exchangedClaims.containsKey("groups")); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verify(groupServiceMock, times(1)) - .getUserGroups(Optional.of(institutionId), Optional.empty(), Optional.of(userId), Pageable.ofSize(100)); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock, groupServiceMock); - } - - - @ParameterizedTest - @EnumSource(PrivateKey.class) - void billingExchange_ok(PrivateKey privateKey) throws Exception { - // given - String jti = "id"; - String sub = "subject"; - Date iat = Date.from(Instant.now().minusSeconds(1)); - Date exp = Date.from(iat.toInstant().plusSeconds(5)); - String institutionId = "institutionId"; - String productRole = "productRole"; - final Pageable pageable = Pageable.ofSize(100); - List roleOnProducts = List.of(new ProductGrantedAuthority(MANAGER, productRole, "productId")); - List authorities = List.of(new SelfCareGrantedAuthority(institutionId, roleOnProducts)); - UUID userId = UUID.randomUUID(); - SelfCareUser selfCareUser = SelfCareUser.builder(userId.toString()).email("test@example.com").build(); - TestingAuthenticationToken authentication = new TestingAuthenticationToken(selfCareUser, "password", authorities); - TestSecurityContextHolder.setAuthentication(authentication); - JwtService jwtServiceMock = mock(JwtService.class); - when(jwtServiceMock.getClaims(any())) - .thenReturn(Jwts.claims() - .setId(jti) - .setSubject(sub) - .setIssuedAt(iat) - .setExpiration(exp)); - InstitutionService institutionServiceMock = mock(InstitutionService.class); - UserService userService = mock(UserService.class); - InstitutionInfo institutionInfo = new InstitutionInfo(); - institutionInfo.setDescription("description"); - institutionInfo.setTaxCode("taxCode"); - institutionInfo.setSubunitCode("subunitCode"); - institutionInfo.setSubunitType("subunitType"); - institutionInfo.setAooParentCode("AOO"); - institutionInfo.setParentDescription("parentDescription"); - institutionInfo.setOriginId("id"); - when(institutionServiceMock.getInstitution(any())) - .thenReturn(institutionInfo); - UserGroupService groupServiceMock = mock(UserGroupService.class); - UserGroupInfo groupInfo = new UserGroupInfo(); - groupInfo.setId("id"); - UserInfo user =new UserInfo(); - user.setId(userId.toString()); - groupInfo.setMembers(List.of(user)); - final List groupInfos = new ArrayList<>(pageable.getPageSize()); - for (int i = 0; i < pageable.getPageSize(); i++) { - groupInfos.add(groupInfo); - } - when(groupServiceMock.getUserGroups(any(), any(), any(), any())) - .thenAnswer(invocation -> getPage(groupInfos, invocation.getArgument(3, Pageable.class), () -> pageable.getPageSize() + 1)); - ProductsConnector productsConnectorMock = mock(ProductsConnector.class); - Product product = new Product(); - ProductRoleInfo productRoleInfo =new ProductRoleInfo(); - ProductRole productRole1 = new ProductRole(); - productRole1.setCode(productRole); - productRoleInfo.setRoles(List.of(productRole1)); - EnumMap roleMappings = new EnumMap<>(PartyRole.class); - roleMappings.put(PartyRole.OPERATOR, productRoleInfo); - product.setRoleMappings(roleMappings); - ProductTree productTree = new ProductTree(); - productTree.setNode(product); - when(productsConnectorMock.getProductsTree()).thenReturn(List.of(productTree)); - File file = ResourceUtils.getFile(privateKey.getResourceLocation()); - String jwtSigningKey = Files.readString(file.toPath(), Charset.defaultCharset()); - String kid = "kid"; - environmentVariables.set("JWT_TOKEN_EXCHANGE_ISSUER", "https://dev.selfcare.pagopa.it"); - String issuer = "https://dev.selfcare.pagopa.it"; - ExchangeTokenProperties properties = new ExchangeTokenProperties(); - properties.setSigningKey(jwtSigningKey); - properties.setKid(kid); - properties.setDuration("PT5S"); - properties.setIssuer(issuer); - User pdvUser = new User(); - pdvUser.setId(UUID.randomUUID().toString()); - Map workContactMap = new HashMap<>(); - WorkContact contact = new WorkContact(); - CertifiedField email = new CertifiedField<>(); - email.setValue("email"); - contact.setEmail(email); - workContactMap.put(institutionId, contact); - pdvUser.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(pdvUser); - ExchangeTokenService exchangeTokenService = new ExchangeTokenService(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService); - // when - final ExchangedToken exchangedToken = exchangeTokenService.retrieveBillingExchangedToken(institutionId); - // then - assertNotNull(exchangedToken.getIdentityToken()); - Jws claimsJws = Jwts.parser() - .setSigningKey(loadPublicKey()) - .parseClaimsJws(exchangedToken.getIdentityToken()); - assertNotNull(claimsJws); - assertNotNull(claimsJws.getHeader()); - assertEquals(kid, claimsJws.getHeader().getKeyId()); - TestTokenExchangeClaims exchangedClaims = new TestTokenExchangeClaims(claimsJws.getBody()); - assertNotEquals(jti, exchangedClaims.getId()); - assertNotEquals(0, exp.compareTo(exchangedClaims.getExpiration())); - assertEquals(sub, exchangedClaims.getSubject()); - assertEquals(issuer, exchangedClaims.getIssuer()); - // https://github.com/jwtk/jjwt/issues/122: - // The JWT RFC *mandates* NumericDate values are represented as seconds. - // Because java.util.Date requires milliseconds, we need to multiply by 1000: - assertEquals(exp.toInstant().getEpochSecond(), exchangedClaims.getDesiredExpiration().toInstant().getEpochSecond()); - assertTrue(exchangedClaims.getIssuedAt().after(iat)); - assertTrue(exchangedClaims.getExpiration().after(exp)); - assertTrue(exchangedClaims.getExpiration().after(exchangedClaims.getIssuedAt())); - ExchangeTokenService.Institution institution = exchangedClaims.getInstitution(); - assertNotNull(institution); - assertEquals(institutionInfo.getDescription(), institution.getName()); - assertEquals(institutionId, institution.getId()); - checkNotNullFields(institution); - List groups = institution.getGroups(); - assertEquals(pageable.getPageSize(), groups.size()); - assertTrue(groups.stream().allMatch(groupId -> groupId.equals(groupInfo.getId()))); - assertEquals(institutionInfo.getTaxCode(), institution.getTaxCode()); - verify(jwtServiceMock, times(1)) - .getClaims(any()); - verify(institutionServiceMock, times(1)) - .getInstitution(institutionId); - verify(groupServiceMock, times(1)) - .getUserGroups(Optional.of(institutionId), Optional.empty(), Optional.of(userId), Pageable.ofSize(100)); - verifyNoMoreInteractions(jwtServiceMock, institutionServiceMock, groupServiceMock); - } - - - private PublicKey loadPublicKey() throws Exception { - File file = ResourceUtils.getFile("classpath:certs/pubkey.pem"); - String key = Files.readString(file.toPath(), Charset.defaultCharset()); - - String publicKeyPEM = key - .replace("-----BEGIN PUBLIC KEY-----", "") - .replaceAll(System.lineSeparator(), "") - .replace("-----END PUBLIC KEY-----", ""); - - byte[] encoded = Base64.getMimeDecoder().decode(publicKeyPEM); - - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); - return keyFactory.generatePublic(keySpec); - } - - - private static class TestTokenExchangeClaims extends ExchangeTokenService.TokenExchangeClaims { - - public TestTokenExchangeClaims(Map map) { - super(map); - } - - public Date getDesiredExpiration() { - return getDate(DESIRED_EXPIRATION); - } - - public ExchangeTokenService.Institution getInstitution() { - LinkedHashMap organizationClaim = (LinkedHashMap) get(INSTITUTION); - ExchangeTokenService.Institution institution = new ExchangeTokenService.Institution(); - institution.setId(organizationClaim.get("id").toString()); - institution.setRoles((List) organizationClaim.get("roles")); - institution.setName(organizationClaim.get("name").toString()); - institution.setTaxCode(organizationClaim.get("fiscal_code").toString()); - institution.setGroups((List) organizationClaim.get("groups")); - institution.setSubUnitCode(organizationClaim.get("subUnitCode").toString()); - institution.setSubUnitType(organizationClaim.get("subUnitType").toString()); - institution.setAooParent(organizationClaim.get("aooParent").toString()); - institution.setParentDescription(organizationClaim.get("parentDescription").toString()); - institution.setOriginId(organizationClaim.get("ipaCode").toString()); - ExchangeTokenService.RootParent rootParent = new ExchangeTokenService.RootParent(); - rootParent.setDescription(organizationClaim.get("parentDescription").toString()); - institution.setRootParent(rootParent); - return institution; - } - - } - - - @Getter - private enum PrivateKey { - PKCS1("classpath:certs/PKCS1Key.pem"), - PKCS8("classpath:certs/PKCS8key.pem"); - - private String resourceLocation; - - PrivateKey(String resourceLocation) { - this.resourceLocation = resourceLocation; - } - } - -} diff --git a/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2Test.java b/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2Test.java index 3c4e2654a..1adfe9ec0 100644 --- a/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2Test.java +++ b/web/src/test/java/it/pagopa/selfcare/dashboard/web/security/ExchangeTokenServiceV2Test.java @@ -16,7 +16,7 @@ import it.pagopa.selfcare.dashboard.connector.model.user.*; import it.pagopa.selfcare.dashboard.core.InstitutionService; import it.pagopa.selfcare.dashboard.core.UserGroupService; -import it.pagopa.selfcare.dashboard.core.UserService; +import it.pagopa.selfcare.dashboard.core.UserV2Service; import it.pagopa.selfcare.dashboard.web.config.ExchangeTokenProperties; import it.pagopa.selfcare.dashboard.web.model.ExchangedToken; import it.pagopa.selfcare.dashboard.web.model.mapper.InstitutionResourceMapperImpl; @@ -387,7 +387,7 @@ void exchange_nullGroupInfo(PrivateKey privateKey) throws Exception { environmentVariables.set("JWT_TOKEN_EXCHANGE_ISSUER", "https://dev.selfcare.pagopa.it"); String issuer = "https://dev.selfcare.pagopa.it"; properties.setIssuer(issuer); - UserService userService = mock(UserService.class); + UserV2Service UserV2Service = mock(UserV2Service.class); User user = new User(); user.setId(UUID.randomUUID().toString()); Map workContactMap = new HashMap<>(); @@ -397,7 +397,7 @@ void exchange_nullGroupInfo(PrivateKey privateKey) throws Exception { contact.setEmail(email); workContactMap.put(institutionId, contact); user.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(user); + when(UserV2Service.getUserById(any(), any(), any())).thenReturn(user); OnboardedProduct onboardedProduct = new OnboardedProduct(); onboardedProduct.setRole(MANAGER); @@ -429,7 +429,7 @@ void exchange_nullGroupInfo(PrivateKey privateKey) throws Exception { UserApiConnector userApiConnector = mock(UserApiConnector.class); when(userApiConnector.getProducts(anyString(), anyString())).thenReturn(userInstitution); - ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService, userApiConnector, new InstitutionResourceMapperImpl()); + ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, UserV2Service, userApiConnector, new InstitutionResourceMapperImpl()); // when final ExchangedToken exchangedToken = ExchangeTokenServiceV2.exchange(institutionId, productId, Optional.empty()); // then @@ -499,7 +499,7 @@ void exchange_ok(PrivateKey privateKey) throws Exception { .setIssuedAt(iat) .setExpiration(exp)); InstitutionService institutionServiceMock = mock(InstitutionService.class); - UserService userService = mock(UserService.class); + UserV2Service UserV2Service = mock(UserV2Service.class); Institution institutionInfo = new Institution(); institutionInfo.setId(institutionId); institutionInfo.setDescription("description"); @@ -553,7 +553,7 @@ void exchange_ok(PrivateKey privateKey) throws Exception { contact.setEmail(email); workContactMap.put(institutionId, contact); pdvUser.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(pdvUser); + when(UserV2Service.getUserById(any(), any(), any())).thenReturn(pdvUser); OnboardedProduct onboardedProduct = new OnboardedProduct(); onboardedProduct.setRole(MANAGER); @@ -586,7 +586,7 @@ void exchange_ok(PrivateKey privateKey) throws Exception { when( institutionServiceMock.getInstitutionById(any())).thenReturn(institutionMock); UserApiConnector userApiConnector = mock(UserApiConnector.class); when(userApiConnector.getProducts(anyString(), anyString())).thenReturn(userInstitution); - ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService, userApiConnector, new InstitutionResourceMapperImpl()); + ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, UserV2Service, userApiConnector, new InstitutionResourceMapperImpl()); // when final ExchangedToken exchangedToken = ExchangeTokenServiceV2.exchange(institutionId, productId, Optional.empty()); // then @@ -822,7 +822,7 @@ void billingExchange_nullGroupInfo(PrivateKey privateKey) throws Exception { String issuer = "https://dev.selfcare.pagopa.it"; properties.setIssuer(issuer); properties.setBillingUrl("http://localhost:8080/#selfcareToken="); - UserService userService = mock(UserService.class); + UserV2Service UserV2Service = mock(UserV2Service.class); User user = new User(); user.setId(UUID.randomUUID().toString()); Map workContactMap = new HashMap<>(); @@ -832,7 +832,7 @@ void billingExchange_nullGroupInfo(PrivateKey privateKey) throws Exception { contact.setEmail(email); workContactMap.put(institutionId, contact); user.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(user); + when(UserV2Service.getUserById(any(), any(), any())).thenReturn(user); UserInstitution userInstitution = new UserInstitution(); OnboardedProduct onboardedProduct = new OnboardedProduct(); onboardedProduct.setRole(MANAGER); @@ -843,7 +843,7 @@ void billingExchange_nullGroupInfo(PrivateKey privateKey) throws Exception { UserApiConnector userApiConnector = mock(UserApiConnector.class); when(userApiConnector.getProducts(anyString(), anyString())).thenReturn(userInstitution); - ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService, userApiConnector, new InstitutionResourceMapperImpl()); + ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, UserV2Service, userApiConnector, new InstitutionResourceMapperImpl()); // when final ExchangedToken exchangedToken = ExchangeTokenServiceV2.retrieveBillingExchangedToken(institutionId); // then @@ -908,7 +908,7 @@ void billingExchange_ok(PrivateKey privateKey) throws Exception { .setIssuedAt(iat) .setExpiration(exp)); InstitutionService institutionServiceMock = mock(InstitutionService.class); - UserService userService = mock(UserService.class); + UserV2Service UserV2Service = mock(UserV2Service.class); Institution institutionInfo = new Institution(); institutionInfo.setId(institutionId); institutionInfo.setDescription("description"); @@ -962,13 +962,13 @@ void billingExchange_ok(PrivateKey privateKey) throws Exception { contact.setEmail(email); workContactMap.put(institutionId, contact); pdvUser.setWorkContacts(workContactMap); - when(userService.getUserByInternalId(any())).thenReturn(pdvUser); + when(UserV2Service.getUserById(any(), any(), any())).thenReturn(pdvUser); UserInstitution userInstitution = new UserInstitution(); userInstitution.setProducts(EMPTY_LIST); UserApiConnector userApiConnector = mock(UserApiConnector.class); when(userApiConnector.getProducts(anyString(), anyString())).thenReturn(userInstitution); - ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, userService, userApiConnector, new InstitutionResourceMapperImpl()); + ExchangeTokenServiceV2 ExchangeTokenServiceV2 = new ExchangeTokenServiceV2(jwtServiceMock, institutionServiceMock, groupServiceMock, productsConnectorMock, properties, UserV2Service, userApiConnector, new InstitutionResourceMapperImpl()); // when final ExchangedToken exchangedToken = ExchangeTokenServiceV2.retrieveBillingExchangedToken(institutionId); // then