ServiceStack seems to be removing trailing "=" from redis password

We are currently looking to switch from redis hosted in-house to Azure Redis Cache.

On modifying the connection string with the azure redis host name and password, I started getting “invalid password” exceptions.

Digging in, via the debugger I noticed that

(RedisResolver)this._pooledClientManager.RedisResolver).Masters[0].Password

is missing the trailing “=” sign.

The code that hydrates this looks correct to me:

  _pooledClientManager =
                new PooledRedisClientManager(
                    writeHostEndpoints.Select(endpoint => endpoint.ToString()),
                    readHostEndpoints.Select(endpoint => endpoint.ToString()),
                    XEnvironment.ConnectionPoolSize.HasValue
                        ? new RedisClientManagerConfig
                        {
                            MaxWritePoolSize = XEnvironment.WriteHosts.Length*XEnvironment.ConnectionPoolSize.Value,
                            MaxReadPoolSize = XEnvironment.ReadHosts.Length*XEnvironment.ConnectionPoolSize.Value
                        }
                        : null) {PoolTimeout = XEnvironment.ConnectionPoolTimeout, ConnectTimeout = XEnvironment.SocketConnectionTimeout};

Note that

writeHostEndpoints.Select(endpoint => endpoint.ToString()

and

readHostEndpoints.Select(endpoint => endpoint.ToString())

both yield endpoints that still contain the trailing “=” , so it seems like the issue is somewhere in PooledRedisClientManager.

I did the following workaround hack so that I could continue my Azure Redis evaluation, though I would strongly prefer a fix or some guidance on what I did wrong.

var redisResolver = ((RedisResolver)this._pooledClientManager.RedisResolver);

                for (int i = 0; i < redisResolver.Masters.Count(); i++)
                {
                    var ep = redisResolver.Masters[i];
                    if (ep.Password != XEnvironment.ConnectionPassword)
                    {
                        ep.Password = XEnvironment.ConnectionPassword;
                    }

                
                }

                for (int i = 0; i < redisResolver.Slaves.Count(); i++)
                {
                    var ep = redisResolver.Slaves[i];
                    if (ep.Password != XEnvironment.ConnectionPassword)
                    {
                        ep.Password = XEnvironment.ConnectionPassword;
                    }
                    
                }

Thank you!

What connection string are you using? The password can be configured on the queryString of the connection string with:

127.0.0.1:6379?password={Password}    

Where the password should be URL Encoded.

Password was setup in code like so:

 endPoint.Password = "{password}";

I tried it as you suggested, URL encoding the password in the connection string… and same thing, that trailing equal sign is lopped off. Very strange.

I’m not seeing this behavior, I’ve tried to rerpo the issue in these tests but they both work as intended:

[Test]
public void Can_use_password_with_equals()
{
    var connString = "127.0.0.1?password=" + "p@55w0rd=".UrlEncode();

    var config = connString.ToRedisEndpoint();
    Assert.That(config.Password, Is.EqualTo("p@55w0rd="));
}

[Test, Ignore("Requires redis-server configured with 'requirepass p@55w0rd='")]
public void Can_connect_to_redis_with_password_with_equals()
{
    var connString = "127.0.0.1?password=" + "p@55w0rd=".UrlEncode();
    var redisManager = new PooledRedisClientManager(connString);
    using (var redis = redisManager.GetClient())
    {
        Assert.That(redis.Password, Is.EqualTo("p@55w0rd="));
    }
}

Can you provide a failing test with an example password that fails that I can use to repro this issue?

Sure, I can replicate like this:

	var ep = "xxxxxx-xxxx-redis-dev.redis.cache.windows.net".ToRedisEndpoint();
		ep.Password = "p@55w0rd=";
		Console.WriteLine(ep.ToString());
		Console.WriteLine("\n");


		var pooledManager = new PooledRedisClientManager(ep.ToString());
		Console.WriteLine(((RedisResolver) pooledManager.RedisResolver).Masters[0].ToString());
		Console.WriteLine("\n");

Output:

xxxxxx-xxxx-redis-dev.redis.cache.windows.net:6379?Password=p@55w0rd=


55w0rd=:6379?Client=xxxxxx-xxxx-redis-dev.redis.cache.windows.net&Password=6379?Password=p

If I UrlEncode the password in code it does seem to work. Personally, when setting the password explicitly in code (vs connection string) I don’t think it should have to be encoded first, but I won’t lose sleep over it. Changing that behavior now would likely break someone else’s code.

Thanks!

ok it wasn’t expected to serialize the endpoint as a string and augment it as the connection string can be passed directly into the Client Managers. But this should now be fixed with this commit where it just needed to URL Encode the password when serializing the RedisEndpoint config to a URL.

1 Like