test(api): Expand v3 coverage and enforce EC2 token restrictions - #1084
test(api): Expand v3 coverage and enforce EC2 token restrictions#1084ShJ-code wants to merge 9 commits into
Conversation
gtema
left a comment
There was a problem hiding this comment.
I stopped reviewing the PR since it makes a forbidden change to the auth logic. Please fix this before we can look at the rest of PR.
| } | ||
|
|
||
| #[test] | ||
| fn test_methods_application_credential_preserves_parent_token_methods() { |
There was a problem hiding this comment.
This test is very confusing. It simulates ec2cred token but then build AuthContext as if user would renew the auth with application credentials. It is forbidden and unreachable business logic - auth with application credentials always return a fresh token - nothing is preserved in it
| } | ||
|
|
||
| #[test] | ||
| fn test_methods_trust_preserves_parent_token_methods() { |
There was a problem hiding this comment.
same here - ec2cred auth does not allow to get a trust auth. Trust always require password auth, not a previously obtained token.
| /// `Ok(())` when the token was not minted from an EC2 credential, `Err(401 | ||
| /// Unauthorized)` otherwise. | ||
| fn reject_if_ec2(user_auth: &ValidatedSecurityContext) -> Result<(), KeystoneApiError> { | ||
| if matches!( |
There was a problem hiding this comment.
this MUST stay - ec2credential token is returned by Keystone, is accepted in the validate token, but is not accepted for anything else - this is a security fix
2fe020e to
1af031e
Compare
|
Thanks for the comments. I just applied the changes to the new commit. Please let me know if anything needs to change as I work on v4. |
| if: needs.changes.outputs.code == 'true' | ||
| run: cargo nextest run -p test_api --profile ci-api --test integration_api_v3 --test integration_api_v4 | ||
|
|
||
| - name: Invalidate eventual openstack_sdk cache |
There was a problem hiding this comment.
removing cache invalidation should be only possible once the openstack_sdk releases with the possibility to control caching programmatically
There was a problem hiding this comment.
this should not be done. Pretty soon I will release the openstack_sdk with programmatical cache control. Adding the clouds.yaml only to disable caching is not desired
There was a problem hiding this comment.
isn't the crud_endpoint! macro to prevent manually creating endpoints?
|
|
||
| const AUTH_URL: &str = "http://localhost:8080"; | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
can we please also get rid of this test?
|
There is currently one structural issue in the test: the |
1af031e to
adbdebc
Compare
gtema
left a comment
There was a problem hiding this comment.
okay, very good. Few last points:
-
tests/api/src/auth/ec2.rs: sign_v2_hmac_sha256 sorts pairs via Vec<(&String,&String)>::sort(), i.e. lexicographic by (key, value) tuple — for AWS SigV2 canonicalization the spec requires sorting by key (byte order) only. Since AWSAccessKeyId/SignatureMethod/SignatureVersion/Timestamp keys are all distinct in practice this doesn't currently bite, but it's a latent correctness gap in the "independent" reference signer if a future test ever needs duplicate keys or relies on value as tiebreaker — worth a one-line comment or switching to sort_by_key(|(k, _)| *k) for precision.
-
test_ec2_token_forbidden_member_caller asserts StatusCode::FORBIDDEN, while test_ec2_credential_create_forbidden_cross_user (and others) use the shared assert_forbidden helper. Fine functionally, just a minor consistency nit — could route through the same helper for uniformity.
-
Fixture provisioning isn't guarded against partial failure in ProjectScopedUser::provision: if add_project_grant or get_user_session fails after the project/user were created, both resources leak (no cleanup-on-error, unlike SystemScopedUser::provision, which does clean up the user on session_result failure). Given these are live-server tests hitting a long-lived dev server, an intermittent failure here silently accumulates orphan projects/users. Might be worth aligning ProjectScopedUser::provision with the same clean-up-on-error pattern used in SystemScopedUser::provision.
c4e4004 to
5afdfb7
Compare
Add the shared building blocks the remaining openstack-experimental#993 v3 suites rely on: - `test_api::fixtures::ProjectScopedUser`, a real password user holding a bootstrap role on a fresh project, authenticated with a genuinely project-scoped token through the live auth path. It is provisioned and torn down with the caller's admin session, so cleanup never depends on the underprivileged session, and it unwinds its own partial work if a later provisioning step fails. - `warn_on_cleanup_failure`, which logs a failed best-effort cleanup instead of shadowing the error that triggered it. - `test_api::common::raw_request`, for the invalid-auth leg of the matrix: the SDK refuses to send a syntactically invalid token, so those cases have to bypass it. Teach `asserts::status_from_error` to unwrap a `reqwest::Error` so the `raw_request` responses can go through `assert_unauthorized` and report the full error chain like every other negative assertion. Migrate the openstack-experimental#992 group suite onto these helpers: its local `ProjectScopedManager` and `status_with_invalid_token` were the prototypes the shared versions generalize, and keeping both would let them drift apart. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Extend crud_endpoint! with an optional parent collection and unwrapped create bodies so the legacy OS-EC2 sub-resource is generated rather than hand-written. Add unguarded create and delete flavors for resources whose teardown session differs from the creating one. Add an independent AWS SigV2 HMAC-SHA256 signer with a published golden-vector unit test. Canonicalization sorts strictly by raw parameter name: the value must never act as a tiebreaker, and encoding before sorting would reorder names whose first differing byte is percent-escaped. A unit test pins that ordering. Enable ec2credential in the live-test and Skaffold Rust configurations. Keep the upstream startup timeout and failure diagnostics. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Cover all four OS-EC2 credential handlers with owner success, cross-user policy denial, and invalid-token rejection. Exercise EC2 token issuance, caller policy, signature and timestamp validation, subject-token validation, and token-from-token reauthentication through live API tests. Route the invalid-token cases through assert_unauthorized so a wrong status reports the full error chain instead of a bare status compare, and reduce asserted values to their access key: Ec2Credential's derived Debug carries the plaintext secret, which the assertion helpers would print on an unexpected success. Release the already-provisioned fixtures when a later setup step fails, so a mid-setup error leaves no orphaned users, projects or credentials behind on the live server. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Cover an admin reading empty and populated memberships, a project-scoped member receiving 403 for another user, and an invalid token receiving 401. Create the populated membership through the only live write path, SCIM, then verify it through v3 in the SCIM binary to preserve the v3 binary's Python Keystone compatibility. Explicitly remove and purge every resource. Route the invalid-token case through assert_unauthorized, release the first fixture when the second fails to provision, and name the tests in the coverage table exactly as they are declared so the table stays greppable. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Keep the admin positive case and add the policy's system-scoped reader positive branch, project-scoped member denial, and invalid-token rejection. Add a reusable system-scoped user fixture and system role-grant endpoint, with admin-owned cleanup for both success and provisioning failures, and route the invalid-token case through assert_unauthorized. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Return 401 when an EC2-issued token is presented as X-Auth-Token, while preserving subject-token validation and token-to-token reauth. Use the shared openstack-experimental#992 status assertions and complete fixture cleanup before panicable assertions in the negative cases. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Re-enforce identity/group/show against every returned group and omit items denied by policy, as required by security-model invariant I8. Add reusable caller-configured policy state and focused tests that verify both per-record policy inputs and denied-item filtering. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Attempt every project-scoped fixture deletion before returning an error, and reuse the helper across multi-user authorization tests. Complete cleanup before panicable assertions and retain the reason the live Rust server enables the ec2credential authentication method. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
Compile FederationProtocol validation tests only when the validate feature provides the Validate implementation. This restores the default crate test configuration after rebasing onto upstream/main. Signed-off-by: ShJ-code <sihao_jiang@outlook.com>
5afdfb7 to
644534b
Compare
|
I modified the commits so that there's better and more extensive use of helpers developed from #992 , specifically for EC2 credential endpoints and role-inference tests, as well as for cleanup. |
Summary
Part of #993 (Phase 2). This PR delivers the v3 portion; v4 coverage will
follow separately.
handlers: owner success, cross-user policy denial, and invalid-token
rejection.
POST /v3/ec2tokens, covering issuance, callerauthorization, invalid signatures, stale timestamps, token validation,
token reauthentication, and the fix(security): Do not allow ec2cred token to do anything #1071 bearer-token restriction.
ec2credentialmarker from the immutable Fernet token payloadand return 401 when an EC2-issued token is used on an ordinary API endpoint.
redemption while encoding the exact EC2 authentication method.
method is unsupported.
GET /v3/users/{id}/groupswith empty and SCIM-populated successcases, cross-user 403, and invalid-token 401.
GET /v3/role_inferencesfor admin and system-reader success,project-scoped-member 403, and invalid-token 401.
ec2credentialconsistently across the repository-owned Rust Keystonetest environments.
Test plan
cargo check --message-format=short -p openstack-keystone-core-types -p openstack-keystone-core -p openstack-keystone-token-driver-fernet -p openstack-keystone -p test_apicargo test -p openstack-keystone-core-typescargo test -p openstack-keystone-corecargo test -p openstack-keystone-token-driver-fernetcargo test -p openstack-keystone -- --test-threads=1cargo test -p test_apicargo nextest run --profile api -p test_api --test integration_api_v3 --test integration_api_v4 --test scim_v2cargo clippy --message-format=short -p openstack-keystone-core-types -p openstack-keystone-core -p openstack-keystone-token-driver-fernet -p openstack-keystone -p test_api --lib --testspre-commit run --all-filesSecurity review checklist
Required because this diff touches authentication, delegation, tokens,
credentials, and EC2.
authentication_context()and the Trust/Application Credential objects;no decision was changed to infer delegation from
ScopeInfoorproject_id. (I1/I2)projection of delegation facts onto
Credentials. (I2/I3)Credential context, so effective-role calculation remains bounded by the
delegation; the existing delegated-role matrices and new EC2 carrier
round-trip tests pass. (I4)
ScopeInfovariant or authentication methodis introduced;
ec2credentialalready existed and is now registered inthe relevant test configurations. (I5, Gate J)
this PR; the existing EC2 credential lookup behavior is unchanged. (I6)
policy input. EC2 secrets are used only for signature verification. (I7,
Gate I)
this PR tests existing endpoints. (I8)
immutable
ec2credentialmarker is preserved across delegation and tokenreauthentication, and ordinary bearer use is rejected with 401. (I5)
callers, the
/v3/ec2tokensmember-caller gate, invalid signatures, staletimestamps, and EC2-token use on ordinary endpoints.
end to end, including
ValidatedSecurityContext::new_for_scope(), ratherthan testing only inner scope or effective-role helpers.