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

Redis ACL Auth NOPERM Issue #1379

Closed
etherrien opened this issue Aug 3, 2020 · 3 comments
Closed

Redis ACL Auth NOPERM Issue #1379

etherrien opened this issue Aug 3, 2020 · 3 comments
Labels
status: declined A suggestion or change that we dont feel we should currently apply status: waiting-for-feedback We need additional information before we can continue

Comments

@etherrien
Copy link

etherrien commented Aug 3, 2020

Bug Report

When trying to use Redis 6 ACL Auth with username and password there is a NOPERM error.

Current Behavior

Stack trace
URI: redis://admin:admin@localhost
Exception in thread "main" io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379
	at lettuce.core@6.0.0.M1/io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78)
	at lettuce.core@6.0.0.M1/io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56)
	at lettuce.core@6.0.0.M1/io.lettuce.core.AbstractRedisClient.getConnection(AbstractRedisClient.java:295)
	at lettuce.core@6.0.0.M1/io.lettuce.core.RedisClient.connect(RedisClient.java:214)
	at lettuce.core@6.0.0.M1/io.lettuce.core.RedisClient.connect(RedisClient.java:199)
	at lettuceTest/lettuceTest.RedisCacheWriter.completeConstructor(RedisCacheWriter.java:71)
	at lettuceTest/lettuceTest.RedisCacheWriter.<init>(RedisCacheWriter.java:49)
	at lettuceTest/lettuceTest.RedisCacheWriter.main(RedisCacheWriter.java:41)
Caused by: io.lettuce.core.RedisCommandExecutionException: NOPERM this user has no permissions to run the 'hello' command or its subcommand
	at lettuce.core@6.0.0.M1/io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:137)
	at lettuce.core@6.0.0.M1/io.lettuce.core.internal.ExceptionFactory.createExecutionException(ExceptionFactory.java:110)
	at lettuce.core@6.0.0.M1/io.lettuce.core.protocol.AsyncCommand.completeResult(AsyncCommand.java:120)
	at lettuce.core@6.0.0.M1/io.lettuce.core.protocol.AsyncCommand.complete(AsyncCommand.java:111)
	at lettuce.core@6.0.0.M1/io.lettuce.core.protocol.CommandHandler.complete(CommandHandler.java:645)
	at lettuce.core@6.0.0.M1/io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:605)
	at lettuce.core@6.0.0.M1/io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:556)
	at io.netty.all@4.1.49.Final/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.all@4.1.49.Final/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.all@4.1.49.Final/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.all@4.1.49.Final/io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.all@4.1.49.Final/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.all@4.1.49.Final/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.all@4.1.49.Final/io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.all@4.1.49.Final/io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.all@4.1.49.Final/io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.all@4.1.49.Final/io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain(NioEventLoop.java:615)
	at io.netty.all@4.1.49.Final/io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:578)
	at io.netty.all@4.1.49.Final/io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.all@4.1.49.Final/io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.all@4.1.49.Final/io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.all@4.1.49.Final/io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)

Input Code

Input Code
    public static void main(String args[]) {
        RedisCacheWriter redis = new RedisCacheWriter();
    }
    
    public RedisCacheWriter() {
        RedisURI uri = getURI();
        client = RedisClient.create(uri);
        System.out.println("URI: " + uri);

        completeConstructor();
    }
    
    private void completeConstructor() {
        if (encryptionEnabled && redisTruststorePath != null && !redisTruststorePath.isEmpty()) {
            SslOptions sslOptions;
            if (redisKeystorePath != null && !redisKeystorePath.isEmpty()) {
                sslOptions = SslOptions.builder()
                        .jdkSslProvider()
                        .keystore(new File(redisKeystorePath), redisKeystorePass)
                        .truststore(new File(redisTruststorePath), redisTruststorePass)
                        .build();
            }
            else {
                sslOptions = SslOptions.builder()
                        .jdkSslProvider()
                        .truststore(new File(redisTruststorePath), redisTruststorePass)
                        .build();
            }
            client.setOptions(ClientOptions.builder().sslOptions(sslOptions).build());
        }
        
        connection = client.connect();
        
        System.out.println("connected");

        connection.sync().set("abc", "value");
        
        preDestroy();
    }

    public void preDestroy() {
        connection.close();
        client.shutdown();
    }
    
    public RedisURI getURI() {
        if (redisPass == null || redisPass.toString().isEmpty()) {
            // Don't use password or username
            return RedisURI.Builder.redis(hostConfig, portConfig).withSsl(encryptionEnabled).withVerifyPeer(false).build();
        }
        else if (redisUser == null || redisUser.isEmpty()) {
          // Use password without ACL username
            return RedisURI.Builder.redis(hostConfig, portConfig).withSsl(encryptionEnabled).withVerifyPeer(false)
                    .withPassword(redisPass).build();
        }
        // Use ACL username and password
        return RedisURI.Builder.redis(hostConfig, portConfig).withSsl(encryptionEnabled).withVerifyPeer(false)
                .withAuthentication(redisUser, redisPass).build();
    }

Expected behavior/code

To connect to Redis with no issues.

Environment

  • Lettuce version(s): 6.0.0.M1
  • Redis version: redis:6.0-alpine (Currently 6.0.5)

Additional context

Code works fine with no Auth, but once Auth is on I get that error. Redis is being run from a docker container, and I know Redis has Auth enabled correctly due to having to log in on the CLI with admin:admin as well as my C# client connecting fine with Auth enabled or disabled.

@etherrien etherrien added the type: bug A general bug label Aug 3, 2020
@etherrien
Copy link
Author

Redis Server Debug logs:

1:M 03 Aug 2020 13:55:26.148 - Accepted 10.0.2.2:54560
1:M 03 Aug 2020 13:55:26.169 - Client closed connection

@mp911de
Copy link
Collaborator

mp911de commented Aug 3, 2020

As per the logs:

Caused by: io.lettuce.core.RedisCommandExecutionException: NOPERM this user has no permissions to run the 'hello' command or its subcommand

There's nothing we can do from our side. Lettuce 6 uses a connection handshake to determine the protocol version. If you want to use Lettuce in RESP2 mode without protocol discovery, please switch to RESP2 and disable ping on connect via ClientOptions:

ClientOptions.builder().protocolVersion(ProtocolVersion.RESP2).pingBeforeActivateConnection(false).build()

Please note that just today we released Lettuce 6.0 RC1.

@mp911de mp911de added status: waiting-for-feedback We need additional information before we can continue status: declined A suggestion or change that we dont feel we should currently apply and removed type: bug A general bug labels Aug 3, 2020
@etherrien
Copy link
Author

Updated and switched to RESP2 worked! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we dont feel we should currently apply status: waiting-for-feedback We need additional information before we can continue
Projects
None yet
Development

No branches or pull requests

2 participants