diff --git a/docker/nginx-certs/default.crt b/docker/nginx-certs/default.crt index 79aeb4fc..f64f2c69 100644 --- a/docker/nginx-certs/default.crt +++ b/docker/nginx-certs/default.crt @@ -1,92 +1,48 @@ -----BEGIN CERTIFICATE----- -MIIFTzCCBDegAwIBAgISA/Jlept1Qhhdiz41X6VdaHJLMA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMTExMzAyMjU4MjNaFw0yMjAyMjgyMjU4MjJaMC8xLTArBgNVBAMM -JCoubG9jYWwuc3RhY2stZGV2LmNpcnJ1c2lkZW50aXR5LmNvbTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUGI0JUZ0AHg3xRivLRsRh0t+YcHw+N+dND -5e1xGyON8rxiUNxZjIJhUX6UrspSPDQj437xDdvH1M8XbdhpR5sx4/K4T20PtTSM -DpuFnpVdM3zfhy8m9o0ikhx44tlg1T7+LvjDF9yY4fFUy83iHesd/P8L/cefr5kz -gXnZthyWF+soUcFJ3NuTI8nI9ppWTahAxQ5cq20HQ6hu+thUiPE39bz6zDPUjkhM -g/xWAemNQj3tEpnlBi6ewbS4vWy1dJ+HCE4kfz3FjBx+jXURWQ2OLqCIH/2iT8wQ -oaqB1zKjX2Avp03t66ElnMxo4x+Fb9wJB5vVwVxMa4zXbVNQGocCAwEAAaOCAmAw -ggJcMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH -AwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUv/yi/9NC/ZtcfQqtkb4A+MW77p4w -HwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBH -MCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKG -Fmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wLwYDVR0RBCgwJoIkKi5sb2NhbC5zdGFj -ay1kZXYuY2lycnVzaWRlbnRpdHkuY29tMEwGA1UdIARFMEMwCAYGZ4EMAQIBMDcG -CysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMubGV0c2VuY3J5 -cHQub3JnMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYARqVV63X6kSAwtaKJafTz -fREsQXS+/Um4havy/HD+bUcAAAF9c0j/QgAABAMARzBFAiBZ4oleDpke0bMLZhs8 -SVWrLCo71PRFOjhnJDUO+BCo2QIhAIF5OhvMPTlooFlsPGdgMOHGQuxne/URjF7Z -7HqhggNyAHcA36Veq2iCTx9sre64X04+WurNohKkal6OOxLAIERcKnMAAAF9c0kB -DwAABAMASDBGAiEAnBJQMiPsS9nbUWGzSU+Z+4Aho9aUZiyleFD17XZE5tgCIQCB -vBG2YcQNDkTiDHCGs4IcPGj8pYkr/Cn5WXIh1iJs8TANBgkqhkiG9w0BAQsFAAOC -AQEAslzvucE9ykWgCLkaq3mGaSLT/UD/2K2w/KoXXth0d0c5iRFHJljVsMVhkAFK -dJUz8TLpY+5Z9NFVm+ycDlWmn9VIeSwkrh4LtTHVTr1jg9JX97kQcvFjrwTdmPbm -G8tej+AZ7Qp8dL7ZbxvHz076zbA/TmzKVg++rToV6QObxSrXqWzmV5REKvrsM8KQ -tTw0Olk3FikFS0qu5y8zXh8Nd7e0G8vDD4e/4oWbhjoNzr6gJSgrjhiyBNZ3gvzH -hq/iUZ1gpBa3Wk5oTpceEZV5lMlI2hkV/AVXfSbZ3xBqHMpP36J63nv7vUBhhSkk -/OOUGcEGCNqBo5MaluzKJQFVCA== +MIIDtTCCAzqgAwIBAgISBS+VOayc1kxCgE5+ZOoS+qWOMAoGCCqGSM49BAMDMDIx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF +NzAeFw0yNTEwMDIyMzAwNDVaFw0yNTEyMzEyMzAwNDRaMC8xLTArBgNVBAMMJCou +bG9jYWwuc3RhY2stZGV2LmNpcnJ1c2lkZW50aXR5LmNvbTBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABHn6Eefi38XP9c3P+I9mbgkJl9v4DWvaHj0BjbMTRtB++uMx +1S3V9KMvfrd3WJQTZHJC5rjg9m8RP8MeoozBGbujggIxMIICLTAOBgNVHQ8BAf8E +BAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQC +MAAwHQYDVR0OBBYEFKHUgyvBC/jq523zzkq9y0614qi3MB8GA1UdIwQYMBaAFK5I +ntyHHUSgb9qi5WB0BHjCnACAMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAoYW +aHR0cDovL2U3LmkubGVuY3Iub3JnLzAvBgNVHREEKDAmgiQqLmxvY2FsLnN0YWNr +LWRldi5jaXJydXNpZGVudGl0eS5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwLQYD +VR0fBCYwJDAioCCgHoYcaHR0cDovL2U3LmMubGVuY3Iub3JnLzE1LmNybDCCAQMG +CisGAQQB1nkCBAIEgfQEgfEA7wB1AKRCxQZJYGFUjw/U6pz7ei0mRU2HqX8v30VZ +9idPOoRUAAABmaddo28AAAQDAEYwRAIgfHBeIowNXBEq+XstySnAnbijEG4+v0ul +aY7lFGMCIjkCIBMIpzZAqFjZFSeAIebvgCkZ/bhalknDjq6h2adS62hMAHYAzPsP +aoVxCWX+lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGZp12jgAAABAMARzBFAiEA +oVR6XksBDPCVonCG2ugt4blqtrlLzvLTPPZsDVU3tYICICQBzR6ciu0UO4CVZF5M +8jxJj/uHwgKBn9Zhz/SsAsluMAoGCCqGSM49BAMDA2kAMGYCMQCkGM/V5auizug/ +GOsW1xUMOOzP3M3s1ml5GLgUuJkSGmiM0VIGo70YztzWkB4g7hoCMQDkYn40g6qc +MgCT3DvgL3krwyWck/upamARO0mDApIvnihiEMKrWXWkyUV0H457hy4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- -MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +MIIEVzCCAj+gAwIBAgIRAKp18eYrjwoiCWbTi7/UuqEwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw -WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg -RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP -R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx -sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm -NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg -Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG -/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB -Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA -FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw -AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw -Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB -gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W -PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl -ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz -CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm -lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 -avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 -yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O -yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids -hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ -HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv -MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX -nLRbwHOoq7hHwg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC -ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL -wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D -LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK -4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 -bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y -sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ -Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 -FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc -SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql -PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND -TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw -SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 -c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx -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 ++VUwFj9tmWxyR/M= -----END CERTIFICATE----- diff --git a/docker/nginx-certs/default.key b/docker/nginx-certs/default.key index 55bad668..57aaaf48 100644 --- a/docker/nginx-certs/default.key +++ b/docker/nginx-certs/default.key @@ -1,28 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVBiNCVGdAB4N8 -UYry0bEYdLfmHB8PjfnTQ+XtcRsjjfK8YlDcWYyCYVF+lK7KUjw0I+N+8Q3bx9TP -F23YaUebMePyuE9tD7U0jA6bhZ6VXTN834cvJvaNIpIceOLZYNU+/i74wxfcmOHx -VMvN4h3rHfz/C/3Hn6+ZM4F52bYclhfrKFHBSdzbkyPJyPaaVk2oQMUOXKttB0Oo -bvrYVIjxN/W8+swz1I5ITIP8VgHpjUI97RKZ5QYunsG0uL1stXSfhwhOJH89xYwc -fo11EVkNji6giB/9ok/MEKGqgdcyo19gL6dN7euhJZzMaOMfhW/cCQeb1cFcTGuM -121TUBqHAgMBAAECggEAB/UCvCeK88lUEAC7v/Y1N0Sk2eOTBXG4MzwGCqh+6wUS -XBcQDisKJJSeBqxnGweXWBs/FC7M5bjBKjslzz+ffRyP9zELRnefvSa+JPEIy2t/ -0NpIompCK2NvMcESOCx1yrST7Jbc/VB4oBsawcYAeBfWq3A3Oo2scXyLCZIoS0j+ -fuEM+s1gg5+vqbYb2+0KUcth2pPRSnHzJXtu6nN5YICgnQpHXfhCyWV2XS36lbeN -m6+hRz4w+VJUAomfIo5ahe6LuYbZt77thOPgf1xWYU+GM+HQUytJPRFjfJPna39G -88SVxvqWAxlfb2tdVeIM6EiSpUr2ncgITylYFy7DgQKBgQD6PQhoK35Cw2SEwWNX -BnoeZvC4YmGJEK8fkp3hri/A3NJ3y0GvLQV8e5LGt9O1xgFp6PdxwpbJhyMy97sN -GxNQcxn8+Xa89JsQQGbjz7LHfUMKqVg+xq8E4a4rKauYOReVvr98grBxLdm0DZNO -Vb6ntbbtsEkO3mBniUDrfES4swKBgQDZ7cD5E+ArjvVjfOrlo6lV3FMDrrv8DwnA -ls1Kvs8MQ9+E4YZ01/+DZ3iCbeKH/NbKm4XXVoZEPA1nvulvdrTaGr7bowzKzHHh -hpz0mfzsKZxXeogemiDYQ6BQO3Z0lHQbTJJOZSMFkXp+agt2ikJOmTLXNxgAN8nq -KeYQAdS43QKBgB+SxdXG7xZjavJpKCyZz5y4ZlUNbLsLlN0J9cu825+c/R1KUw5U -QuXy/ZD/LsI3qoP/dgEviTECUQmkQkCkEurKqxPFMhsjTdFeHt1NnoQXJPdaaJz7 -GqgmBYDCsDjzsysctzJxluug2mAielye6wBkKCGTZZRvsIA/zCYqNs2LAoGBANNx -xnElIrTAoUClPDgRIkSHYBhLmmNGp/yvlII4PiW1WRLRyqZlyKlTZG6QdWHiJPky -CptTfTSJW6xUZKPcdj7EAniSa9/8m2XpOTJukiMFgIa0AYxHmSScANi3yQf13e16 -zt23bVKCw2oSNAsQvKMMK3L7JpNXjdZgTrMrQ50VAoGBAIqSg3w2wnjsHrqryGQa -jIUCm80EDx5t2tqGAn23RbR3ps+tSRB6KLjaZM+S90SzFRZjI3shA60tXTj2Mra/ -xcJpc828KgGnyZIRB2gmO/YFURwLEx3dOwWlTS8wfRb3inCGydwQu2A+V59CLmck -VTUEdI5qZrc1Aq/5OjkFI1GJ +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTVrOmRapta1bw8iJ +p4e0OhYa2uwz7iIiYsaGQuhqQDKhRANCAAR5+hHn4t/Fz/XNz/iPZm4JCZfb+A1r +2h49AY2zE0bQfvrjMdUt1fSjL363d1iUE2RyQua44PZvET/DHqKMwRm7 -----END PRIVATE KEY----- diff --git a/src/Controllers/AccessTokenController.php b/src/Controllers/AccessTokenController.php index 4ae09aba..dcf430a5 100644 --- a/src/Controllers/AccessTokenController.php +++ b/src/Controllers/AccessTokenController.php @@ -61,9 +61,16 @@ public function token(Request $request): Response * @psalm-suppress DeprecatedMethod Until we drop support for old public/*.php routes, we need to bridge * between PSR and Symfony HTTP messages. */ - return $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( + $response = $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( $this->__invoke($this->psrHttpBridge->getPsrHttpFactory()->createRequest($request)), ); + + // If not already handled, allow CORS (for JS clients). + if (!$response->headers->has('Access-Control-Allow-Origin')) { + $response->headers->set('Access-Control-Allow-Origin', '*'); + } + + return $response; } catch (OAuthServerException $exception) { return $this->errorResponder->forException($exception); } diff --git a/src/Controllers/AuthorizationController.php b/src/Controllers/AuthorizationController.php index 07b31be4..fa4c6079 100644 --- a/src/Controllers/AuthorizationController.php +++ b/src/Controllers/AuthorizationController.php @@ -106,9 +106,16 @@ public function authorization(Request $request): Response * @psalm-suppress DeprecatedMethod Until we drop support for old public/*.php routes, we need to bridge * between PSR and Symfony HTTP messages. */ - return $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( + $response = $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( $this->__invoke($this->psrHttpBridge->getPsrHttpFactory()->createRequest($request)), ); + + // If not already handled, allow CORS (for JS clients). + if (!$response->headers->has('Access-Control-Allow-Origin')) { + $response->headers->set('Access-Control-Allow-Origin', '*'); + } + + return $response; } catch (OAuthServerException $exception) { return $this->errorResponder->forException($exception); } diff --git a/src/Controllers/ConfigurationDiscoveryController.php b/src/Controllers/ConfigurationDiscoveryController.php index d3eea6e9..cb4db4fb 100644 --- a/src/Controllers/ConfigurationDiscoveryController.php +++ b/src/Controllers/ConfigurationDiscoveryController.php @@ -27,6 +27,9 @@ public function __construct(private readonly OpMetadataService $opMetadataServic public function __invoke(): JsonResponse { - return new JsonResponse($this->opMetadataService->getMetadata()); + return new JsonResponse( + $this->opMetadataService->getMetadata(), + headers: ['Access-Control-Allow-Origin' => '*'], + ); } } diff --git a/src/Controllers/Federation/EntityStatementController.php b/src/Controllers/Federation/EntityStatementController.php index d521c60e..b1b74f84 100644 --- a/src/Controllers/Federation/EntityStatementController.php +++ b/src/Controllers/Federation/EntityStatementController.php @@ -310,7 +310,10 @@ protected function prepareEntityStatementResponse(string $entityStatementToken): return $this->routes->newResponse( $entityStatementToken, 200, - [HttpHeadersEnum::ContentType->value => ContentTypesEnum::ApplicationEntityStatementJwt->value,], + [ + HttpHeadersEnum::ContentType->value => ContentTypesEnum::ApplicationEntityStatementJwt->value, + 'Access-Control-Allow-Origin' => '*', + ], ); } } diff --git a/src/Controllers/Federation/SubordinateListingsController.php b/src/Controllers/Federation/SubordinateListingsController.php index 9c076ad9..ef6b6a65 100644 --- a/src/Controllers/Federation/SubordinateListingsController.php +++ b/src/Controllers/Federation/SubordinateListingsController.php @@ -63,6 +63,7 @@ function (ClientEntityInterface $clientEntity): ?string { return $this->routes->newJsonResponse( $subordinateEntityIdList, + headers: ['Access-Control-Allow-Origin' => '*'], ); } } diff --git a/src/Controllers/JwksController.php b/src/Controllers/JwksController.php index 7159b562..d2e12ad1 100644 --- a/src/Controllers/JwksController.php +++ b/src/Controllers/JwksController.php @@ -38,6 +38,8 @@ public function __invoke(): JsonResponse public function jwks(): Response { - return $this->psrHttpBridge->getHttpFoundationFactory()->createResponse($this->__invoke()); + $response = $this->psrHttpBridge->getHttpFoundationFactory()->createResponse($this->__invoke()); + $response->headers->set('Access-Control-Allow-Origin', '*'); + return $response; } } diff --git a/src/Controllers/UserInfoController.php b/src/Controllers/UserInfoController.php index 25b39f90..982b0eac 100644 --- a/src/Controllers/UserInfoController.php +++ b/src/Controllers/UserInfoController.php @@ -92,9 +92,16 @@ public function userInfo(Request $request): Response * @psalm-suppress DeprecatedMethod Until we drop support for old public/*.php routes, we need to bridge * between PSR and Symfony HTTP messages. */ - return $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( + $response = $this->psrHttpBridge->getHttpFoundationFactory()->createResponse( $this->__invoke($this->psrHttpBridge->getPsrHttpFactory()->createRequest($request)), ); + + // If not already handled, allow CORS (for JS clients). + if (!$response->headers->has('Access-Control-Allow-Origin')) { + $response->headers->set('Access-Control-Allow-Origin', '*'); + } + + return $response; } catch (OAuthServerException $exception) { return $this->errorResponder->forException($exception); } diff --git a/tests/unit/src/Controllers/AccessTokenControllerTest.php b/tests/unit/src/Controllers/AccessTokenControllerTest.php index 15c1a2c4..3f2ab25a 100644 --- a/tests/unit/src/Controllers/AccessTokenControllerTest.php +++ b/tests/unit/src/Controllers/AccessTokenControllerTest.php @@ -16,6 +16,9 @@ use SimpleSAML\Module\oidc\Repositories\AllowedOriginRepository; use SimpleSAML\Module\oidc\Server\AuthorizationServer; use SimpleSAML\Module\oidc\Services\ErrorResponder; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; /** * @covers \SimpleSAML\Module\oidc\Controllers\AccessTokenController @@ -31,6 +34,14 @@ class AccessTokenControllerTest extends TestCase protected MockObject $requestFactoryMock; protected MockObject $responseFactoryMock; + protected MockObject $symfonyRequestMock; + + protected MockObject $symfonyResponseMock; + + protected MockObject $httpFoundationFactoryMock; + + protected MockObject $responseHeaderBagMock; + /** * @throws \Exception @@ -47,6 +58,15 @@ protected function setUp(): void $this->responseFactoryMock = $this->createMock(ResponseFactoryInterface::class); $this->responseFactoryMock->method('createResponse')->willReturn($this->responseMock); $this->psrHttpBridgeMock->method('getResponseFactory')->willReturn($this->responseFactoryMock); + + $this->symfonyRequestMock = $this->createMock(Request::class); + $this->symfonyResponseMock = $this->createMock(\Symfony\Component\HttpFoundation\Response::class); + $this->responseHeaderBagMock = $this->createMock(ResponseHeaderBag::class); + $this->symfonyResponseMock->headers = $this->responseHeaderBagMock; + + $this->httpFoundationFactoryMock = $this->createMock(HttpFoundationFactory::class); + $this->httpFoundationFactoryMock->method('createResponse')->willReturn($this->symfonyResponseMock); + $this->psrHttpBridgeMock->method('getHttpFoundationFactory')->willReturn($this->httpFoundationFactoryMock); } protected function mock(): AccessTokenController @@ -100,6 +120,20 @@ public function testItHandlesCorsRequest(): void $this->mock()->__invoke($this->serverRequestMock); } + public function testItAlwaysReturnsAccessControlAllowOrigin(): void + { + $this->authorizationServerMock + ->expects($this->once()) + ->method('respondToAccessTokenRequest') + ->willReturn($this->responseMock); + + $this->responseHeaderBagMock->expects($this->once()) + ->method('set') + ->with('Access-Control-Allow-Origin', '*'); + + $this->mock()->token($this->symfonyRequestMock); + } + public function testItUsesRequestTrait(): void { $this->assertContains(RequestTrait::class, class_uses(AccessTokenController::class)); diff --git a/tests/unit/src/Controllers/AuthorizationControllerTest.php b/tests/unit/src/Controllers/AuthorizationControllerTest.php index af04ba46..ec0636f5 100644 --- a/tests/unit/src/Controllers/AuthorizationControllerTest.php +++ b/tests/unit/src/Controllers/AuthorizationControllerTest.php @@ -21,6 +21,9 @@ use SimpleSAML\Module\oidc\Services\AuthenticationService; use SimpleSAML\Module\oidc\Services\ErrorResponder; use SimpleSAML\Module\oidc\Services\LoggerService; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; /** * @covers \SimpleSAML\Module\oidc\Controllers\AuthorizationController @@ -57,6 +60,11 @@ class AuthorizationControllerTest extends TestCase protected static array $sampleRequestedAcrs = ['values' => ['1', '0'], 'essential' => false]; + protected MockObject $symfonyRequestMock; + protected MockObject $symfonyResponseMock; + protected MockObject $responseHeaderBagMock; + protected MockObject $httpFoundationFactoryMock; + /** * @throws \Exception */ @@ -84,6 +92,15 @@ public function setUp(): void ], 'authorizationRequest' => $this->authorizationRequestMock, ]; + + $this->symfonyRequestMock = $this->createMock(Request::class); + $this->symfonyResponseMock = $this->createMock(\Symfony\Component\HttpFoundation\Response::class); + $this->responseHeaderBagMock = $this->createMock(ResponseHeaderBag::class); + $this->symfonyResponseMock->headers = $this->responseHeaderBagMock; + + $this->httpFoundationFactoryMock = $this->createMock(HttpFoundationFactory::class); + $this->httpFoundationFactoryMock->method('createResponse')->willReturn($this->symfonyResponseMock); + $this->psrHttpBridgeMock->method('getHttpFoundationFactory')->willReturn($this->httpFoundationFactoryMock); } public static function queryParameterValues(): array @@ -98,6 +115,31 @@ public static function queryParameterValues(): array ]; } + protected function mock( + ?AuthenticationService $authenticationService = null, + ?AuthorizationServer $authorizationServer = null, + ?ModuleConfig $moduleConfig = null, + ?LoggerService $loggerService = null, + ?PsrHttpBridge $psrHttpBridge = null, + ?ErrorResponder $errorResponder = null, + ): AuthorizationController { + $authenticationService ??= $this->authenticationServiceStub; + $authorizationServer ??= $this->authorizationServerStub; + $moduleConfig ??= $this->moduleConfigStub; + $loggerService ??= $this->loggerServiceMock; + $psrHttpBridge ??= $this->psrHttpBridgeMock; + $errorResponder ??= $this->errorResponderMock; + + return new AuthorizationController( + $authenticationService, + $authorizationServer, + $moduleConfig, + $loggerService, + $psrHttpBridge, + $errorResponder, + ); + } + /** * @throws \SimpleSAML\Error\AuthSource * @throws \SimpleSAML\Error\BadRequest @@ -128,6 +170,7 @@ public function testReturnsResponseWhenInvoked(array $queryParameters): void ->method('getAuthorizationRequestFromState') ->willReturn($this->authorizationRequestMock); + // TODO mivanci Move to mock() method. $controller = new AuthorizationController( $this->authenticationServiceStub, $this->authorizationServerStub, @@ -486,4 +529,17 @@ public function testValidateAcrLogsWarningIfNoAcrsConfigured(): void $this->errorResponderMock, ))($this->serverRequestStub); } + + public function testItAlwaysReturnsAccessControlAllowOrigin(): void + { + $this->authorizationServerStub + ->method('completeAuthorizationRequest') + ->willReturn($this->responseStub); + + $this->responseHeaderBagMock->expects($this->once()) + ->method('set') + ->with('Access-Control-Allow-Origin', '*'); + + $this->mock()->authorization($this->symfonyRequestMock); + } } diff --git a/tests/unit/src/Controllers/ConfigurationDiscoveryControllerTest.php b/tests/unit/src/Controllers/ConfigurationDiscoveryControllerTest.php index 86040b12..778e1be3 100644 --- a/tests/unit/src/Controllers/ConfigurationDiscoveryControllerTest.php +++ b/tests/unit/src/Controllers/ConfigurationDiscoveryControllerTest.php @@ -30,7 +30,7 @@ class ConfigurationDiscoveryControllerTest extends TestCase 'end_session_endpoint' => 'http://localhost/end-session', ]; - protected MockObject $oidcOpenIdProviderMetadataServiceMock; + protected MockObject $opMetadataServiceMock; protected MockObject $serverRequestMock; /** @@ -38,30 +38,38 @@ class ConfigurationDiscoveryControllerTest extends TestCase */ protected function setUp(): void { - $this->oidcOpenIdProviderMetadataServiceMock = $this->createMock(OpMetadataService::class); - $this->oidcOpenIdProviderMetadataServiceMock->method('getMetadata')->willReturn(self::OIDC_OP_METADATA); + $this->opMetadataServiceMock = $this->createMock(OpMetadataService::class); + $this->opMetadataServiceMock->method('getMetadata')->willReturn(self::OIDC_OP_METADATA); $this->serverRequestMock = $this->createMock(ServerRequest::class); } + protected function mock( + ?OpMetadataService $opMetadataService = null, + ): ConfigurationDiscoveryController { + $opMetadataService ??= $this->opMetadataServiceMock; + + return new ConfigurationDiscoveryController($opMetadataService); + } + public function testItIsInitializable(): void { $this->assertInstanceOf( ConfigurationDiscoveryController::class, - new ConfigurationDiscoveryController($this->oidcOpenIdProviderMetadataServiceMock), + $this->mock(), ); } - protected function getStubbedInstance(): ConfigurationDiscoveryController - { - return new ConfigurationDiscoveryController($this->oidcOpenIdProviderMetadataServiceMock); - } - public function testItReturnsOpenIdConnectConfiguration(): void { $this->assertSame( - json_decode($this->getStubbedInstance()->__invoke()->getContent(), true), + json_decode($this->mock()->__invoke()->getContent(), true), self::OIDC_OP_METADATA, ); } + + public function testItAlwaysReturnsAccessControlAllowOrigin(): void + { + $this->assertTrue($this->mock()->__invoke()->headers->has('Access-Control-Allow-Origin'),); + } } diff --git a/tests/unit/src/Controllers/JwksControllerTest.php b/tests/unit/src/Controllers/JwksControllerTest.php index 15fe5580..4b3267e1 100644 --- a/tests/unit/src/Controllers/JwksControllerTest.php +++ b/tests/unit/src/Controllers/JwksControllerTest.php @@ -10,6 +10,8 @@ use SimpleSAML\Module\oidc\Bridges\PsrHttpBridge; use SimpleSAML\Module\oidc\Controllers\JwksController; use SimpleSAML\Module\oidc\Services\JsonWebKeySetService; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; /** * @covers \SimpleSAML\Module\oidc\Controllers\JwksController @@ -18,7 +20,10 @@ class JwksControllerTest extends TestCase { protected MockObject $jsonWebKeySetServiceMock; protected MockObject $serverRequestMock; - protected MockObject $psrHttpBridge; + protected MockObject $psrHttpBridgeMock; + protected MockObject $symfonyResponseMock; + protected MockObject $responseHeaderBagMock; + protected MockObject $httpFoundationFactoryMock; /** * @throws \Exception @@ -27,14 +32,27 @@ protected function setUp(): void { $this->jsonWebKeySetServiceMock = $this->createMock(JsonWebKeySetService::class); $this->serverRequestMock = $this->createMock(ServerRequest::class); - $this->psrHttpBridge = $this->createMock(PsrHttpBridge::class); + $this->psrHttpBridgeMock = $this->createMock(PsrHttpBridge::class); + + $this->symfonyResponseMock = $this->createMock(\Symfony\Component\HttpFoundation\Response::class); + $this->responseHeaderBagMock = $this->createMock(ResponseHeaderBag::class); + $this->symfonyResponseMock->headers = $this->responseHeaderBagMock; + + $this->httpFoundationFactoryMock = $this->createMock(HttpFoundationFactory::class); + $this->httpFoundationFactoryMock->method('createResponse')->willReturn($this->symfonyResponseMock); + $this->psrHttpBridgeMock->method('getHttpFoundationFactory')->willReturn($this->httpFoundationFactoryMock); } - protected function mock(): JwksController - { + protected function mock( + ?JsonWebKeySetService $jsonWebKeySetService = null, + ?PsrHttpBridge $psrHttpBridge = null, + ): JwksController { + $jsonWebKeySetService ??= $this->jsonWebKeySetServiceMock; + $psrHttpBridge ??= $this->psrHttpBridgeMock; + return new JwksController( - $this->jsonWebKeySetServiceMock, - $this->psrHttpBridge, + $jsonWebKeySetService, + $psrHttpBridge, ); } @@ -66,4 +84,12 @@ public function testItReturnsJsonKeys(): void $this->mock()->__invoke()->getPayload(), ); } + + public function testItAlwaysReturnsAccessControlAllowOrigin(): void + { + $this->responseHeaderBagMock->expects($this->once())->method('set') + ->with('Access-Control-Allow-Origin', '*'); + + $this->mock()->jwks(); + } } diff --git a/tests/unit/src/Controllers/UserInfoControllerTest.php b/tests/unit/src/Controllers/UserInfoControllerTest.php index 08b08bb3..2b1a0e5c 100644 --- a/tests/unit/src/Controllers/UserInfoControllerTest.php +++ b/tests/unit/src/Controllers/UserInfoControllerTest.php @@ -20,6 +20,8 @@ use SimpleSAML\Module\oidc\Repositories\UserRepository; use SimpleSAML\Module\oidc\Services\ErrorResponder; use SimpleSAML\Module\oidc\Utils\ClaimTranslatorExtractor; +use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; /** * @covers \SimpleSAML\Module\oidc\Controllers\UserInfoController @@ -37,6 +39,10 @@ class UserInfoControllerTest extends TestCase protected MockObject $userEntityMock; protected MockObject $psrHttpBridgeMock; protected MockObject $errorResponderMock; + protected MockObject $symfonyRequestMock; + protected MockObject $symfonyResponseMock; + protected MockObject $responseHeaderBagMock; + protected MockObject $httpFoundationFactoryMock; protected function setUp(): void { @@ -53,6 +59,15 @@ protected function setUp(): void $this->psrHttpBridgeMock = $this->createMock(PsrHttpBridge::class); $this->errorResponderMock = $this->createMock(ErrorResponder::class); + + $this->symfonyRequestMock = $this->createMock(\Symfony\Component\HttpFoundation\Request::class); + $this->symfonyResponseMock = $this->createMock(\Symfony\Component\HttpFoundation\Response::class); + $this->responseHeaderBagMock = $this->createMock(ResponseHeaderBag::class); + $this->symfonyResponseMock->headers = $this->responseHeaderBagMock; + + $this->httpFoundationFactoryMock = $this->createMock(HttpFoundationFactory::class); + $this->httpFoundationFactoryMock->method('createResponse')->willReturn($this->symfonyResponseMock); + $this->psrHttpBridgeMock->method('getHttpFoundationFactory')->willReturn($this->httpFoundationFactoryMock); } protected function mock(): UserInfoController @@ -236,4 +251,63 @@ public function testItUsesRequestTrait(): void { $this->assertContains(RequestTrait::class, class_uses(UserInfoController::class)); } + + public function testItAlwaysReturnsAccessControlAllowOrigin(): void + { + $this->responseHeaderBagMock->expects($this->once())->method('set') + ->with('Access-Control-Allow-Origin', '*'); + + $this->authorizationServerRequestMock + ->expects($this->atLeast(2)) + ->method('getAttribute') + ->willReturnCallback(function ($argument) { + $argumentValueMap = [ + 'oauth_access_token_id' => 'tokenid', + 'oauth_scopes' => ['openid', 'email'], + ]; + + if (array_key_exists($argument, $argumentValueMap)) { + return $argumentValueMap[$argument]; + } + + return null; + }); + $this->resourceServerMock + ->expects($this->once()) + ->method('validateAuthenticatedRequest') + ->willReturn($this->authorizationServerRequestMock); + $this->accessTokenEntityMock + ->expects($this->once()) + ->method('getUserIdentifier') + ->willReturn('userid'); + $this->accessTokenEntityMock + ->expects($this->once()) + ->method('getRequestedClaims') + ->willReturn([]); + $this->accessTokenRepositoryMock + ->expects($this->once()) + ->method('findById') + ->willReturn($this->accessTokenEntityMock); + $this->userEntityMock + ->expects($this->atLeast(2)) + ->method('getClaims') + ->willReturn(['mail' => ['userid@localhost.localdomain']]); + $this->userRepositoryMock + ->expects($this->once()) + ->method('getUserEntityByIdentifier') + ->with('userid') + ->willReturn($this->userEntityMock); + $this->claimTranslatorExtractorMock + ->expects($this->once()) + ->method('extract') + ->with(['openid', 'email'], ['mail' => ['userid@localhost.localdomain']]) + ->willReturn(['email' => 'userid@localhost.localdomain']); + $this->claimTranslatorExtractorMock + ->expects($this->once()) + ->method('extractAdditionalUserInfoClaims') + ->with([], ['mail' => ['userid@localhost.localdomain']]) + ->willReturn([]); + + $this->mock()->userInfo($this->symfonyRequestMock); + } }