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

KAFKA-17415: Avoid overflow of expired timestamp #17026

Merged
merged 20 commits into from
Oct 6, 2024

Conversation

frankvicky
Copy link
Contributor

@frankvicky frankvicky commented Aug 28, 2024

JIRA: KAFKA-17415

Currently DelegationTokenControlManager does not handle the overflow, and hence setting a large max life time will cause a negative expired timestamp and negative max timestamp. That is unexpected behavior.

Committer Checklist (excluded from commit message)

  • Verify design and implementation
  • Verify test coverage and CI build status
  • Verify documentation (including upgrade notes)

@chia7712
Copy link
Member

chia7712 commented Sep 2, 2024

@frankvicky could you please fix conflicts?

@@ -178,6 +178,12 @@ class DelegationTokenManagerZk(config: KafkaConfig,

val issueTimeStamp = time.milliseconds
val maxLifeTime = if (maxLifeTimeMs <= 0) tokenMaxLifetime else Math.min(maxLifeTimeMs, tokenMaxLifetime)

if (checkTimestampOverflow(issueTimeStamp, maxLifeTime)) {
responseCallback(CreateTokenResult(owner, tokenRequester, -1, -1, -1, "", Array[Byte](), Errors.INVALID_TIMESTAMP))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we set upper bound Long.MAX_VALUE instead of throwing exception? That makes Long.MAX_VALUE valid in request. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, this change will make api easier to use.

@@ -292,6 +298,8 @@ class DelegationTokenManagerZk(config: KafkaConfig,
expireResponseCallback(Errors.NONE, now)
} else if (tokenInfo.maxTimestamp < now || tokenInfo.expiryTimestamp < now) {
expireResponseCallback(Errors.DELEGATION_TOKEN_EXPIRED, -1)
} else if (now > Long.MaxValue - expireLifeTimeMs) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should align the behavior of handling the overflow timestamp, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I missed it.
Thanks for pointing out 😸

@github-actions github-actions bot added core Kafka Broker kraft labels Sep 21, 2024
@chia7712
Copy link
Member

@frankvicky please rebase code to trigger CI again

val maxLifeTimeStamp = issueTimeStamp + maxLifeTime
val expiryTimeStamp = Math.min(maxLifeTimeStamp, issueTimeStamp + defaultTokenRenewTime)

val isOverflowed = checkTimestampOverflow(issueTimeStamp, maxLifeTime)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too complicated. Could you please add sum method?

    private static long sum(long now, long duration) {
        return Long.MAX_VALUE - now <= duration ? Long.MAX_VALUE : now + duration;
    }
        long maxTimestamp = sum(now, maxLifeTime);
        long expiryTimestamp = Math.min(maxTimestamp, sum(now, tokenDefaultRenewLifetimeMs));

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frankvicky thanks for your patch

@@ -294,7 +299,8 @@ class DelegationTokenManagerZk(config: KafkaConfig,
expireResponseCallback(Errors.DELEGATION_TOKEN_EXPIRED, -1)
} else {
//set expiry time stamp
val expiryTimeStamp = Math.min(tokenInfo.maxTimestamp, now + expireLifeTimeMs)
val expiryTimeStamp = if (now > Long.MaxValue - expireLifeTimeMs) Long.MaxValue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

val expiryTimeStamp = Math.min(tokenInfo.maxTimestamp, sum(now, expireLifeTimeMs))

long expiryTimestamp = Math.min(myTokenInformation.maxTimestamp(),
now + requestData.expiryTimePeriodMs());
} else {
long expiryTimestamp = now > Long.MAX_VALUE - requestData.expiryTimePeriodMs()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

long expiryTimestamp = Math.min(myTokenInformation.maxTimestamp(), sum(now, requestData.expiryTimePeriodMs()));

@@ -192,6 +193,10 @@ class DelegationTokenManagerZk(config: KafkaConfig,
}
}

private def sum(now: Long, duration: Long): Long = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the zk is dropping and we don't add tests for zk, so could you please revert those changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frankvicky thanks for this patch. one small question remains.

@@ -633,7 +633,7 @@ class SaslSslAdminIntegrationTest extends BaseAdminIntegrationTest with SaslSetu
@ValueSource(strings = Array("kraft"))
def testExpireDelegationToken(quorum: String): Unit = {
client = createAdminClient
val createDelegationTokenOptions = new CreateDelegationTokenOptions()
val createDelegationTokenOptions = new CreateDelegationTokenOptions().maxlifeTimeMs(5000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we need this change?

Copy link
Contributor Author

@frankvicky frankvicky Oct 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was made because the previous value of maxlifeTimeMs was 5000 milliseconds. Later, I modified the config to Long.MaxValue to test overflow scenarios. To avoid breaking the original test logic, I changed the CreateDelegationTokenOptions that used the default value to explicitly set .maxlifeTimeMs(5000).

Copy link
Member

@chia7712 chia7712 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chia7712 chia7712 merged commit 924c108 into apache:trunk Oct 6, 2024
6 checks passed
@frankvicky
Copy link
Contributor Author

I have updated the description due to removing zk.

tedyu pushed a commit to tedyu/kafka that referenced this pull request Jan 6, 2025
Both ZK and KRaft modes do not handle overflow, so setting a large max lifetime results in a negative expired timestamp and negative max timestamp, which is unexpected behavior.

In this PR, we are only fixing the KRaft code since ZK will be removed soon.

Reviewers: Chia-Ping Tsai <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants