StackExchange / StackExchange.Redis

General purpose redis client
https://stackexchange.github.io/StackExchange.Redis/
Other
5.9k stars 1.51k forks source link

How to get the second levels of RedisObject? #2377

Open Fedack opened 1 year ago

Fedack commented 1 year ago

Greetings, I'm currently facing an issue.

I'm using execute to get ACL GETUSER and I am trying to parse the value of the permissions. This is to check they are correct.

I have this so far:

var getACL = db.Execute("ACL", "GETUSER", mac);
var acl = getACL.ToDictionary().FirstOrDefault(c => c.Key == "selectors").Value;
var aclSelectors = acl.ToDictionary();

Except, the problem is that acl.ToDictionary() returns an error saying System.InvalidCastException: 'Specified cast is not valid.'

What's the appropriate way to get the values?

NickCraver commented 1 year ago

@slorello89 Thoughts on this? I didn't even think of ACL commands when we did the bulk pass...

slorello89 commented 1 year ago

It would be nice to have the informational ACL commands - probably under IServer (they aren't actually server level but I think that's the more appropriate home) The actual authentication is done at the connection level - so it's something we'd need to think about a bit more - it could either be handled like SELECT's by the IDatabase, or we'd need some custom socket manager so we could split out connections (larger discussion around pooling) - by the way all this is why I left those commands off the table when we were talking about command modernization :)

NickCraver commented 1 year ago

@slorello89 oo I gotcha, so IServer makes sense with a standalone but not so much for cluster in this case for a cardinality mapping?

mgravell commented 1 year ago

Even if the question isn't about a single server, in a way IServer still makes sense because "who are you asking?" - it isn't like it is key-routable.

If I get a moment I might try to look at a short-term thing (re this ticket) of seeing how to issue it via Execute; it feels like that should still be possible, even if awkward and ugly. But I'm out until tomorrow.

slorello89 commented 1 year ago

@Fedack - sorry I didn't actually answer the meat of your question yesterday - wasn't at my desk so I couldn't look at it. Take this example:

ACL SETUSER alan allkeys +@string +@set (-SET ~key2) -SADD >alanpassword

This produces the result (when queried from the cli) of:

127.0.0.1:6379> ACL GETUSER alan
 1) "flags"
 2) 1) "off"
 3) "passwords"
 4) 1) "b9a6a68f0be27a1c1b4e54d719abeb7d7113db2a276270f14cbe2f72fbcc1186"
 5) "commands"
 6) "-@all +@string +@set -sadd"
 7) "keys"
 8) "~*"
 9) "channels"
10) ""
11) "selectors"
12) 1) 1) "commands"
       2) "-@all"
       3) "keys"
       4) "~key2"
       5) "channels"
       6) ""

When you run the line:

var acl = getACL.ToDictionary().FirstOrDefault(c => c.Key == "selectors").Value;

You are grabbing this portion of the result:

1) 1) "commands"
       2) "-@all"
       3) "keys"
       4) "~key2"
       5) "channels"
       6) ""

You'll notice that this is actually not a dictionary-like result (which is what you need to use ToDictionary on the Redis Result) rather it is an array with a single element (which is a dictionary-like result) - so you need to cast it to an array, extract the first element and then cast that to a dictionary:

if (acl != null && acl.Type == ResultType.MultiBulk)
{
    var aclSelectors =((RedisResult[])acl)[0].ToDictionary();
    Console.WriteLine(aclSelectors);
}

Some weird nonsense with NRTs going on with this snippet above 🤔 - but this ought to do it.

slorello89 commented 1 year ago

@NickCraver - ACLs should be identical throughout the deployment - I just think like @mgravell here in that I feel IServer is the more appropriate home ( I just think of anything in the data model as being in IDatabase whereas configuration things being IServer)

NickCraver commented 1 year ago

I'd agree with that - not sure what the full slate is here (and API surface area for response objects) but +1 to landing on IServer. Main focus at the moment is the async state machine/GC issue (#2408 repro), but would love to get these in overall.