-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Added token revocation functionality to Managed Identity's App Service and Service Fabric sources #7679
base: dev
Are you sure you want to change the base?
Conversation
lib/msal-node/test/client/ManagedIdentitySources/AppService.spec.ts
Outdated
Show resolved
Hide resolved
lib/msal-node/test/client/ManagedIdentitySources/AppService.spec.ts
Outdated
Show resolved
Hide resolved
lib/msal-node/test/client/ManagedIdentitySources/AppService.spec.ts
Outdated
Show resolved
Hide resolved
@@ -389,3 +389,8 @@ export const ONE_DAY_IN_MS = 86400000; | |||
|
|||
// Token renewal offset default in seconds | |||
export const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300; | |||
|
|||
export const EncodingTypes = { | |||
HEX: "hex", |
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'll be making another PR where I replace every instance of "hex" with this new constant, and make "base64" value as well.
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 would recommend to create a github issue and link it here for reference
@@ -2215,6 +2215,17 @@ const emptyInputScopesError = "empty_input_scopes_error"; | |||
// @public (undocumented) | |||
const emptyInputScopeSet = "empty_input_scopeset"; | |||
|
|||
// Warning: (ae-missing-release-tag) "EncodingTypes" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) | |||
// Warning: (ae-missing-release-tag) "EncodingTypes" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) |
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.
nit: Duplicate line.
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.
Everything in this file is auto-generated; we don't touch this file. But I'll re-run the apiExtractor and see if it removes the duplicate line.
* @param refreshAccessToken - Optional flag indicating whether to force a refresh of the access token. | ||
* @returns A promise that resolves to an AuthenticationResult containing the acquired token and related information. | ||
*/ | ||
private async acquireTokenFromManagedIdentity( |
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.
Why is this method 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.
I extracted the functionality for the network request since it's being used multiple times.
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 allowed me to write better docs for it
@@ -176,6 +178,70 @@ describe("Acquires a token successfully via an App Service Managed Identity", () | |||
}); | |||
}); | |||
|
|||
describe("Miscellaneous", () => { | |||
test("ignores a cached token when claims are provided and the Managed Identity does support token revocation, and ensures the token revocation query parameter token_sha256_to_refresh was included in the network request to the Managed Identity", async () => { |
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 test when just the capabilities are set and claims are not passed?
} from "../../utils/Constants.js"; | ||
import { CryptoProvider } from "../../crypto/CryptoProvider.js"; | ||
import { ManagedIdentityRequestParameters } from "../../config/ManagedIdentityRequestParameters.js"; | ||
import { ManagedIdentityId } from "../../config/ManagedIdentityId.js"; | ||
import { NodeStorage } from "../../cache/NodeStorage.js"; | ||
|
||
// MSI Constants. Docs for MSI are available here https://docs.microsoft.com/azure/app-service/overview-managed-identity | ||
const APP_SERVICE_MSI_API_VERSION: string = "2019-08-01"; | ||
const APP_SERVICE_MSI_API_VERSION: string = "2025-03-30"; |
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.
please do not merge this
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.
Overall, the PR looks solid. It adds a clear, consistent approach for token revocation. If you remove 'app service' the PR can be merged. Else,. please mark it as 'Do Not Merge'
|
||
const SOURCES_THAT_SUPPORT_TOKEN_REVOCATION: Array<ManagedIdentitySourceNames> = | ||
[ | ||
ManagedIdentitySourceNames.APP_SERVICE, |
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.
If you remove app service, you can merge the PR. we can add app service later
* Check if there is a cached token and if the Managed Identity source supports token revocation. | ||
* If so, hash the cached access token and add it to the request. | ||
*/ | ||
if ( |
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.
GOOD - if claims are set and you have a cached token, you skip the cache for that request, if the source supports revocation, you also send the old token’s SHA-256 to the server. This ensures the old token is invalidated on the RP
expect(networkManagedIdentityResult.accessToken).toEqual( | ||
DEFAULT_SYSTEM_ASSIGNED_MANAGED_IDENTITY_AUTHENTICATION_RESULT.accessToken | ||
); | ||
|
||
expect(sendGetRequestAsyncSpy.mock.calls.length).toEqual(1); | ||
const firstNetworkRequestUrlParams: URLSearchParams = |
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.
Good use of spies and verifying the final URLSearchParams
import { ManagedIdentityId } from "../config/ManagedIdentityId.js"; | ||
import { HashUtils } from "../crypto/HashUtils.js"; | ||
|
||
const SOURCES_THAT_SUPPORT_TOKEN_REVOCATION: Array<ManagedIdentitySourceNames> = |
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.
Great that you have a dedicated list of sources that handle revocation. If more services adopt it, it should be trivial to add them to SOURCES_THAT_SUPPORT_TOKEN_REVOCATION.
Token Revocation spec