Description
Symfony version(s) affected
6.3.9, 6.4., 7.0.
Description
With the resolution of #52420 via #52688, the addition of a rawurlencode
was given to each DSN parameters on the RedisTrait. If this solves the issue with a username/password containing meta-characters an URL can evaluates, such as :
, @
, #
, ?
, …, it causes a break down of applications when the username-password used to contain %
.
Let's imagine the password is "484fj%2aAYzt".
- With symfony/cache 6.3.8, when this password is given through the DSN, no
rawurlencode
of the password, so it matches and you're logged to your Redis server. - With symfony/cache 6.3.9, when this password is given through the DSN,
rawurlencode
is applied on the password, so it becomes "484fj*aYzt", and doesn't match anymore: you cannot log to your Redis server.
To give a little more context, here is how I create a CacheAdapter from RedisAdatper using service container definition:
services:
MyProject\RedisSentinel\CacheAdapter:
class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
arguments:
- !service
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- '@="redis:default:"~env("REDIS_PASSWORD")~"@?"~env("REDIS_SENTINEL_DSN_QUERY")'
This way, my CacheAdapter service is always directly setup without the need of handling all initialisation through classes, and it's definitly more performant. The REDIS_PASSWORD is given via env variable as it is reset each time a new deployment of the application is detected for security reasons. And of course, today, it contained a %
char for the first time since I migrated to 6.3.9.
So, with the current implementation, it seems that I can't trust symfony/cache package anymore since 6.3.9. I wish a solution could be found.
Thanks a lot.
How to reproduce
Mount a Redis or a RedisSentinel with a password containing a '%' character.
In your application, define the following service in your service container, and use it to try any action to the Redis[Sentinel] server (save a key, for instance)
services:
MyProject\RedisSentinel\CacheAdapter:
class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
arguments:
- !service
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- '@="redis:default:{{yourPasswordWith%Char}}@?{{yourRedisHost}}"
Run it with symfony/cache 6.3.8. Enjoy.
Run it with symfony/cache 6.3.9. Cry.
Possible Solution
The more global solution to me would be to add a static class member on the RedisTrait
to define if the DSN parameters should be decoded or not, settable via a setter, and depending on the flag value, the DSN parameters are url-decoded or not.
Another solution could be to add a way to url-encode env variables with the default EnvVarProcessor. Therefore, something like:
parameters:
redis_password: '%env(url_encode:REDIS_PASSWORD)%'
services:
MyProject\RedisSentinel\CacheAdapter:
class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
arguments:
- !service
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- '@="redis:default:"~parameter("redis_password")~"@?"~env("REDIS_SENTINEL_DSN_QUERY")'
could be possible. The env variable will be url_encoded, and when passed to the RedisAdapter when creating the connection, it will be decoded back.
Considering this solution could also help in solving similar issues on Mailer or other components where DSN are used, like #52420 told about.
Any other more elegant solutions are welcome too, of course 🙂
Thanks a lot!
Additional Context
No response