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

RedisURI class does not parse password when using redis-sentinel #1232

Closed
kyrogue opened this issue Feb 19, 2020 · 7 comments
Closed

RedisURI class does not parse password when using redis-sentinel #1232

kyrogue opened this issue Feb 19, 2020 · 7 comments
Labels
type: documentation A documentation update
Milestone

Comments

@kyrogue
Copy link

kyrogue commented Feb 19, 2020

Bug Report

If our redis sentinel setup has password setup on the sentinel instances, providing the connection string of the format 'redis-sentinel://[email protected]:26379/0#mymaster' will cause it to report NOAUTH Authentication required, however if we remove the password setup on the sentinel instances, it will work as expected; that is it directs us to the redis master instance.

Current Behavior

13:10:52.374 [main] ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: Error instantiating bean of type [io.lettuce.core.api.StatefulRedisConnection]: null
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type [io.lettuce.core.api.StatefulRedisConnection]: null
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1626)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2307)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1989)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1102)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:615)
        at io.micronaut.context.BeanLocator.findBean(BeanLocator.java:135)
        at io.micronaut.configuration.lettuce.RedisConnectionUtil.lambda$findRedisConnection$5(RedisConnectionUtil.java:56)
        at java.base/java.util.Optional.orElseGet(Optional.java:369)
        at io.micronaut.configuration.lettuce.RedisConnectionUtil.findRedisConnection(RedisConnectionUtil.java:56)
        at io.micronaut.configuration.lettuce.session.RedisSessionStore.findRedisConnection(RedisSessionStore.java:415)
        at io.micronaut.configuration.lettuce.session.RedisSessionStore.<init>(RedisSessionStore.java:129)
        at io.micronaut.configuration.lettuce.session.$RedisSessionStoreDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2307)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1989)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1082)
        at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
        at io.micronaut.session.binder.$SessionArgumentBinderDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        at io.micronaut.context.DefaultBeanContext.addCandidateToList(DefaultBeanContext.java:2630)
        at io.micronaut.context.DefaultBeanContext.getBeansOfTypeInternal(DefaultBeanContext.java:2552)
        at io.micronaut.context.DefaultBeanContext.getBeansOfType(DefaultBeanContext.java:911)
        at io.micronaut.context.AbstractBeanDefinition.lambda$getBeansOfTypeForConstructorArgument$10(AbstractBeanDefinition.java:1120)
        at io.micronaut.context.AbstractBeanDefinition.resolveBeanWithGenericsFromConstructorArgument(AbstractBeanDefinition.java:1758)
        at io.micronaut.context.AbstractBeanDefinition.getBeansOfTypeForConstructorArgument(AbstractBeanDefinition.java:1115)
        at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:990)
        at io.micronaut.http.bind.$DefaultRequestBinderRegistryDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2307)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1989)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1082)
        at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
        at io.micronaut.http.server.netty.$NettyRequestArgumentSatisfierDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2307)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1989)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1082)
        at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
        at io.micronaut.http.server.netty.$NettyHttpServerDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2307)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:1989)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:1963)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1102)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:615)
        at io.micronaut.context.BeanLocator.findBean(BeanLocator.java:135)
        at io.micronaut.runtime.Micronaut.start(Micronaut.java:71)
        at io.micronaut.runtime.Micronaut.run(Micronaut.java:307)
        at io.micronaut.runtime.Micronaut.run(Micronaut.java:293)
        at redis.world.Application.main(Application.java:8)
Caused by: io.lettuce.core.RedisConnectionException: null
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:75)
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56)
        at io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:235)
        at io.lettuce.core.RedisClient.connect(RedisClient.java:204)
        at io.lettuce.core.RedisClient.connect(RedisClient.java:189)
        at io.micronaut.configuration.lettuce.AbstractRedisClientFactory.redisConnection(AbstractRedisClientFactory.java:51)
        at io.micronaut.configuration.lettuce.DefaultRedisClientFactory.redisConnection(DefaultRedisClientFactory.java:52)
        at io.micronaut.configuration.lettuce.$DefaultRedisClientFactory$RedisConnectionDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1598)
        ... 53 common frames omitted
Caused by: io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required.
        at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135)
        at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:108)
        at io.lettuce.core.RedisPublisher$SubscriptionCommand.complete(RedisPublisher.java:751)
        at io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:646)
        at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:604)
        at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:556)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514)
        at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:834)

Environment

  • Lettuce version(s): 5
  • Redis version:5.0.7
@kyrogue kyrogue added the type: bug A general bug label Feb 19, 2020
@mp911de
Copy link
Collaborator

mp911de commented Feb 19, 2020

The password configured via a String-based RedisURI is used for master/replica authentication only. Sentinel authentication is a relatively new feature and there's typically no correlation between Sentinel- and data node password. This is why we decided to not automatically apply the password to Sentinel nodes as it would break a lot of existing applications.

Please provide a RedisURI object for configuration like the one below:

RedisURI redisURI = RedisURI.create("redis-sentinel://password@localhost:26379/0#mymaster");
redisURI.getSentinels().forEach(it -> it.setPassword("my-sentinel-password"));

Since the URI format is not flexible enough to represent multiple passwords, especially in the light that Redis 6 is going to ship username and password support, we cannot really do anything useful here. Adding query parameters (sentinelUsername=…&sentinelPassword=…) do not seem a good fit.

@mp911de mp911de added status: waiting-for-triage and removed type: bug A general bug labels Feb 19, 2020
@kyrogue
Copy link
Author

kyrogue commented Feb 19, 2020

no wonder.

I was expecting something of the format 'redis-sentinel://password@host1:26379,password@host2:26379/0#mymaster' to work.

Because if we look at the documentation for RedisURI , the format specifies the password in the connection string.

@mp911de
Copy link
Collaborator

mp911de commented Feb 19, 2020

The URI format specifies [ userinfo "@" ] host [ ":" port ] as authority. password@host1:26379,password@host2 would help to specify a password per Sentinel but no longer the data node password.

@kyrogue
Copy link
Author

kyrogue commented Feb 20, 2020

when you say userinfo, what does userinfo exactly mean?
If we look at https://lettuce.io/core/5.1.7.RELEASE/api/io/lettuce/core/RedisURI.html under redis sentinel it mentions password.

So to confirm, for the redis-sentinel connection string, the password@ is actually talking about the redis master password? and not the sentinel instance password ( which is not supported right now )

Also in the connection string it uses the fragment &sentinelMasterId=mymaster , however that does not seem to work, instead i had to use #/mymaster. Is this the correct way?

@mp911de
Copy link
Collaborator

mp911de commented Feb 20, 2020

userinfo is the part after :// and before the host name (password@, :password, username:password@).

Regarding the master Id, bot approaches, the fragment and sentinelMasterId are picked up. In some setups, the fragment was stripped down from the URL and so we had to fall back to the query string.

@mp911de
Copy link
Collaborator

mp911de commented Feb 21, 2020

The docs are updated now to reflect the actual behavior.

@pskowronek
Copy link

@mp911de Shouldn't we reconsider returning to this issue and address that as an enhancement?

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

No branches or pull requests

3 participants