-
Notifications
You must be signed in to change notification settings - Fork 387
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
feat(core): improve SASL interface #546
Conversation
As for testing, the same method outlined in #533 can be used. |
bc487a4
to
8d19b07
Compare
463face
to
d41a7d6
Compare
This PR looks good. Was able to test this as well. See test below Test:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concerning connection using Kerberos, how are you managing the tickets renewal? It seems like the client must handle this, in case of re-connection
else: | ||
client._session_callback(KeeperState.CONNECTED) | ||
self._ro_mode = None | ||
def _authenticate_with_sasl(self, host, timeout): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a possibility I thought of when developping the initial DIGEST-MD5 SASL connection but I am not sure if, while authenticating using SASL, the zk server can not send the client any other kind of messages... I also noticed that, in the official java zk client, the choice was made to handle SASL packets in the readResponses()
loop (see https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java#L876)
On your side, what do you think would be the best?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that no other message can be exchanged during the SASL negotiation (and this block 879-885 seems to confirm it).
Also, while I was working on this and the pure-sasl patch for DIGEST-MD5, I modified a Zookeeper LUA dissector for Wireshark and I did not see any other messages.
That being said, Zookeeper is a little light on protocol specs, so I can double check that assumption, maybe something like Pings are still possible if I pause for long enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is safer to keep it the way it was currently done because, even if currently nothing might happen, we don't know what will happen in future release. Moreover, I am also not sure how this will behave when using watchers that are waiting for KazooState.CONNECTED
state (that you are setting before the sasl authentication) to be spawned. In my development, that was the reason why I set the state after the sasl authentication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have studied the Java client code and it seems to me that no other packet is allowed while SASL negotiation is in progress. Their code goes to great length to bypass all send queue during that process and that the packets are strict XID for XID request/response exchanges:
- https://github.com/apache/zookeeper/blob/caca062767c36525e6ecead2ae0f34c447394809/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxnSocketNIO.java#L170
- https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java#L890
- https://github.com/apache/zookeeper/blob/cb9f303bda9137d1aebe8eff3eab85c8a59f3cdd/zookeeper-server/src/main/java/org/apache/zookeeper/client/ZooKeeperSaslClient.java#L296
Furthermore, the client also does check that the state is CONNECTED
or CONNECTEDREADONLY
before starting the SASL authentication:
- https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java#L1163
- https://github.com/apache/zookeeper/blob/22e4acc802904231d537ae18f479cfc729851d87/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java#L638
This indicate the the SASL negotiation only starts once the connection to the server is established (which means a CONNECTED
event was already emitted), which my PR emulates. Note that native forms of authentication, when passed in as auth_data
, are also evaluated right after the client reaches the connected state.
The only possible downside to my approach is a connection watcher would get a CONNECTED
event followed by a LOST
which is already possible (networks can fail) and what happens with native authentication schemes.
Looking at the links above, what do you think? Do you agree with my interpretation?
As for factoring out the SASL negotiation in its own function, since only SASL packets can be sent during the authentication process anyway, and only during connection, I do not see how this could bite us down the road (and it definitely made my PR less invasive).
If you still feel strongly about this, can you give me guidance as to how you would tackle integrating the SASL loop, with the above state conditions, in the main send/receive loop?
Also, could this be done in a different refactoring PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all those links, you are right, I missed the findSendablePacket
method and it really seems nothing can happen during the SASL authentication. It makes totally sense to do the things the way you suggest.
I do not try to implement a ticket cache that would try to leverage keytabs to refresh tickets. Java does this because they are going down the rabbit hole of trying to abstract the OS but this is far from trivial. You would have to consider all the options provided in the JAAS config (use cache, use keytabs etc), and have some tooling to understand the expiration and renewals options of tickets. Full disclosure: we have a completely managed environment in this regard so we did not need this functionality at work. |
I agree with you, you certainly know better Kerberos than me. Maybe we could also add those informations in the documentation in order to help any user for the settings? |
8cb6748
to
f6199b1
Compare
* Move SASL configuration out of auth_data into its own dictionary which exposes more SASL features (e.g. server service name, client principal, ...). Legacy syntax is still supported for backward compatibiltiy. * Remove SASL from auth_data and place it between 'connection' and 'zookeeper protocol level authentication' to simplify connection logic and bring code in line with the protocol stack (SASL wraps Zookeeper, not the other way around). * Consistent exception, `AuthFailedError`, raised during authentication failure between SASL and ZK authentication. * New 'SASLException' exception raised in case of SASL intrisinc failures. * Add support for GSSAPI (Kerberos). Example connection using Digest-MD5: client = KazooClient( sasl_options={'mechanism': 'DIGEST-MD5', 'username': 'myusername', 'password': 'mypassword'} ) Example connection using GSSAPI (with some optional settings): client = KazooClient( sasl_options={'mechanism': 'GSSAPI', 'service': 'myzk', # optional 'principal': 'clt@EXAMPLE.COM'} # optional )
Thanks a lot for this PR and for your awesome work. |
Merged to master, and might be a 2.7.0 Kazoo version on its own. |
Hi @StephenSorriaux, are there any plans to cut a release for this feature soon? |
Hi @anthonyliao, I would like to also merge #547 for the 2.7.0 version. Unfortunately, I did not find time to review / update it for now... |
@StephenSorriaux @anthonyliao I would like to investigate the high rate of "timeouts" in the Travis integration jobs too. I think I traced it to the |
feat(core): improve SASL interface
exposes more SASL features (e.g. server service name, client principal,
...). Legacy syntax is still supported for backward compatibility.
'zookeeper protocol level authentication' to simplify connection logic
and bring code in line with the protocol stack (SASL wraps Zookeeper,
not the other way around).
AuthFailedError
, raised during authenticationfailure between SASL and ZK authentication.
failures.
Example connection using Digest-MD5:
Example connection using GSSAPI (with some optional settings):
I provided patches to pure-sasl to fix its DIGEST support but got pulled in by other projects before I could get around to clean it up, get legal approval, and contribute this back.
This is a rebase of code we have had in production for over a year now, with both DIGEST and GSSAPI authentications.
I have found this approach to be cleaner then trying to mix SASL data with Zookeeper's own auth_data.
Disclaimer from my employer: