[PROTOTYPE][Do Not Merge] External Evaluation (Invoke) policy for azure-core-management#49701
Draft
weidongxu-microsoft wants to merge 10 commits into
Draft
Conversation
… draft) Adds ExternalEvaluationPolicy plus the PolicyTokenCredential / PolicyToken / PolicyTokenRequestContext trio to support the Azure Policy external evaluation flow: on a 403 RequestDisallowedByPolicy with missingPolicyTokenDetails, acquire a policy token and retry the operation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copied the TypeSpec-generated Storage management client into azure-core-management test sources to serve as the guarded ARM client for the External Evaluation policy E2E test. Suppressed a deprecation warning on HttpResponse.getHeaderValue(String) to satisfy -Werror. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… propagation The External Evaluation policy set the acquired token header on an early-captured request reference. Because the retry policy below it replaces the context's request with a fresh copy on each attempt, the header was lost on the replay. Set the header on context.getHttpRequest() so the retried request carries it. Add a WireMock-based E2E test that drives a copied Storage management client guarded by the policy and acquires the token via the real acquirePolicyToken API from azure-resourcemanager-resources. Opens the storage model packages to azure-core/azure-json for reflective (de)serialization under JPMS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…isition fails When ExternalEvaluationPolicy cannot acquire a policy token, the operation remains denied by policy. Re-surface the original 403 as a ManagementException (the exception the caller would otherwise see) with the acquisition failure chained as its cause, in both the async and sync paths. The credential wrapper in the E2E test now errors on a failed/missing token result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… body The mock ARM service now asserts every aspect of the guarded requests: - both PUTs match the exact URL path, PUT method, and a byte-for-byte identical request body (the External Evaluation flow requires the retried body to be identical to the original); - the denied PUT has no token header while the retried PUT carries the acquired token; - the acquirePolicyToken POST echoes the guarded operation verbatim (same httpMethod, same uri, and byte-for-byte the same content). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace matchingJsonPath/equalToJson on the acquirePolicyToken POST with a single byte-for-byte equalTo against the exact serialized request body. The PolicyTokenRequest serialization order is deterministic (operation -> uri, httpMethod, content), so the whole body can be asserted as an exact UTF-8 string, matching the byte-for-byte requirement on operation.content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…2E test Opt into the External Evaluation flow the way a user would: build the guarded StorageManager through configure().withPolicy(new ExternalEvaluationPolicy(...)) .authenticate(credential, profile) instead of hand-assembling the pipeline and calling authenticate(pipeline, profile). This also verifies the policy is placed correctly (PER_CALL, above retry) within the real manager pipeline. Because the manager pipeline adds a BearerTokenAuthenticationPolicy that requires HTTPS, the mock service is now served over TLS and the clients use a trust-all Netty HTTP client. Adds --add-reads for com.azure.http.netty to the module test args. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The acquired policy token is not an authentication credential (it is a token proving external policy evaluation context, not an AAD token), so 'Credential' was misleading. Rename the interface to PolicyTokenProvider and update the ExternalEvaluationPolicy field/parameter, tests, javadoc and CHANGELOG. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply the external evaluation flow to all resource operations except GET, and skip any request that already carries the x-ms-policy-external-evaluations header. Per the service contract such a request will not produce a 403 with missingPolicyTokenDetails, so this acts as a loop guard (relevant now that non-idempotent POST is in scope). Bodyless operations (e.g. DELETE) acquire a token with null operation.content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Warning
This is a PROTOTYPE / design-review draft — not intended to merge as-is.
Summary
Prototype of an External Evaluation ("Invoke") policy for
azure-core-management. It lets a management client transparently satisfy Azure Policy external evaluation: when a resource operation is denied with403 RequestDisallowedByPolicycarryingmissingPolicyTokenDetails, the policy acquires a policy token (via a user-injected provider) and replays the request with thex-ms-policy-external-evaluationsheader.The flow applies to all resource operations except
GET(i.e.PUT/PATCH/DELETE/POST). Operations without a request body (e.g.DELETE) acquire a token with anulloperation.content.How a user opts in
Import the policy-token API (e.g.
azure-resourcemanager-resourcesacquirePolicyToken), write a smallPolicyTokenProvider, and add the policy to the client pipeline via the manager builder:What is included
Main (new public API —
com.azure.core.management.evaluation):ExternalEvaluationPolicy— detects the 403, acquires the token, replays with the header (async + sync). On acquisition failure it re-surfaces the original 403ManagementExceptionwith the provider error chained as the cause.PolicyTokenProvider,PolicyToken,PolicyTokenRequestContext, and internalMissingPolicyTokenDetailsparsing.Tests:
ExternalEvaluationPolicyTests— unit coverage (acquire+retry async/sync, non-GET methods such as bodylessDELETE,GETpass-through, plain deny pass-through, non-403 pass-through, change-reference guard, acquisition-failure re-surface).ExternalEvaluationPolicyE2ETests— full flow against a real generated Storage client and the realacquirePolicyTokenAPI, with ARM faked by WireMock (HTTPS). Asserts exact request URL, method, and byte-for-byte request body.Prototype caveats (why this is a draft)
azure-resourcemanager-resources(a downstream library) purely to exercise the realacquirePolicyTokenAPI. Needs a decision on the proper home for this test / dependency direction.pom.xmladd-opens / add-reads and a trust-all Netty client are test-only scaffolding for the WireMock-over-HTTPS E2E.PolicyTokenProvidercontract, failure semantics) is up for review.Validation
ExternalEvaluationPolicyTests(10) +ExternalEvaluationPolicyE2ETests(1) pass; checkstyle clean.