diff --git a/gradlew.bat b/gradlew.bat index 25da30db..7101f8e4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/openapi/p4pa-auth.openapi.yaml b/openapi/p4pa-auth.openapi.yaml index c3e81420..edd3fa76 100644 --- a/openapi/p4pa-auth.openapi.yaml +++ b/openapi/p4pa-auth.openapi.yaml @@ -9,7 +9,7 @@ paths: /auth/token: post: tags: - - auth + - authn operationId: postToken security: [] parameters: @@ -77,7 +77,7 @@ paths: /auth/userinfo: get: tags: - - auth + - authn operationId: getUserInfo responses: '200': @@ -97,7 +97,7 @@ paths: /auth/revoke: post: tags: - - auth + - authn operationId: logout security: [] parameters: @@ -141,9 +141,9 @@ components: type: string token_type: type: string - default: bearer + default: Bearer expires_in: - type: int + type: integer UserInfo: type: object required: @@ -152,7 +152,7 @@ components: - familyName - name - issuer - - organization + - organizations properties: userId: type: string @@ -164,8 +164,12 @@ components: type: string issuer: type: string - organization: - $ref: components/schemas/UserOrganizationRoles + organizationAccess: + type: string + organizations: + type: array + items: + $ref: '#/components/schemas/UserOrganizationRoles' UserOrganizationRoles: type: object required: diff --git a/postman/p4pa-auth-E2E.postman_collection.json b/postman/p4pa-auth-E2E.postman_collection.json index 92849bc4..382640f0 100644 --- a/postman/p4pa-auth-E2E.postman_collection.json +++ b/postman/p4pa-auth-E2E.postman_collection.json @@ -94,13 +94,15 @@ " pm.expect(jsonResponse).have.property(\"familyName\").to.eq(\"demo\")\r", " pm.expect(jsonResponse).have.property(\"fiscalCode\").to.eq(\"DMEMPY15L21L736U\")\r", " pm.expect(jsonResponse).have.property(\"issuer\").to.eq(pm.environment.get(\"tokenExchange_issuer\"))\r", + " pm.expect(jsonResponse).have.property(\"organizationAccess\").to.eq(\"SELC_99999999990\")\r", "\r", - " pm.expect(jsonResponse.organization).have.property(\"id\")\r", - " pm.expect(jsonResponse.organization).have.property(\"name\").to.eq(\"Ente P4PA intermediato 1\")\r", - " pm.expect(jsonResponse.organization).have.property(\"fiscalCode\").to.eq(\"99999999990\")\r", - " pm.expect(jsonResponse.organization).have.property(\"ipaCode\").to.eq(\"SELC_99999999990\")\r", - " pm.expect(jsonResponse.organization.roles).have.property(\"length\").to.eq(1)\r", - " pm.expect(jsonResponse.organization.roles[0]).to.eq(\"ROLE_ADMIN\")\r", + " pm.expect(jsonResponse.organizations).have.property(\"length\").to.eq(1)\r", + " pm.expect(jsonResponse.organizations[0]).have.property(\"id\")\r", + " pm.expect(jsonResponse.organizations[0]).have.property(\"name\").to.eq(\"Ente P4PA intermediato 1\")\r", + " pm.expect(jsonResponse.organizations[0]).have.property(\"fiscalCode\").to.eq(\"99999999990\")\r", + " pm.expect(jsonResponse.organizations[0]).have.property(\"ipaCode\").to.eq(\"SELC_99999999990\")\r", + " pm.expect(jsonResponse.organizations[0].roles).have.property(\"length\").to.eq(1)\r", + " pm.expect(jsonResponse.organizations[0].roles[0]).to.eq(\"ROLE_ADMIN\")\r", "});" ], "type": "text/javascript", diff --git a/src/main/java/it/gov/pagopa/payhub/auth/controller/AuthControllerImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/controller/AuthControllerImpl.java index f8e6598e..786055f7 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/controller/AuthControllerImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/controller/AuthControllerImpl.java @@ -2,7 +2,7 @@ import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.service.AuthService; -import it.gov.pagopa.payhub.controller.generated.AuthApi; +import it.gov.pagopa.payhub.controller.generated.AuthnApi; import it.gov.pagopa.payhub.model.generated.AccessToken; import it.gov.pagopa.payhub.model.generated.UserInfo; import org.springframework.http.HttpHeaders; @@ -14,7 +14,7 @@ import org.springframework.web.context.request.ServletRequestAttributes; @RestController -public class AuthControllerImpl implements AuthApi { +public class AuthControllerImpl implements AuthnApi { private final AuthService authService; diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenService.java b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenService.java index 8e119e44..9455a364 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenService.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenService.java @@ -1,7 +1,7 @@ -package it.gov.pagopa.payhub.auth.service.exchange; - -import it.gov.pagopa.payhub.model.generated.AccessToken; - -public interface ExchangeTokenService { - AccessToken postToken(String clientId, String grantType, String subjectToken, String subjectIssuer, String subjectTokenType, String scope); -} +package it.gov.pagopa.payhub.auth.service.exchange; + +import it.gov.pagopa.payhub.model.generated.AccessToken; + +public interface ExchangeTokenService { + AccessToken postToken(String clientId, String grantType, String subjectToken, String subjectIssuer, String subjectTokenType, String scope); +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenServiceImpl.java index c9d4c18d..cba772bd 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/ExchangeTokenServiceImpl.java @@ -1,36 +1,36 @@ -package it.gov.pagopa.payhub.auth.service.exchange; - -import com.auth0.jwt.interfaces.Claim; -import it.gov.pagopa.payhub.auth.service.TokenStoreService; -import it.gov.pagopa.payhub.model.generated.AccessToken; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Map; - -@Service -@Slf4j -public class ExchangeTokenServiceImpl implements ExchangeTokenService{ - - private final ValidateExternalTokenService validateExternalTokenService; - private final AccessTokenBuilderService accessTokenBuilderService; - private final TokenStoreService tokenStoreService; - private final IDTokenClaims2UserInfoMapper idTokenClaimsMapper; - - public ExchangeTokenServiceImpl(ValidateExternalTokenService validateExternalTokenService, AccessTokenBuilderService accessTokenBuilderService, TokenStoreService tokenStoreService, IDTokenClaims2UserInfoMapper idTokenClaimsMapper) { - this.validateExternalTokenService = validateExternalTokenService; - this.accessTokenBuilderService = accessTokenBuilderService; - this.tokenStoreService = tokenStoreService; - this.idTokenClaimsMapper = idTokenClaimsMapper; - } - - @Override - public AccessToken postToken(String clientId, String grantType, String subjectToken, String subjectIssuer, String subjectTokenType, String scope) { - log.info("Client {} requested to exchange a {} token provided by {} asking for grant type {} and scope {}", - clientId, subjectTokenType, subjectIssuer, grantType, scope); - Map claims = validateExternalTokenService.validate(clientId, grantType, subjectToken, subjectIssuer, subjectTokenType, scope); - AccessToken accessToken = accessTokenBuilderService.build(); - tokenStoreService.save(accessToken.getAccessToken(), idTokenClaimsMapper.apply(claims)); - return accessToken; - } -} +package it.gov.pagopa.payhub.auth.service.exchange; + +import com.auth0.jwt.interfaces.Claim; +import it.gov.pagopa.payhub.auth.service.TokenStoreService; +import it.gov.pagopa.payhub.model.generated.AccessToken; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +@Slf4j +public class ExchangeTokenServiceImpl implements ExchangeTokenService{ + + private final ValidateExternalTokenService validateExternalTokenService; + private final AccessTokenBuilderService accessTokenBuilderService; + private final TokenStoreService tokenStoreService; + private final IDTokenClaims2UserInfoMapper idTokenClaimsMapper; + + public ExchangeTokenServiceImpl(ValidateExternalTokenService validateExternalTokenService, AccessTokenBuilderService accessTokenBuilderService, TokenStoreService tokenStoreService, IDTokenClaims2UserInfoMapper idTokenClaimsMapper) { + this.validateExternalTokenService = validateExternalTokenService; + this.accessTokenBuilderService = accessTokenBuilderService; + this.tokenStoreService = tokenStoreService; + this.idTokenClaimsMapper = idTokenClaimsMapper; + } + + @Override + public AccessToken postToken(String clientId, String grantType, String subjectToken, String subjectIssuer, String subjectTokenType, String scope) { + log.info("Client {} requested to exchange a {} token provided by {} asking for grant type {} and scope {}", + clientId, subjectTokenType, subjectIssuer, grantType, scope); + Map claims = validateExternalTokenService.validate(clientId, grantType, subjectToken, subjectIssuer, subjectTokenType, scope); + AccessToken accessToken = accessTokenBuilderService.build(); + tokenStoreService.save(accessToken.getAccessToken(), idTokenClaimsMapper.apply(claims)); + return accessToken; + } +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapper.java index 3bd6df0b..26962184 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapper.java @@ -17,13 +17,15 @@ public class IDTokenClaims2UserInfoMapper implements Function @Override public UserInfo apply(Map claims) { try { + UserOrganizationRoles organizationRoles = buildUserOrganizationRoles(claims); return UserInfo.builder() .issuer(claims.get(Claims.ISSUER).asString()) .userId(claims.get("uid").asString()) .name(claims.get("name").asString()) .familyName(claims.get("family_name").asString()) .fiscalCode(claims.get("fiscal_number").asString()) - .organization(buildUserOrganizationRoles(claims)) + .organizationAccess(organizationRoles.getIpaCode()) + .organizations(List.of(organizationRoles)) .build(); } catch (Exception e){ throw new InvalidTokenException("Unexpected IDToken structure", e); diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapperTest.java index 6cfb640c..7fa36ecc 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/exchange/IDTokenClaims2UserInfoMapperTest.java @@ -37,13 +37,14 @@ void givenIDTokenClaimsThenOk() { .familyName("demosurname") .fiscalCode("DMEMPY15L21L736U") .issuer("https://dev.selfcare.pagopa.it") - .organization(UserOrganizationRoles.builder() + .organizationAccess("SELC_99999999990") + .organizations(List.of(UserOrganizationRoles.builder() .id("133e9c1b-dfc5-43ea-98a7-f64f30613074") .name("Ente P4PA intermediato 1") .fiscalCode("99999999990") .ipaCode("SELC_99999999990") .roles(List.of("ROLE_ADMIN")) - .build()) + .build())) .build(); Map claims = JWT.decode("eyJraWQiOiJqd3QtZXhjaGFuZ2VfZTA6OTQ6M2Q6NWI6YWY6ODY6YWU6YWM6YzM6ZGI6OWM6MzI6NTc6NWE6YTA6NDciLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ0eXAiOiJJRCIsImZhbWlseV9uYW1lIjoiZGVtb3N1cm5hbWUiLCJmaXNjYWxfbnVtYmVyIjoiRE1FTVBZMTVMMjFMNzM2VSIsIm5hbWUiOiJkZW1vIiwic3BpZF9sZXZlbCI6Imh0dHBzOi8vd3d3LnNwaWQuZ292Lml0L1NwaWRMMiIsImZyb21fYWEiOmZhbHNlLCJzdWIiOiJlMWQ5YzUzNC04NmE5LTQwMzktODBkYS04YWE3YTMzYWM5ZTciLCJ1aWQiOiJlMWQ5YzUzNC04NmE5LTQwMzktODBkYS04YWE3YTMzYWM5ZTciLCJsZXZlbCI6IkwyIiwiaWF0IjoxNzE0OTgwNTY4LCJleHAiOjU3MTQ5ODE0NjgsImF1ZCI6ImRldi5waWF0dGFmb3JtYXVuaXRhcmlhLnBhZ29wYS5pdCIsImlzcyI6Imh0dHBzOi8vZGV2LnNlbGZjYXJlLnBhZ29wYS5pdCIsImp0aSI6IjkyYzQ3OWI1LTUxMTUtNGQzMS1iMDliLTVjZmFmNTQ1Mzc3NCIsImVtYWlsIjoiZWVAZWUuaXQiLCJvcmdhbml6YXRpb24iOnsiaWQiOiIxMzNlOWMxYi1kZmM1LTQzZWEtOThhNy1mNjRmMzA2MTMwNzQiLCJuYW1lIjoiRW50ZSBQNFBBIGludGVybWVkaWF0byAxIiwicm9sZXMiOlt7InBhcnR5Um9sZSI6IkRFTEVHQVRFIiwicm9sZSI6IlJPTEVfQURNSU4ifV0sImZpc2NhbF9jb2RlIjoiOTk5OTk5OTk5OTAiLCJpcGFDb2RlIjoiU0VMQ185OTk5OTk5OTk5MCJ9LCJkZXNpcmVkX2V4cCI6NTcxNTAxMjg5NH0.I1LBk-69DTROtoLqS5wN3oHC-9W5GBUqiDe907ak5mVNwE00SnMxLFTzTPLfrSCy6zw1PaSx_Xcju2PiK6Xax6gkEz49-LeZ2KFFla1Al1bP35lrO8JRfoo7EefgMNRhXnnYUL6klVIVDpW1hz6G0Lx5p7WZZfU9Kq-hvf8cofkQs3mVIzEF_kvYtrJNug2liZmEzGqwYlgeHE0P3wWPDLKYELHfACiYgw9JMAktPmMsupyyDMfGLfJkZ62z_QovktuFYAqgV6METGwuJP0u3T3XxJy1NspsOudJo_r5r5o3oR14NOpR_PezzDO8ZhcXBRtb11v6mcuvLQD6VSPQ0A").getClaims();