diff --git a/.docker/nginx/README.md b/.docker/nginx/README.md deleted file mode 100644 index 1ec3729..0000000 --- a/.docker/nginx/README.md +++ /dev/null @@ -1,19 +0,0 @@ -## Nginx setup (Docker) - -### HTTPS certificates - -Generate locally trusted HTTPS certificates, using `mkcert`: - -```bash -cd .docker/nginx/ssl - -CAROOT=$(pwd) mkcert -install -# Optional, if not stored on the system already -#sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$(pwd)/rootCA.pem" - -domain=precontentieux.anje-justice.dev -# Create certificates for domain -CAROOT=$(pwd) mkcert "${domain}" -# Register domain as local domain -echo "127.0.0.1 ${domain}" | sudo tee -a /etc/hosts -``` diff --git a/.docker/nginx/conf/proconnect.anje-justice.test.conf b/.docker/nginx/conf/proconnect.anje-justice.test.conf new file mode 100644 index 0000000..f0fed80 --- /dev/null +++ b/.docker/nginx/conf/proconnect.anje-justice.test.conf @@ -0,0 +1,40 @@ +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + +# SSL + ssl_certificate /etc/nginx/certs/proconnect.anje-justice.test.pem; + ssl_certificate_key /etc/nginx/certs/proconnect.anje-justice.test-key.pem; + ssl_trusted_certificate /etc/nginx/certs/rootCA.pem; + + server_name proconnect.anje-justice.test; + + location / { + # Allow performing host detection on request + resolver 127.0.0.11 valid=1s; + set $upstream proconnect:9998; + + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Port $server_port; + + proxy_pass http://$upstream; + } +} + +server { + listen 80; + listen [::]:80; + + server_name proconnect.anje-justice.test; + + location / { + return 301 https://proconnect.anje-justice.test/$request_uri; + } +} diff --git a/.docker/proconnect/mock-oidc-provider/.gitignore b/.docker/proconnect/mock-oidc-provider/.gitignore new file mode 100644 index 0000000..763301f --- /dev/null +++ b/.docker/proconnect/mock-oidc-provider/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ \ No newline at end of file diff --git a/.docker/proconnect/mock-oidc-provider/package.json b/.docker/proconnect/mock-oidc-provider/package.json new file mode 100644 index 0000000..3cc22bd --- /dev/null +++ b/.docker/proconnect/mock-oidc-provider/package.json @@ -0,0 +1,17 @@ +{ + "name": "mock-oidc-provider", + "version": "0.1.0", + "type": "module", + "description": "Mock OIDC provider server", + "main": "dist/index.js", + "author": "Pierre LEMEÉ", + "license": "MIT", + "private": true, + "dependencies": { + "oauth2-mock-server": "^7.2.0" + }, + "devDependencies": { + "@types/node": "^22.10.7", + "typescript": "^5.7.3" + } +} diff --git a/.docker/proconnect/mock-oidc-provider/src/index.ts b/.docker/proconnect/mock-oidc-provider/src/index.ts new file mode 100644 index 0000000..9f4ae4e --- /dev/null +++ b/.docker/proconnect/mock-oidc-provider/src/index.ts @@ -0,0 +1,52 @@ +import { OAuth2Server } from 'oauth2-mock-server'; + +let server = new OAuth2Server(); + +// use JWKs generated here https://mkjwk.org/ +await server.issuer.keys.add({ + "p": "9B6mboyeh7j8KBWFyL-Sxgta-RRcnxqm4Ey_1vYvCV_R9PgZhLzkIOLSoBqxqBn5m6spcuOTmLDBXrdmxvyVIuIuLJTMbg9MrO9H7GgbLYVMSumHFsk6NZFKlDGmA4HfEk0RKQwctIFNhCJnvE8NDQP0enyl3Ii32WjttM9gmtM", + "kty": "RSA", + "q": "8d4BwO1jgFK_DvWlwVMhxbhwX4IEuBaqe7HU0qGRCwAHqPe5_2jsBliP-Cyaqj4oeNFyNpVyBupGAy5md6YsicvFg2IOVwX0eQNGIvxIcFofTyc5q9eV3ppZxVVt01MVKHJ62269CAMp3pTOYgYzUhA9ltVy0V-g8xfcjZ3rycE", + "d": "jsUelRMiqCRnXlYTOBqjBOqOmyjgMqFDXRlSyHbaVaRAjO_9-awCzD8kTKLEZdsqaaXbrVcAyqWF7up4YKs8Ogz5YPQ8RMhysC-Wg786m-Z4fsHlYHuQHP50bgApqYgA5KXZ_NEoOEQYasyAQuv5rBlTwueyDjRD0Ya4ED16NFhxZSplq-HPvDGh3sNtKsD_2na15AHyT8Mrbglax404n3dzGwR4itcQ4TGx-NV_yZ-LfbvFIvLA2tTijFmcrNdUjbBztLEyD9RlqVUxt0L64LB8Ti5WnX8Z7pk7gW_Cshs9-9WY_rOlH7G0wKCwtHc4J5iczotwG-tLBpsbV-fEAQ", + "e": "AQAB", + "use": "sig", + "kid": "kREyd2R7x30J8jw3vVvnMCvqa3SgvreX2Py9fDfOhhs", + "qi": "jd2JsBBXT7F8nSt0sQdARhd_T12unE-SzL1Ba-dW-xk8srRNFJoUL_DQ9Mh4ap70OhN03YfNfWoVhWfbLulDGJfTS-1jSpAwkNjQ37r0YopaNql5Uc6_e1PbHywwmOvzTmXoRfO6MV7GkPvoQI3VQfg_BVbpJbbMXTpJUOuMoTg", + "dp": "4Ulb7M_HCZf01QUvxtjNGgmmthFNfON6t6r8q-Pb-rm8KGfCHRa5LYRGPs0DwQ_fpAKsqMNPFe2hNsjoh6DX_S5g0HGty7BA4aOda5WT50mJ4-Rp7-Ra3M6t1d-PxtLWy6vlt0zfPNHLeLLLqyQE9kr9FwDrjH97s587J87t51M", + "alg": "RS256", + "dq": "n521Zo7DJYJ2F_dBBk5IcWWAs2bomlxK8gqvurlpMOs6IuYpV0b0zFNR36QABe2zY9hFGYSSlcGxppPOh5OgvOc_V680a3XAmsPwW1JGs-6lzuTCCIfjnd4a9EGmktm3ktPKBFoWYd1EmmF1ufcBk1yoaIxAk7AaVZMfuE3Jt4E", + "n": "5qSO7n5BswHdYseE6R4bj5v28vjaQr94Sn4BUudU1wycABq5VYftxvde7qC-rcKdPCCLdGFrsOHdf18bFCpi4RylRMsgaqZwh-o7ywdpICohc-yj-_efoZZl9B1t9oUJ0rVtg8flACDRf4A_GawTVeQIDbPnGTsg5qxo8qgsvVX9MbAuAHD3OOwe9zZRKsYuV6Z-3uxpOdVklY40rfaAYy6yf8BBDR_W0GCLhbEj8dmeVsqhIoss5ISdUvj4M7gKgkPdBxcwuDRPR2J2QSGMOg8MGTNJSnjkC6fYqTmGk1Ab_4gcO-1mAqq0XJP5nSOTHpmV_Cz3DbnSHmL7uBVkEw" +}); +await server.issuer.keys.add({ + "kty": "EC", + "d": "QVZNI6vv0NEshgrd8JzYm3JA3YomEnm8j9a_gBuh3G8", + "use": "sig", + "crv": "P-256", + "kid": "Jh9D8jQqOfbNi4AM1r8-mKU_KOpeMbjGRduPyDXxVy4", + "x": "SiYrczxd1TP6NXuDTNp3KqBsVKm7yEIBqCUp3_fiaS8", + "y": "1OI5MJQ2JhMtODX8WLVzGP-5tRPU-131I58AD0yg2sM", + "alg": "ES256" +}); + +server.issuer.url = "https://proconnect.anje-justice.test" +server.service.once('beforeAuthorizeRedirect', (authorizeRedirectUri, req) => { + console.log(authorizeRedirectUri); +}); + +server.service.once('beforeUserinfo', (userInfoResponse, req) => { + userInfoResponse.body = { + sub: 'c1722a03-4172-4015-9f0d-d1995d4cbe5c', + email: 'redacteur@test.fr', + usual_name: "Chantal", + given_name: "Redacteur", + uid: '1234', + idp_id: 'fce74da7-34d5-4b59-ba78-828a97d859cf' + }; +}); + +// Start the server +await server.start(parseInt(process.env.PORT || "9998", 10), '0.0.0.0'); +console.log('Issuer URL:', server.issuer.url); + +// Stop the server +// await server.stop(); diff --git a/.docker/proconnect/mock-oidc-provider/tsconfig.json b/.docker/proconnect/mock-oidc-provider/tsconfig.json new file mode 100644 index 0000000..ba87cee --- /dev/null +++ b/.docker/proconnect/mock-oidc-provider/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "NodeNext", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "src", + "sourceMap": true, + "experimentalDecorators": true, + "moduleResolution": "nodenext", + "resolveJsonModule": true, + "types": [ + "node", + ] + }, + "include": ["src"] +} diff --git a/.docker/proconnect/mock-oidc-provider/yarn.lock b/.docker/proconnect/mock-oidc-provider/yarn.lock new file mode 100644 index 0000000..934c00e --- /dev/null +++ b/.docker/proconnect/mock-oidc-provider/yarn.lock @@ -0,0 +1,563 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@^22.10.7": + version "22.10.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.7.tgz#14a1ca33fd0ebdd9d63593ed8d3fbc882a6d28d7" + integrity sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg== + dependencies: + undici-types "~6.20.0" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +basic-auth@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bound@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express@^4.21.1: + version "4.21.2" + resolved "https://registry.npmjs.org/express/-/express-4.21.2.tgz" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.7.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.12" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: + version "1.2.7" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz" + integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + get-proto "^1.0.0" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + +jose@^5.9.6: + version "5.9.6" + resolved "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz" + integrity sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +oauth2-mock-server@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/oauth2-mock-server/-/oauth2-mock-server-7.2.0.tgz" + integrity sha512-3M74brZTGsosmpKMhxSRjzYjphGah0vDDdXbszccZa0UtpvX2uGa3cHPlRt5urcO5XP04hsB+JoKC83Pe9TtPA== + dependencies: + basic-auth "^2.0.1" + cors "^2.8.5" + express "^4.21.1" + is-plain-object "^5.0.0" + jose "^5.9.6" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.13.0: + version "6.13.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.19.0: + version "0.19.0" + resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.0.6: + version "1.1.0" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^5.7.3: + version "5.7.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" + integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== + +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== diff --git a/compose.yaml b/compose.yaml index f279f9a..c52c331 100644 --- a/compose.yaml +++ b/compose.yaml @@ -9,6 +9,10 @@ services: - ./.docker/postgres/data:/var/lib/postgresql/data:rw # To run init scripts, wipe the data dir (`rm -Rf .docker/postgres/data/*`) first - ./.docker/postgres/scripts/:/docker-entrypoint-initdb.d + networks: + mijnet: + aliases: + - postgres ports: - "5432:5432" @@ -22,6 +26,12 @@ services: volumes: # Ce partage, via un volume, est requis afin que Nginx puisse servir les fichiers statiques seul - ./public:/app/public + networks: + mijnet: + aliases: + - mon-indemnisation.anje-justice.dev + - mon-indemnisation.anje-justice.test + - proconnect.anje-justice.test ports: - "80:80" - "443:443" @@ -29,6 +39,10 @@ services: # Mailpit: email SMTP + web UI to see trapped emails mailpit: image: axllent/mailpit + networks: + mijnet: + aliases: + - mailpit ports: - "1025" - "8025:8025" @@ -44,7 +58,7 @@ services: tty: true # En attendant un accès à Harbor image: pierrelemee/precontentieux-full:latest - command: bash -c 'composer install --no-interaction --optimize-autoloader && bin/console doctrine:migration:migrate --no-interaction --all-or-nothing && php-fpm' + command: bash -c 'update-ca-certificates && composer install --no-interaction --optimize-autoloader && bin/console doctrine:migration:migrate --no-interaction --all-or-nothing && php-fpm' environment: - APP_ENV=${APP_ENV:-dev} - TS=Europe/Paris @@ -64,6 +78,9 @@ services: - /app/drivers - /app/vendor - /app/node_modules + - ./.docker/nginx/ssl:/usr/local/share/ca-certificates + networks: + - mijnet ports: - "9000:9000" @@ -79,3 +96,23 @@ services: - /app/node_modules ports: - "5173:5173" + + proconnect: + image: node:22 + hostname: proconnect + networks: + mijnet: + aliases: + - proconnect + command: bash -c 'yarn install && npx tsc -w & npx nodemon build/index.js' + ports: + - '9998:9998' + environment: + PORT: 9998 + working_dir: /app + volumes: + - ./.docker/proconnect/mock-oidc-provider:/app + + +networks: + mijnet: diff --git a/docs/001-Installation.md b/docs/001-Installation.md index 6f94112..7f9d266 100644 --- a/docs/001-Installation.md +++ b/docs/001-Installation.md @@ -17,13 +17,16 @@ cd .docker/nginx/ssl # Optionnel, si le certificat racine (i.e. le fichier `rootCA.pem` n'est pas encore présent) CAROOT=$(pwd) mkcert -install +# Sous MacOSX, déclaré le certificat fiable sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$(pwd)/rootCA.pem" +# Convertir le certificat racine au format .crt +openssl x509 -inform PEM -in "$(pwd)/rootCA.pem" -out rootCA.crt -for tld in dev test; do +for domain in mon-indemnisation.anje-justice.dev mon-indemnisation.anje-justice.test proconnect.anje-justice.test; do # Génération - CAROOT=$(pwd) mkcert "mon-indemnisation.anje-justice.${tld}" + CAROOT=$(pwd) mkcert "${domain}" # Register domain as local domain - echo "127.0.0.1 mon-indemnisation.anje-justice.${tld}" | sudo tee -a /etc/hosts + echo "127.0.0.1 ${domain}" | sudo tee -a /etc/hosts done ```` diff --git a/src/Security/Jwt/Jwk.php b/src/Security/Jwt/Jwk.php deleted file mode 100644 index 86c19c0..0000000 --- a/src/Security/Jwt/Jwk.php +++ /dev/null @@ -1,54 +0,0 @@ -kty = JwkKeyType::from($values['kty']); - $jwk->use = JwkUseType::from($values['use']); - $jwk->alg = JwkEncryptionAlgorithm::from($values['alg']); - $jwk->kid = $values['kid']; - // Send as key data the other values - $jwk->data = array_filter($values, function ($k) { - return !in_array($k, ['kty', 'use', 'alg', 'kid']); - }, ARRAY_FILTER_USE_KEY); - - return $jwk; - } -} diff --git a/src/Security/Jwt/Jwt.php b/src/Security/Jwt/Jwt.php deleted file mode 100644 index 9650124..0000000 --- a/src/Security/Jwt/Jwt.php +++ /dev/null @@ -1,84 +0,0 @@ -value = $value; - list($header, $payload, $signature) = explode('.', $value); - - $this->header = json_decode(base64_decode(urldecode($header)), true); - $this->payload = json_decode(base64_decode(urldecode($payload)), true); - $this->message = "{$header}.{$payload}"; - $this->signature = $signature; - } - - public function getPayload(): array - { - return $this->payload; - } - - public function getValue(string $name): mixed - { - return $this->payload[$name] ?? null; - } - - protected function extractJwkForAlgo(array $jwks, string $kid) - { - $key = array_search($kid, array_column($jwks, 'kid')); - - return $jwks[$key]; - } - - protected function buildPem(array $jwk): string - { - // Ça ne fonctionne pas, voire vendor/firebase/php-jwt/src/JWK.php:231 - - return "-----BEGIN PUBLIC KEY-----\n". - chunk_split(base64_encode('MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA'.strtr($jwk['n'].'ID'.$jwk['e'], '-_', '+/')), 64). - '-----END PUBLIC KEY-----'; - } - - public function verify(array $jwks): bool - { - $jwk = $this->extractJwkForAlgo($jwks, $this->header['kid']); - - try { - /* - return 1 === openssl_verify( - $this->message, - base64_decode($this->signature), - $this->buildPem($jwk)) - OPENSSL_ALGO_SHA256 - ); */ - FirebaseJWT::decode($this->value, FirebaseJWK::parseKey($jwk)); - - return true; - } catch (SignatureInvalidException) { - return false; - } - } - - private static function base64Encode(string $value): string - { - return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($value)); - } - - public static function parse(string $jwt): Jwt - { - return new Jwt($jwt); - } -} diff --git a/src/Security/Oidc/OidcClient.php b/src/Security/Oidc/OidcClient.php index 0cea7a9..7713b45 100644 --- a/src/Security/Oidc/OidcClient.php +++ b/src/Security/Oidc/OidcClient.php @@ -2,10 +2,13 @@ namespace MonIndemnisationJustice\Security\Oidc; +use Firebase\JWT\JWK; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; +use Firebase\JWT\SignatureInvalidException; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\RequestException; -use MonIndemnisationJustice\Security\Jwt\Jwt; use Ramsey\Uuid\Uuid; use Symfony\Component\DependencyInjection\Attribute\Target; use Symfony\Component\HttpFoundation\Request; @@ -24,6 +27,9 @@ class OidcClient { protected HttpClient $client; protected ?array $configuration = null; + /** + * @var array the set of JSON Web Keys + */ protected ?array $jwks = null; public function __construct( @@ -52,15 +58,18 @@ protected function configure(): void } if (null === $this->jwks) { - $this->jwks = $this->cache->get('oidc_jwks', function () { + $this->jwks = JWK::parseKeySet($this->cache->get('oidc_jwks', function () { try { $response = $this->client->get($this->configuration['jwks_uri']); - return json_decode($response->getBody()->getContents(), true)['keys']; + return json_decode( + $response->getBody()->getContents(), + true + ); } catch (GuzzleException $e) { throw new AuthenticationException('Fetch of OIDC JWKs failed.'); } - }); + })); } } @@ -134,13 +143,13 @@ public function authenticate(Request $request): string $credentials = json_decode($response->getBody()->getContents()); $accessToken = $credentials->access_token ?? null; - $idToken = Jwt::parse($credentials->id_token); - - if (!$idToken->verify($this->jwks)) { + try { + $idToken = JWT::decode($credentials->id_token, $this->jwks); + } catch (SignatureInvalidException) { throw new AuthenticationException('Authorization failed (invalid id token).'); } - if ($idToken->getValue('nonce') !== $context['nonce']) { + if ($idToken->nonce !== $context['nonce']) { throw new AuthenticationException('Authorization failed (nonce does not match).'); } @@ -161,8 +170,12 @@ public function fetchUserInfo(string $token): array throw new AuthenticationException('User info fetching failed.'); } - $jwt = Jwt::parse($response->getBody()->getContents()); + // Si les données utilisateurs renvoyées sont au format JSON, on les renvoie décodées + if (json_validate($raw = $response->getBody()->getContents())) { + return json_decode($raw, true); + } - return $jwt->getPayload(); + // Sinon, on traite en JWT (au risque de jeter des exceptions) + return (array) JWT::decode($raw, $this->jwks); } } diff --git a/src/Security/Provider/AgentProvider.php b/src/Security/Provider/AgentProvider.php index e1ec194..062fd63 100644 --- a/src/Security/Provider/AgentProvider.php +++ b/src/Security/Provider/AgentProvider.php @@ -16,7 +16,13 @@ public function __construct(protected readonly AgentRepository $agentRepository) public function refreshUser(UserInterface $user): UserInterface { - return $this->agentRepository->findOneBy(['identifiant' => $user->getUserIdentifier()]); + $agent = $this->agentRepository->findOneBy(['identifiant' => $user->getUserIdentifier()]); + + if (null === $agent) { + throw new UserNotFoundException($user->getUserIdentifier()); + } + + return $user; } public function supportsClass(string $class): bool