-
-
Notifications
You must be signed in to change notification settings - Fork 527
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
authenticate on every request to broker when needed #1241
Conversation
Is this issue really limited to heartbeats? From reading the issue description, it sounds like the problem should occur on any request if the broker needs to reauthenticate. If that's the case, then we could do the same thing in sendRequest, except when the request is |
yes, it can happend at any point. I will add it into [sendRequest]. |
Not sure it matters much, but you could grab the api key of ApiVersions from |
@Nevon everything should be ok now. Can you please check? :) Thanks. |
I've been trying to figure out how to test this, and I wrote a test that looks something like this: test('Reauthenticates if needed before making a request', async () => {
const saslEntry = saslEntries.pop()
const connection = createConnection(saslEntry.opts())
broker = new Broker({
connection,
logger: newLogger(),
})
await broker.connect()
const spy = jest.spyOn(connection, 'send')
broker.authenticatedAt = null
await broker.listGroups()
// Assert that sasl authenticate requests happen
console.log(spy.mock.calls)
}) But I ran into the problem that the server rejects the second authentication request with an ILLEGAL_SASL_STATE error. This got me thinking and reading the KIP about reauthentication. In the current implementation, if you have multiple requests going on when you realize that you have to reauthenticate, each one is going to try to reauthenticate, which is gonna cause a problem. This is relatively easily solved by having the async isAuthenticated() {
try {
await this.authLock.acquire()
return this.authenticatedAt != null && !this[PRIVATE.SHOULD_REAUTHENTICATE]()
} finally {
await this.authLock.release()
}
} Unfortunately it makes the method async, which ripples through and affects a lot of things. A pain in the ass to fix, but doable. But it doesn't explain why I fail to authenticate. In my test I'm not making concurrent requests that trigger multiple authentications. I'm just authenticating once, then making it appear that I need to reauthenticate, and then I trigger a request that will cause me to reauthenticate. |
What do you think about putting |
You might want to look at the sharedPromise in utils. Heartbeat() is
wrapped with this so that when multiple are issues concurrently, only 1
actual request is sent.
…On Tue, 30 Nov 2021, 17:21 Tommy Brunn, ***@***.***> wrote:
I've been trying to figure out how to test this, and I wrote a test that
looks something like this:
test('Reauthenticates if needed before making a request', async () => {
const saslEntry = saslEntries.pop()
const connection = createConnection(saslEntry.opts())
broker = new Broker({
connection,
logger: newLogger(),
})
await broker.connect()
const spy = jest.spyOn(connection, 'send').mockImplementation()
broker.authenticatedAt = null
await broker.listGroups()
// Assert that sasl authenticate requests happen
console.log(spy.mock.calls)})
But I ran into the problem that the server rejects the second
authentication request with an ILLEGAL_SASL_STATE error. This got me
thinking and reading the KIP about reauthentication
<https://cwiki.apache.org/confluence/display/KAFKA/KIP-368%3A+Allow+SASL+Connections+to+Periodically+Re-Authenticate>
.
In the current implementation, if you have multiple requests going on when
you realize that you have to reauthenticate, each one is going to try to
reauthenticate, which is gonna cause a problem. This is relatively easily
solved by having the isAuthenticated method wait for the authLock to be
released, so that you wait to check if you need to authenticate while
there's an authentication going on. Unfortunately it makes the method
async, which ripples through and affects a lot of things. A pain in the ass
to fix, but doable.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1241 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABDLW5TG5ZGLFA6B4MGVTFTUOSJQLANCNFSM5I6ZIHQQ>
.
|
|
No, but I think it's an issue with the test. Maybe you can't authenticate again right after authenticating with sasl/scram like I'm doing. I'm guessing if you swap it out for oauthbearer with a short reauthentication timeout maybe it'll work. I just didn't have time to test it out.
I would be very surprised if it isn't. Tossing |
Ok then, are you ok to handle it with
|
Sounds like a good solution! Let's give it a try. I would also really like to test these scenarios. We do have a test suite that uses oauthbearer, which should certainly allow for reauthentication. See the |
Hi @Nevon, I implemented tests and sorry it took longer time. I had issues with kafka SASL OAUTHBEARER authentication. Within test, the kafka returned me all the time that provided token created in test utils is invalid and I didn't know why. After debugging and looking to how other kafka clients are implemented, I found out that expiration time was missing in the token. Btw. you were right with multiple parallel requests causing error: when I removed fix with Can you please check PR again when you will have time? If all will be good, can you merge it and release? Thank you very much. |
@Nevon just a gentle reminder :) |
Haven't forgotten about you. I left the notification sitting on my phone so it wouldn't get lost. 😅 The change looks good overall - I'd just like to get your thoughts on whether we can get rid of those sleeps in the test (or at least reduce them). |
src/broker/index.js
Outdated
*/ | ||
this[PRIVATE.AUTHENTICATE] = sharedPromiseTo(async () => { | ||
try { | ||
await this.authLock.acquire() |
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.
We don't need this lock anymore now right? If there's more callers, the first one will create a promise and start the authentication, the second one will just receive the promise from the first one so it'll just await the promise settlement from the first one. Since the promise creation itself is synchronous there shouldn't be any race condition there, I think.
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.
yes you are right. I will remove auth lock.
…re waiting a long time to re-authenticate
@Nevon done, now my test is faster by 30 seconds (14s vs 44s). |
Thanks for your patience and for taking the time to contribute! |
Fixes #1240