Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JWT key permission check always fails on Windows #2904

Open
rmobis opened this issue Dec 28, 2022 · 3 comments
Open

JWT key permission check always fails on Windows #2904

rmobis opened this issue Dec 28, 2022 · 3 comments
Labels

Comments

@rmobis
Copy link

rmobis commented Dec 28, 2022

PHP Version

8.1.13

Shopware Version

6.4.18.0

Expected behaviour

After a fresh install on Windows and having generated the required jwt/config/private.pem and jwt/config/public.pem files, starting the server symfony server:start -d and accessing the admin login page, both files should be correctly read from disk so the authorization server can be instantiated by the container and the whole page can function.

Actual behaviour

You get an exception:

{
	code: "0",
	status: "500",
	title: "Internal Server Error",
	detail: "User Notice: Key file "file://C:\projects\personal\project/config/jwt/public.pem" permissions are not correct, recommend changing to 600 or 660 instead of 666",
	meta: {
		// ...
	}
}
Full API Response
{
	"errors": [
		{
			"code": "0",
			"status": "500",
			"title": "Internal Server Error",
			"detail": "User Notice: Key file \u0022file://C:\\projects\\personal\\project/config/jwt/public.pem\u0022 permissions are not correct, recommend changing to 600 or 660 instead of 666",
			"meta": {
				"trace": [
					{
						"file": "C:\\projects\\personal\\project\\var\\cache\\dev_hae705bf1e4f7057c4da9d57bc278047b\\Container5V6QJWM\\Shopware_Core_KernelDevDebugContainer.php",
						"line": 22661,
						"function": "__construct",
						"class": "League\\OAuth2\\Server\\CryptKey",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\var\\cache\\dev_hae705bf1e4f7057c4da9d57bc278047b\\Container5V6QJWM\\Shopware_Core_KernelDevDebugContainer.php",
						"line": 11913,
						"function": "getApiAuthenticationListenerService",
						"class": "Container5V6QJWM\\Shopware_Core_KernelDevDebugContainer",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\event-dispatcher\\EventDispatcher.php",
						"line": 245,
						"function": "Container5V6QJWM\\{closure}",
						"class": "Container5V6QJWM\\Shopware_Core_KernelDevDebugContainer",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\event-dispatcher\\EventDispatcher.php",
						"line": 76,
						"function": "sortListeners",
						"class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\Content\\Flow\\Dispatching\\FlowDispatcher.php",
						"line": 126,
						"function": "getListeners",
						"class": "Symfony\\Component\\EventDispatcher\\EventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\Framework\\Webhook\\WebhookDispatcher.php",
						"line": 161,
						"function": "getListeners",
						"class": "Shopware\\Core\\Content\\Flow\\Dispatching\\FlowDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\Framework\\Event\\BusinessEventDispatcher.php",
						"line": 100,
						"function": "getListeners",
						"class": "Shopware\\Core\\Framework\\Webhook\\WebhookDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\Framework\\Event\\NestedEventDispatcher.php",
						"line": 69,
						"function": "getListeners",
						"class": "Shopware\\Core\\Framework\\Event\\BusinessEventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\event-dispatcher\\Debug\\TraceableEventDispatcher.php",
						"line": 293,
						"function": "getListeners",
						"class": "Shopware\\Core\\Framework\\Event\\NestedEventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\event-dispatcher\\Debug\\TraceableEventDispatcher.php",
						"line": 148,
						"function": "preProcess",
						"class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpKernel.php",
						"line": 139,
						"function": "dispatch",
						"class": "Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpKernel.php",
						"line": 75,
						"function": "handleRaw",
						"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\Kernel.php",
						"line": 202,
						"function": "handle",
						"class": "Symfony\\Component\\HttpKernel\\HttpKernel",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpCache\\SubRequestHandler.php",
						"line": 86,
						"function": "handle",
						"class": "Symfony\\Component\\HttpKernel\\Kernel",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpCache\\HttpCache.php",
						"line": 479,
						"function": "handle",
						"class": "Symfony\\Component\\HttpKernel\\HttpCache\\SubRequestHandler",
						"type": "::"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpCache\\HttpCache.php",
						"line": 452,
						"function": "forward",
						"class": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpCache\\HttpCache.php",
						"line": 346,
						"function": "fetch",
						"class": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\http-kernel\\HttpCache\\HttpCache.php",
						"line": 224,
						"function": "lookup",
						"class": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\HttpKernel.php",
						"line": 154,
						"function": "handle",
						"class": "Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\shopware\\core\\HttpKernel.php",
						"line": 79,
						"function": "doHandle",
						"class": "Shopware\\Core\\HttpKernel",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\public\\index.php",
						"line": 76,
						"function": "handle",
						"class": "Shopware\\Core\\HttpKernel",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\symfony\\runtime\\Runner\\Symfony\\HttpKernelRunner.php",
						"line": 35,
						"function": "handle",
						"class": "Symfony\\Component\\HttpKernel\\HttpKernelInterface@anonymous\u0000C:\\projects\\personal\\project\\public\\index.php:66$1776",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\vendor\\autoload_runtime.php",
						"line": 29,
						"function": "run",
						"class": "Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner",
						"type": "-\u003E"
					},
					{
						"file": "C:\\projects\\personal\\project\\public\\index.php",
						"line": 12,
						"args": [
							"C:\\projects\\personal\\project\\vendor\\autoload_runtime.php"
						],
						"function": "require_once"
					}
				],
				"file": "C:\\projects\\personal\\project\\vendor\\league\\oauth2-server\\src\\CryptKey.php",
				"line": 80
			}
		}
	]
}

How to reproduce

On a Windows 11 machine, with PHP v8.1.13, Symfony CLI v5.4.20 and Docker v20.10.21 installed, run the following commands, from this repository's README.md:

> composer create-project shopware/production:dev-flex project
> cd project
> docker compose up -d
> symfony console system:install --basic-setup --drop-database --create-database -f
> symfony server:start -d

Then, generate your secret files and remember to set the password to shopware:

> openssl genrsa -out ./config/jwt/private.pem -aes256 4096
> openssl rsa -pubout -in ./config/jwt/private.pem -out ./config/jwt/public.pem

Edit the ,env file at the root to set APP_ENV=dev and finally, visit localhost:8000/admin. You should be greeted with the previously mentioned error.

Further Context

This happens because League\OAuth2\Server\CryptKey::__construct by default checks for file permissions. While that is a perfectly valid idea in Linux, in Windows files don't follow a similar permission system as as such, when requested, PHP always returns 666. This can be a pain for Windows developers and packages such as laravel/passport have decided to disable it by default, by passing the false as the third parameter of the constructor. It seems to be the maintainers "recommendation" as per thephpleague/oauth2-server#779.

Now I'm really new to Shopware (this really was my first attempt at installing it), but it seems to me that simply editing shopware\core\Framework\DependencyInjection\api.xml definitions to pass false as the last argument should work. For testing purposes, I replaced old definitions in my vendor folder with the ones below, and it worked™.

<service class="League\OAuth2\Server\CryptKey" id="shopware.private_key">
    <argument>file://%kernel.project_dir%/config/jwt/private.pem</argument>
    <argument>shopware</argument>
+    <argument>false</argument>
</service>
<service class="League\OAuth2\Server\CryptKey" id="shopware.public_key">
    <argument>file://%kernel.project_dir%/config/jwt/public.pem</argument>
+    <argument>null</argument>
+    <argument>false</argument>
</service>

Perhaps not always disabling it, but only on Windows? I think this could be done with <argument type="expression">PHP_OS_FAMILY !== 'Windows'</argument>, but I haven't tested it.

Either way, I would be happy to work on a PR to solve this issue if you could point me in the right direction.

@rmobis rmobis added the Bug label Dec 28, 2022
@shyim
Copy link
Member

shyim commented Dec 28, 2022

Another approach could be to do an CompilerPass. Feel free to make a PR, but we officially don't support Windows. So I assume there are a lot of other problems

@rmobis
Copy link
Author

rmobis commented Dec 31, 2022

@shyim which of those approaches would you guess would be better? Just so I know where to start.

  1. Disabling permission checks by default
  2. Disabling permission checks on Windows only, using a <argument type="expression"> tag
  3. Disabling permission checks on Windows only, doing a CompilePass

I understand getting this to work on Windows is gonna be a battle, but I'd like to entertain it.

@shyim
Copy link
Member

shyim commented Jan 27, 2023

Disabling permission checks on Windows only, doing a CompilePass

Sounds the best for me as expressions are on runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants