-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Fix the CAE bug in js core lib #22324
Conversation
API change check APIView has identified API level changes in this PR and created following API reviews. |
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 looks good overall! The only thing I wonder is if we should make the "force refresh" decision in the challenge callback rather than in the cycler. @jeremymeng what do you think?
// If the tenantId passed in token options is different to the one we have | ||
// Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to | ||
// refresh the token with the new tenantId or token. | ||
const mustRefresh = tenantId !== tokenOptions.tenantId || !!tokenOptions.claims || cycler.mustRefresh; |
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.
@jeremymeng, I'm wondering if we should have an option that can set mustRefresh
to true instead of adding more logic around specific contents of the token in the cycler. This way the individual callbacks can make the decision about forcing refresh or not. What do you 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.
It is usually clearer if you do Boolean(tokenOptions.claims)
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.
@MaryGao can you please add some tests to validate this behavior? I would like to see specifically a test that validates that the token doesn't get refreshed when there is no need to refresh but we still have claims
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.
@joheredi Currently I just assume that we must refresh the token if claim details provides. Do you mean we need to support your cases?
Update below existing test cases:
// Case1: Will refresh token once as the first time token is empty
await pipeline.sendRequest(testHttpsClient, pipelineRequest);
clock.tick(5000);
// Case2: Will refresh token twice
// - 1st refreshing because the token is epxired
// - 2nd refreshing because the response with old token has 401 error with claim details so we need refresh token again
await pipeline.sendRequest(testHttpsClient, pipelineRequest);
// Case3: Token is still valid and no need to refresh it
await pipeline.sendRequest(testHttpsClient, pipelineRequest);
/** | ||
* Claim details to perform the Continuous Access Evaluation authentication flow | ||
*/ | ||
claims?: string; |
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.
These are the claims we get from the challenge right? We are already passing it in authorizeRequestOnClaimChallenge
callback but forgot to update this interface when the callback was originally added
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 exactly! This parameter is already passed in code
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.
Makes sense. Thanks for adding it! Could you please add an entry to core-auth CHANGELOG?
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.
It would be nice to also remove the "as GetTokenOptions" cast https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/src/authorizeRequestOnClaimChallenge.ts#L87 as it is no longer needed.
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.
Updated
This pull request is protected by Check Enforcer. What is Check Enforcer?Check Enforcer helps ensure all pull requests are covered by at least one check-run (typically an Azure Pipeline). When all check-runs associated with this pull request pass then Check Enforcer itself will pass. Why am I getting this message?You are getting this message because Check Enforcer did not detect any check-runs being associated with this pull request within five minutes. This may indicate that your pull request is not covered by any pipelines and so Check Enforcer is correctly blocking the pull request being merged. What should I do now?If the check-enforcer check-run is not passing and all other check-runs associated with this PR are passing (excluding license-cla) then you could try telling Check Enforcer to evaluate your pull request again. You can do this by adding a comment to this pull request as follows: What if I am onboarding a new service?Often, new services do not have validation pipelines associated with them, in order to bootstrap pipelines for a new service, you can issue the following command as a pull request comment: |
/check-enforcer evaluate |
// Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to | ||
// refresh the token with the new tenantId or token. | ||
const mustRefresh = | ||
tenantId !== tokenOptions.tenantId || Boolean(tokenOptions.claims) || cycler.mustRefresh; |
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.
so whenever we see claims, we know we have to refresh? Can we add a test with claims and one without to make sure those booleans are covered?
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.
Add a test to cover that
I agree that it would be better if we have a way to invalidate the token cache. I logged an issue before for token cache api discussion. I added this to the issue. For this PR I think it is fine for now, considering that tenantId and claims are special in the flow. |
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.
Change looks good. Can you please add a test to make sure we are not always refreshing the token?
Added with the test `it("tests that once the challenge is processed we won't refresh the token again and again", async function () { |
Issue
From client side we are supposed to refresh our token in claim challenge, below are the code snippet:
azure-sdk-for-js/sdk/core/core-client/src/authorizeRequestOnClaimChallenge.ts
Lines 84 to 89 in 78042b9
However in token cycler we missed this condition to refresh the token if we have an invalid but not expired token, below are the logic to refresh:
azure-sdk-for-js/sdk/core/core-rest-pipeline/src/util/tokenCycler.ts
Lines 206 to 208 in 78042b9
How to fix
During claim challenge we need to bypass our cached token and refresh a new token in some way. Currently I add the
claims
inGetTokenOptions
and refine the conditionmustRefresh
if we have claim details:How to reproduce
fix #21820