Skip to content

[fix][broker] Fix token expiration - #16016

Merged
codelipenghui merged 1 commit into
apache:masterfrom
nodece:fix-token-expiration
Jun 15, 2022
Merged

[fix][broker] Fix token expiration#16016
codelipenghui merged 1 commit into
apache:masterfrom
nodece:fix-token-expiration

Conversation

@nodece

@nodece nodece commented Jun 11, 2022

Copy link
Copy Markdown
Member

Signed-off-by: Zixuan Liu nodeces@gmail.com

Motivation

When token expiration, the broker requests the client to refresh the token, then the broker performs org.apache.pulsar.broker.service.ServerCnx#doAuthentication when the broker receives the auth response, which uses org.apache.pulsar.broker.authentication.AuthenticationState#authenticate to authentication, but the org.apache.pulsar.broker.authentication.AuthenticationProviderToken.TokenAuthenticationState#authenticate doesn't do anything, this cause a loop to refresh the token.

Right now the token is only validated in the TokenAuthenticationState constructor, we need to add a check to the authenticate method.

Modifications

  • Add check the token expiration

Documentation

  • doc-not-needed
    Fix

@github-actions github-actions Bot added the doc-not-needed Your PR changes do not impact docs label Jun 11, 2022
@nodece
nodece force-pushed the fix-token-expiration branch from 265d2fb to ef237ab Compare June 11, 2022 04:50
@nodece

nodece commented Jun 11, 2022

Copy link
Copy Markdown
Member Author

/pulsarbot rerun-failure-checks

@codelipenghui codelipenghui added this to the 2.11.0 milestone Jun 12, 2022

@codelipenghui codelipenghui left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks the issue is introduced by #14044?

I just checked the branch-2.10

@Override
public AuthData authenticate(AuthData authData) throws AuthenticationException {
String token = new String(authData.getBytes(), UTF_8);
this.jwt = provider.authenticateToken(token);
this.authenticationDataSource = new AuthenticationDataCommand(token, remoteAddress, sslSession);
if (jwt.getBody().getExpiration() != null) {
this.expiration = jwt.getBody().getExpiration().getTime();
} else {
// Disable expiration
this.expiration = Long.MAX_VALUE;
}
// There's no additional auth stage required
return null;
}

private Jwt<?, Claims> authenticateToken(final String token) throws AuthenticationException {
try {
Jwt<?, Claims> jwt = parser.parseClaimsJws(token);
if (audienceClaim != null) {
Object object = jwt.getBody().get(audienceClaim);
if (object == null) {
throw new JwtException("Found null Audience in token, for claimed field: " + audienceClaim);
}
if (object instanceof List) {
List<String> audiences = (List<String>) object;
// audience not contains this broker, throw exception.
if (audiences.stream().noneMatch(audienceInToken -> audienceInToken.equals(audience))) {
throw new AuthenticationException("Audiences in token: [" + String.join(", ", audiences)
+ "] not contains this broker: " + audience);
}
} else if (object instanceof String) {
if (!object.equals(audience)) {
throw new AuthenticationException("Audiences in token: [" + object
+ "] not contains this broker: " + audience);
}
} else {
// should not reach here.
throw new AuthenticationException("Audiences in token is not in expected format: " + object);
}
}
if (jwt.getBody().getExpiration() != null) {
expiringTokenMinutesMetrics.observe(
(double) (jwt.getBody().getExpiration().getTime() - new Date().getTime()) / (60 * 1000));
}
return jwt;
} catch (JwtException e) {
if (e instanceof ExpiredJwtException) {
expiredTokenMetrics.inc();
}
throw new AuthenticationException("Failed to authentication token: " + e.getMessage());
}
}

@nodece

nodece commented Jun 13, 2022

Copy link
Copy Markdown
Member Author

@codelipenghui @RobertIndie Thanks for your review! These request changes have been fixed, could you review this PR again?

@nodece

nodece commented Jun 13, 2022

Copy link
Copy Markdown
Member Author

/pulsarbot rerun-failure-checks

Signed-off-by: Zixuan Liu <nodeces@gmail.com>
@nodece
nodece force-pushed the fix-token-expiration branch from 8e7686e to 5da0d10 Compare June 14, 2022 10:14
@nodece
nodece requested a review from codelipenghui June 14, 2022 10:16
@nodece

nodece commented Jun 14, 2022

Copy link
Copy Markdown
Member Author

@codelipenghui The authenticate logic has been update.

@michaeljmarshall michaeljmarshall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Great catch @nodece! I'm glad we didn't cherry pick #14044 when it was merged since it would be live now.

For additional context, I had mistakenly approved this specific change, and here is a link to my justification: #14044 (comment). This change technically means that clients authenticate the token twice on the initial connection, but only once on token refreshes.

@codelipenghui
codelipenghui merged commit 7576c93 into apache:master Jun 15, 2022
michaeljmarshall pushed a commit to michaeljmarshall/pulsar that referenced this pull request Apr 19, 2023
### Motivation

When token expiration, the broker requests the client to refresh the token, then the broker performs `org.apache.pulsar.broker.service.ServerCnx#doAuthentication` when the broker receives the auth response, which uses `org.apache.pulsar.broker.authentication.AuthenticationState#authenticate` to authentication, but the `org.apache.pulsar.broker.authentication.AuthenticationProviderToken.TokenAuthenticationState#authenticate` doesn't do anything, this cause a loop to refresh the token.

Right now the token is only validated in the TokenAuthenticationState constructor, we need to add a check to the authenticate method.

(cherry picked from commit 7576c93)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/security doc-not-needed Your PR changes do not impact docs type/bug The PR fixed a bug or issue reported a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants