)]}'
{"id":"openstack%2Fkeystone~1002307","triplet_id":"openstack%2Fkeystone~stable%2F2025.1~Ic8775eb0fdaa2330206023818ce18f76430fa45e","project":"openstack/keystone","branch":"stable/2025.1","attention_set":{},"removed_from_attention_set":{"14250":{"account":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"last_update":"2026-08-31 12:59:18.000000000","reason":"Change was submitted"}},"hashtags":["CVE-2026-80182","OSSA-2026-037"],"change_id":"Ic8775eb0fdaa2330206023818ce18f76430fa45e","subject":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints","status":"MERGED","created":"2026-08-25 14:49:47.000000000","updated":"2026-08-31 13:01:16.000000000","submitted":"2026-08-31 12:59:18.000000000","submitter":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"total_comment_count":17,"unresolved_comment_count":0,"has_review_started":true,"submission_id":"1002307","meta_rev_id":"95dca34b1f18c04d512b75534e28b6ff50bdde4b","_number":1002307,"virtual_id_number":1002307,"owner":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"actions":{},"labels":{"Verified":{"approved":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"all":[{"value":0,"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},{"tag":"autogenerated:zuul:gate","value":2,"date":"2026-08-31 12:59:18.000000000","permitted_voting_range":{"min":2,"max":2},"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]}],"values":{"-2":"Fails","-1":"Doesn\u0027t seem to work"," 0":"No score","+1":"Works for me","+2":"Verified"},"description":"","default_value":0,"optional":true},"Code-Review":{"approved":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"all":[{"value":2,"date":"2026-08-31 11:09:34.000000000","permitted_voting_range":{"min":2,"max":2},"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},{"value":0,"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]}],"values":{"-2":"Do not merge","-1":"This patch needs further work before it can be merged"," 0":"No score","+1":"Looks good to me, but someone else must approve","+2":"Looks good to me (core reviewer)"},"description":"","default_value":0,"optional":true},"Workflow":{"approved":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"all":[{"value":1,"date":"2026-08-31 11:09:34.000000000","permitted_voting_range":{"min":1,"max":1},"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},{"value":0,"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]}],"values":{"-1":"Work in progress"," 0":"Ready for reviews","+1":"Approved"},"description":"","default_value":0,"optional":true}},"removable_reviewers":[],"reviewers":{"REVIEWER":[{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"}]},"pending_reviewers":{},"reviewer_updates":[{"updated":"2026-08-25 18:42:34.000000000","updated_by":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"reviewer":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"state":"REVIEWER"},{"updated":"2026-08-31 11:09:34.000000000","updated_by":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"reviewer":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"state":"REVIEWER"}],"messages":[{"id":"c293c829b405f1a64bf2bc5a096f5461ad476cef","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"date":"2026-08-25 14:49:47.000000000","message":"Uploaded patch set 1.","accounts_in_message":[],"_revision_number":1},{"id":"d7fd5061da0b55379e5bf7c3b7df3aab8cab34d1","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"date":"2026-08-25 16:14:21.000000000","message":"Uploaded patch set 2: Patch Set 1 was rebased.","accounts_in_message":[],"_revision_number":2},{"id":"a798b97dddc3b11a5fcc114d2a81b6154e88b2e9","tag":"autogenerated:zuul:check","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-25 18:42:34.000000000","message":"Patch Set 2: Verified-1\n\n(17 comments)\n\nBuild failed (check pipeline).  For information on how to proceed, see\nhttps://docs.opendev.org/opendev/infra-manual/latest/developers.html#automated-testing\nand https://docs.openstack.org/project-team-guide/testing.html#how-to-handle-test-failures\n\nhttps://zuul.opendev.org/t/openstack/buildset/b308bdfb2754497bb1152b0666323e2d\n\n- openstack-tox-cover https://zuul.opendev.org/t/openstack/build/a8418b2bacaf4738b1b4bfda96b90953 : SUCCESS in 19m 57s\n- openstack-tox-pep8 https://zuul.opendev.org/t/openstack/build/b7246f92578b4e74a9f46c25c63afec4 : FAILURE in 7m 17s\n- openstack-tox-py39 https://zuul.opendev.org/t/openstack/build/ac5484916eb44fff8c0eb6bb8538e662 : SUCCESS in 15m 25s\n- openstack-tox-py312 https://zuul.opendev.org/t/openstack/build/5dc91867ee4d4a52b06c23d57d272e91 : SUCCESS in 15m 07s\n- openstack-tox-docs https://zuul.opendev.org/t/openstack/build/30749946d3d7420498df516cdf914974 : SUCCESS in 9m 33s\n- build-openstack-releasenotes https://zuul.opendev.org/t/openstack/build/d99816661e714d54abf4dd7df61485ff : SUCCESS in 14m 22s\n- keystone-dsvm-py3-functional https://zuul.opendev.org/t/openstack/build/6ecb27c40c2f4e36bfa89b8eb2f2af20 : FAILURE in 8m 46s\n- keystone-dsvm-py3-functional-fips https://zuul.opendev.org/t/openstack/build/05671006373b43d69a574f257e0b36cf : FAILURE in 33m 18s (non-voting)\n- keystone-dsvm-py3-functional-federation-ubuntu-jammy https://zuul.opendev.org/t/openstack/build/7a3e64ebedeb499a97c7861622f497ae : FAILURE in 27m 19s (non-voting)\n- keystone-dsvm-py3-functional-federation-ubuntu-jammy-k2k https://zuul.opendev.org/t/openstack/build/813bd8b17b3b48d4b6dbc5130ecc7932 : SUCCESS in 29m 25s (non-voting)\n- keystoneclient-devstack-functional https://zuul.opendev.org/t/openstack/build/3f06cf7ac6b74d9ebdbf3e3159c27543 : SUCCESS in 19m 59s (non-voting)\n- keystone-dsvm-ldap-domain-specific-driver https://zuul.opendev.org/t/openstack/build/cc2b6f5e59f74b82b3faffd38d961c7a : SUCCESS in 27m 01s (non-voting)\n- tempest-full-py3 https://zuul.opendev.org/t/openstack/build/48642b3fd1ab448f81b43bbf6a6c7bd1 : SUCCESS in 1h 43m 42s\n- grenade https://zuul.opendev.org/t/openstack/build/02e596fbef5f43ce8d721ae04a236ba6 : FAILURE in 53m 56s (non-voting)\n- tempest-ipv6-only https://zuul.opendev.org/t/openstack/build/4e7fc7fdb34d476ea981214ad9e7490b : SUCCESS in 1h 06m 51s\n- keystone-dsvm-functional-oidc-federation https://zuul.opendev.org/t/openstack/build/2ecfa404207043749b7dc3cd05781187 : SUCCESS in 32m 17s (non-voting)\n\nWarning:\n  File .ssh/known_hosts.old found in build home directory during playbook opendev.org/opendev/base-jobs/playbooks/base/cleanup.yaml for job keystone-dsvm-py3-functional-fips.  Add to preserve-home-paths if safe, or otherwise remove.\n  File .ssh/known_hosts.old found in build home directory during playbook opendev.org/opendev/base-jobs/playbooks/base/post-logs.yaml for job keystone-dsvm-py3-functional-fips.  Add to preserve-home-paths if safe, or otherwise remove.","accounts_in_message":[],"_revision_number":2},{"id":"30dd9e2a633a89d4cdd6bb51a48f483959b81b58","tag":"autogenerated:gerrit:setHashtag","author":{"_account_id":16643,"name":"Goutham Pacha Ravi","email":"gouthampravi@gmail.com","username":"gouthamr"},"date":"2026-08-25 22:13:01.000000000","message":"Hashtags added: CVE-2026-80182, OSSA-2026-037","accounts_in_message":[],"_revision_number":2},{"id":"b4ddebe3afadff75d626c1462556b34828b54145","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"date":"2026-08-25 22:48:40.000000000","message":"Uploaded patch set 3.\n\nOutdated Votes:\n* Verified-1 (copy condition: \"NEVER\")\n","accounts_in_message":[],"_revision_number":3},{"id":"56b2448bed1d1f16590cea2c2c7201cc7e44642b","tag":"autogenerated:zuul:check","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-26 00:18:08.000000000","message":"Patch Set 3: Verified+1\n\nBuild succeeded (check pipeline).\nhttps://zuul.opendev.org/t/openstack/buildset/1fef141b5dda43a595b12ca705d0b4d9\n\n- openstack-tox-cover https://zuul.opendev.org/t/openstack/build/101480b41b21467a88e874ed7303fda9 : SUCCESS in 15m 40s\n- openstack-tox-pep8 https://zuul.opendev.org/t/openstack/build/9746f280ca914f52a1cb5ab467fd82eb : SUCCESS in 6m 59s\n- openstack-tox-py39 https://zuul.opendev.org/t/openstack/build/9482d14ef519453faf924184fde9851a : SUCCESS in 11m 10s\n- openstack-tox-py312 https://zuul.opendev.org/t/openstack/build/2bfb484363d044088227bc4f8db31b2a : SUCCESS in 8m 36s\n- openstack-tox-docs https://zuul.opendev.org/t/openstack/build/f8f599957c4047539661364aa5338a17 : SUCCESS in 14m 30s\n- build-openstack-releasenotes https://zuul.opendev.org/t/openstack/build/2ddeb48782c34483941cea29d447932d : SUCCESS in 9m 06s\n- keystone-dsvm-py3-functional https://zuul.opendev.org/t/openstack/build/c006c77fcb814aeb8bccb732f1657121 : SUCCESS in 31m 22s\n- keystone-dsvm-py3-functional-fips https://zuul.opendev.org/t/openstack/build/b113dab134b5464daaf54ba1aac372e0 : FAILURE in 28m 41s (non-voting)\n- keystone-dsvm-py3-functional-federation-ubuntu-jammy https://zuul.opendev.org/t/openstack/build/01dca2da286f4faeadd65a97211a2cdb : FAILURE in 21m 23s (non-voting)\n- keystone-dsvm-py3-functional-federation-ubuntu-jammy-k2k https://zuul.opendev.org/t/openstack/build/07fb4c2bef5644acb1f510c9ee32d19a : SUCCESS in 30m 11s (non-voting)\n- keystoneclient-devstack-functional https://zuul.opendev.org/t/openstack/build/e07bdcb6f6a84e0da8a57409ccb722b3 : SUCCESS in 16m 44s (non-voting)\n- keystone-dsvm-ldap-domain-specific-driver https://zuul.opendev.org/t/openstack/build/cc2beb6957564c5381fe716df341faff : SUCCESS in 28m 51s (non-voting)\n- tempest-full-py3 https://zuul.opendev.org/t/openstack/build/3afd39eddc984b7d889365a56ada22dd : SUCCESS in 1h 26m 39s\n- grenade https://zuul.opendev.org/t/openstack/build/2b2defa11c514bada6de98d23fd045b0 : FAILURE in 27m 09s (non-voting)\n- tempest-ipv6-only https://zuul.opendev.org/t/openstack/build/ecd5a681017a4757b69848fc401c4e89 : SUCCESS in 50m 27s\n- keystone-dsvm-functional-oidc-federation https://zuul.opendev.org/t/openstack/build/54009d20f6fd45a58b9910cc4aee4920 : SUCCESS in 34m 00s (non-voting)\n\nWarning:\n  File .ssh/known_hosts.old found in build home directory during playbook opendev.org/opendev/base-jobs/playbooks/base/cleanup.yaml for job keystone-dsvm-py3-functional-fips.  Add to preserve-home-paths if safe, or otherwise remove.\n  File .ssh/known_hosts.old found in build home directory during playbook opendev.org/opendev/base-jobs/playbooks/base/post-logs.yaml for job keystone-dsvm-py3-functional-fips.  Add to preserve-home-paths if safe, or otherwise remove.","accounts_in_message":[],"_revision_number":3},{"id":"f691fd5d09187dbe74f2707d89894f96f79a20b4","author":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"},"date":"2026-08-31 11:09:34.000000000","message":"Patch Set 3: Code-Review+2 Workflow+1","accounts_in_message":[],"_revision_number":3},{"id":"74ec4728773f5fd2382570117f3e19e77650bfe2","tag":"autogenerated:zuul:gate","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-31 11:09:57.000000000","message":"Patch Set 3: -Verified\n\nStarting gate jobs.","accounts_in_message":[],"_revision_number":3},{"id":"80c192303437b7fbf371f415bf060c192524bcb9","tag":"autogenerated:zuul:gate","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-31 12:59:18.000000000","message":"Patch Set 3: Verified+2\n\nBuild succeeded (gate pipeline).\nhttps://zuul.opendev.org/t/openstack/buildset/4cbf5da20caa4cd98a6e923c56d1addd\n\n- openstack-tox-pep8 https://zuul.opendev.org/t/openstack/build/ac97afa6c84d4ea9be27b8bfeec749db : SUCCESS in 8m 14s\n- openstack-tox-py39 https://zuul.opendev.org/t/openstack/build/155b6062114b456093d0ec52281eb0c5 : SUCCESS in 14m 17s\n- openstack-tox-py312 https://zuul.opendev.org/t/openstack/build/de1b2481a6914b3ab9c0a4f09ce82ed6 : SUCCESS in 13m 02s\n- openstack-tox-docs https://zuul.opendev.org/t/openstack/build/9c67313c0ab7485eb6d762c67805d40b : SUCCESS in 11m 45s\n- build-openstack-releasenotes https://zuul.opendev.org/t/openstack/build/528fcf1f4aeb421da5a46f9cd3edb044 : SUCCESS in 14m 48s\n- keystone-dsvm-py3-functional https://zuul.opendev.org/t/openstack/build/36e207ae84c141e8b56904a5517c8d3e : SUCCESS in 33m 31s\n- tempest-full-py3 https://zuul.opendev.org/t/openstack/build/f89d3918e2a84561a90c79657195f405 : SUCCESS in 1h 45m 01s\n- grenade https://zuul.opendev.org/t/openstack/build/1e36c6cc01c84276982d5478f8c0a4ca : FAILURE in 25m 04s (non-voting)\n- tempest-ipv6-only https://zuul.opendev.org/t/openstack/build/172d35e632564d1b8e565d62c2591936 : SUCCESS in 1h 00m 40s","accounts_in_message":[],"_revision_number":3},{"id":"f41f80576c2a2db50c9a2500115e679c94c84189","tag":"autogenerated:gerrit:merged","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-31 12:59:18.000000000","message":"Change has been successfully merged","accounts_in_message":[],"_revision_number":3},{"id":"95dca34b1f18c04d512b75534e28b6ff50bdde4b","tag":"autogenerated:zuul:promote","author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"date":"2026-08-31 13:01:16.000000000","message":"Patch Set 3:\n\nBuild succeeded (promote pipeline).\nhttps://zuul.opendev.org/t/openstack/buildset/e0ca80be0422493783d93ddf823cf0b0\n\n- promote-openstack-tox-docs https://zuul.opendev.org/t/openstack/build/355ab658a23b43f9a07be702e878102d : SUCCESS in 1m 39s\n- promote-openstack-releasenotes https://zuul.opendev.org/t/openstack/build/c68ec092785a4bd2959fd61ba88b0f74 : SUCCESS in 1m 11s","accounts_in_message":[],"_revision_number":3}],"current_revision_number":3,"current_revision":"c8872fabde992542b304895f90d5ac1651e87e24","revisions":{"212985ad01ec102d4d9ee96fea198b1f18e11d30":{"kind":"REWORK","_number":1,"created":"2026-08-25 14:49:47.000000000","uploader":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"ref":"refs/changes/07/1002307/1","fetch":{"anonymous http":{"url":"https://review.opendev.org/openstack/keystone","ref":"refs/changes/07/1002307/1","commands":{"Checkout":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/1 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/1 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.opendev.org/openstack/keystone refs/changes/07/1002307/1"}}},"commit":{"parents":[{"commit":"b896b71557ce8370c442fe05818a74d7a9a623a8","subject":"Merge \"Fix project policy allowing unauthorized access to root domains\" into stable/2025.1","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/b896b71557ce8370c442fe05818a74d7a9a623a8"}]}],"author":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-07-23 07:32:00.000000000","tz":120},"committer":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-08-25 14:48:07.000000000","tz":120},"subject":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints","message":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints\n\n_check_application_credential() in trusts.py only recognized\n\u0027application_credential\u0027 in token.methods, so OAuth1 access-token-scoped\nand ec2credential-derived tokens were never blocked from creating,\nlisting, reading, or deleting trusts -- unlike application_credential,\nwhich has had this restriction since LP#2148477.\n\nTwo more endpoints that mint a new persistent grant had the same gap:\n\n- users.py\u0027s _block_delegated_token_app_creds (guarding application\n  credential and access-rule CRUD) only checked trust_id/access_token_id,\n  so ec2credential-scoped tokens could create, list, read, and delete\n  application credentials.\n- os_oauth1.py\u0027s AuthorizeResource.put (PUT /v3/OS-OAUTH1/authorize) only\n  checked is_delegated_auth (trust/oauth1) and application_credential, so\n  an ec2credential-scoped token could authorize OAuth1 request tokens.\n\nAll three are extended to the same primary-auth-method allowlist used in\ncredentials.py, users.py, and token.py: any token whose methods aren\u0027t\nentirely primary auth methods is rejected outright. Trust-scoped tokens\nare deliberately not blocked from trust operations on trust_id alone --\nthat\u0027s the trust redelegation feature working as designed (a trustee\ncreating a further, narrower trust from one they were delegated) and\ntrustee self-service reads of their own trusts. A trust-scoped token\nwhose underlying method is itself delegated (an EC2 credential\u0027s blob\ncan embed a trust_id, see keystone.api.credentials._assign_unique_id) is\nstill caught by the method check regardless of trust scoping.\napplication_credential keeps its existing, documented opt-in escape\nhatch for trust management\n(allow_insecure_application_credential_trust_escalation) and its\nunrestricted/restricted distinction for creating further application\ncredentials (_check_unrestricted_application_credential); OAuth1 and EC2\ncredentials have no such use case and are blocked unconditionally\neverywhere.\n\nThis also closes off the underlying role-escalation path in trust\ncreation: trust role validation checks the trustor\u0027s full role\nassignments, not the requesting token\u0027s own scoped roles, so a\nnarrowly-scoped oauth1/ec2 token could previously delegate roles it was\nnever itself authorized for. Blocking those token types from trust\ncreation removes the path to that gap without needing to touch the\nvalidation itself.\n\nNeither the app-cred nor the OAuth1-authorize gap is reachable on\ncurrent master, where a separate middleware change globally rejects any\ncaller token with \u0027ec2credential\u0027 in its methods before Flask routing --\nbut that change is not backported to stable branches, so both gaps are\nlive there. Fixed at the source regardless, so the guard doesn\u0027t depend\non an unrelated middleware check remaining in place.\n\nAn empty token.methods list (e.g. an ec2credential-derived token that\nlost its methods on a fernet cache-miss round-trip -- ec2credential has\nno bit in the method bitmask) is also treated as delegated at all three\ncall sites: _PRIMARY_AUTH_METHODS.issuperset([]) is True, so without this\nan empty list would otherwise be accepted as \u0027all primary\u0027.\n\nConsolidated the three independent _PRIMARY_AUTH_METHODS copies (this\npatch, LP#2158538, LP#2159643) into keystone.api._shared.delegation,\nper gtema\u0027s review comment #16 -- now that all three land together the\nNameError-avoidance reason for keeping them separate no longer applies.\nAlso replaced the hardcoded method list with an operator-extensible one\n([auth] additional_primary_auth_methods): a hardcoded allowlist blocks\nany third-party auth plugin (e.g. a site-specific SSO integration) from\nreauthenticating/managing its own trusts, app-creds, and OAuth1 tokens,\nsince it can never appear in a list only keystone maintainers can edit.\n\nCloses-Bug: #2153453\nChange-Id: Ic8775eb0fdaa2330206023818ce18f76430fa45e\nAssisted-by: Claude Sonnet 5 \u003cnoreply@anthropic.com\u003e\nSigned-off-by: Grzegorz Grasza \u003cxek@redhat.com\u003e\nSigned-off-by: Artem Goncharov \u003cartem.goncharov@gmail.com\u003e\n","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/212985ad01ec102d4d9ee96fea198b1f18e11d30"}],"resolve_conflicts_web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/212985ad01ec102d4d9ee96fea198b1f18e11d30"}]},"branch":"refs/heads/stable/2025.1"},"d719264b44bbd87fe4e880619d9af9b9b7be8350":{"kind":"TRIVIAL_REBASE","_number":2,"created":"2026-08-25 16:14:21.000000000","uploader":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"ref":"refs/changes/07/1002307/2","fetch":{"anonymous http":{"url":"https://review.opendev.org/openstack/keystone","ref":"refs/changes/07/1002307/2","commands":{"Checkout":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/2 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/2 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/2 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.opendev.org/openstack/keystone refs/changes/07/1002307/2"}}},"commit":{"parents":[{"commit":"8b5cf08d5516380325e371cb0cdfb9b38e75a9b0","subject":"Merge \"Block app credential token rescoping\" into stable/2025.1","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/8b5cf08d5516380325e371cb0cdfb9b38e75a9b0"}]}],"author":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-07-23 07:32:00.000000000","tz":120},"committer":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-08-25 16:08:10.000000000","tz":120},"subject":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints","message":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints\n\n_check_application_credential() in trusts.py only recognized\n\u0027application_credential\u0027 in token.methods, so OAuth1 access-token-scoped\nand ec2credential-derived tokens were never blocked from creating,\nlisting, reading, or deleting trusts -- unlike application_credential,\nwhich has had this restriction since LP#2148477.\n\nTwo more endpoints that mint a new persistent grant had the same gap:\n\n- users.py\u0027s _block_delegated_token_app_creds (guarding application\n  credential and access-rule CRUD) only checked trust_id/access_token_id,\n  so ec2credential-scoped tokens could create, list, read, and delete\n  application credentials.\n- os_oauth1.py\u0027s AuthorizeResource.put (PUT /v3/OS-OAUTH1/authorize) only\n  checked is_delegated_auth (trust/oauth1) and application_credential, so\n  an ec2credential-scoped token could authorize OAuth1 request tokens.\n\nAll three are extended to the same primary-auth-method allowlist used in\ncredentials.py, users.py, and token.py: any token whose methods aren\u0027t\nentirely primary auth methods is rejected outright. Trust-scoped tokens\nare deliberately not blocked from trust operations on trust_id alone --\nthat\u0027s the trust redelegation feature working as designed (a trustee\ncreating a further, narrower trust from one they were delegated) and\ntrustee self-service reads of their own trusts. A trust-scoped token\nwhose underlying method is itself delegated (an EC2 credential\u0027s blob\ncan embed a trust_id, see keystone.api.credentials._assign_unique_id) is\nstill caught by the method check regardless of trust scoping.\napplication_credential keeps its existing, documented opt-in escape\nhatch for trust management\n(allow_insecure_application_credential_trust_escalation) and its\nunrestricted/restricted distinction for creating further application\ncredentials (_check_unrestricted_application_credential); OAuth1 and EC2\ncredentials have no such use case and are blocked unconditionally\neverywhere.\n\nThis also closes off the underlying role-escalation path in trust\ncreation: trust role validation checks the trustor\u0027s full role\nassignments, not the requesting token\u0027s own scoped roles, so a\nnarrowly-scoped oauth1/ec2 token could previously delegate roles it was\nnever itself authorized for. Blocking those token types from trust\ncreation removes the path to that gap without needing to touch the\nvalidation itself.\n\nNeither the app-cred nor the OAuth1-authorize gap is reachable on\ncurrent master, where a separate middleware change globally rejects any\ncaller token with \u0027ec2credential\u0027 in its methods before Flask routing --\nbut that change is not backported to stable branches, so both gaps are\nlive there. Fixed at the source regardless, so the guard doesn\u0027t depend\non an unrelated middleware check remaining in place.\n\nAn empty token.methods list (e.g. an ec2credential-derived token that\nlost its methods on a fernet cache-miss round-trip -- ec2credential has\nno bit in the method bitmask) is also treated as delegated at all three\ncall sites: _PRIMARY_AUTH_METHODS.issuperset([]) is True, so without this\nan empty list would otherwise be accepted as \u0027all primary\u0027.\n\nConsolidated the three independent _PRIMARY_AUTH_METHODS copies (this\npatch, LP#2158538, LP#2159643) into keystone.api._shared.delegation,\nper gtema\u0027s review comment #16 -- now that all three land together the\nNameError-avoidance reason for keeping them separate no longer applies.\nAlso replaced the hardcoded method list with an operator-extensible one\n([auth] additional_primary_auth_methods): a hardcoded allowlist blocks\nany third-party auth plugin (e.g. a site-specific SSO integration) from\nreauthenticating/managing its own trusts, app-creds, and OAuth1 tokens,\nsince it can never appear in a list only keystone maintainers can edit.\n\nCloses-Bug: #2153453\nChange-Id: Ic8775eb0fdaa2330206023818ce18f76430fa45e\nAssisted-by: Claude Sonnet 5 \u003cnoreply@anthropic.com\u003e\nSigned-off-by: Grzegorz Grasza \u003cxek@redhat.com\u003e\nSigned-off-by: Artem Goncharov \u003cartem.goncharov@gmail.com\u003e\n","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/d719264b44bbd87fe4e880619d9af9b9b7be8350"}],"resolve_conflicts_web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/d719264b44bbd87fe4e880619d9af9b9b7be8350"}]},"branch":"refs/heads/stable/2025.1"},"c8872fabde992542b304895f90d5ac1651e87e24":{"kind":"REWORK","_number":3,"created":"2026-08-25 22:48:40.000000000","uploader":{"_account_id":14250,"name":"Grzegorz Grasza","email":"xek@redhat.com","username":"xek"},"ref":"refs/changes/07/1002307/3","fetch":{"anonymous http":{"url":"https://review.opendev.org/openstack/keystone","ref":"refs/changes/07/1002307/3","commands":{"Checkout":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/3 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/3 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.opendev.org/openstack/keystone refs/changes/07/1002307/3 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.opendev.org/openstack/keystone refs/changes/07/1002307/3"}}},"commit":{"parents":[{"commit":"8b5cf08d5516380325e371cb0cdfb9b38e75a9b0","subject":"Merge \"Block app credential token rescoping\" into stable/2025.1","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/8b5cf08d5516380325e371cb0cdfb9b38e75a9b0"}]}],"author":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-07-23 07:32:00.000000000","tz":120},"committer":{"name":"Grzegorz Grasza","email":"xek@redhat.com","date":"2026-08-25 22:44:21.000000000","tz":120},"subject":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints","message":"trusts, oauth1, app-creds: reject delegated tokens across all endpoints\n\n_check_application_credential() in trusts.py only recognized\n\u0027application_credential\u0027 in token.methods, so OAuth1 access-token-scoped\nand ec2credential-derived tokens were never blocked from creating,\nlisting, reading, or deleting trusts -- unlike application_credential,\nwhich has had this restriction since LP#2148477.\n\nTwo more endpoints that mint a new persistent grant had the same gap:\n\n- users.py\u0027s _block_delegated_token_app_creds (guarding application\n  credential and access-rule CRUD) only checked trust_id/access_token_id,\n  so ec2credential-scoped tokens could create, list, read, and delete\n  application credentials.\n- os_oauth1.py\u0027s AuthorizeResource.put (PUT /v3/OS-OAUTH1/authorize) only\n  checked is_delegated_auth (trust/oauth1) and application_credential, so\n  an ec2credential-scoped token could authorize OAuth1 request tokens.\n\nAll three are extended to the same primary-auth-method allowlist used in\ncredentials.py, users.py, and token.py: any token whose methods aren\u0027t\nentirely primary auth methods is rejected outright. Trust-scoped tokens\nare deliberately not blocked from trust operations on trust_id alone --\nthat\u0027s the trust redelegation feature working as designed (a trustee\ncreating a further, narrower trust from one they were delegated) and\ntrustee self-service reads of their own trusts. A trust-scoped token\nwhose underlying method is itself delegated (an EC2 credential\u0027s blob\ncan embed a trust_id, see keystone.api.credentials._assign_unique_id) is\nstill caught by the method check regardless of trust scoping.\napplication_credential keeps its existing, documented opt-in escape\nhatch for trust management\n(allow_insecure_application_credential_trust_escalation) and its\nunrestricted/restricted distinction for creating further application\ncredentials (_check_unrestricted_application_credential); OAuth1 and EC2\ncredentials have no such use case and are blocked unconditionally\neverywhere.\n\nThis also closes off the underlying role-escalation path in trust\ncreation: trust role validation checks the trustor\u0027s full role\nassignments, not the requesting token\u0027s own scoped roles, so a\nnarrowly-scoped oauth1/ec2 token could previously delegate roles it was\nnever itself authorized for. Blocking those token types from trust\ncreation removes the path to that gap without needing to touch the\nvalidation itself.\n\nNeither the app-cred nor the OAuth1-authorize gap is reachable on\ncurrent master, where a separate middleware change globally rejects any\ncaller token with \u0027ec2credential\u0027 in its methods before Flask routing --\nbut that change is not backported to stable branches, so both gaps are\nlive there. Fixed at the source regardless, so the guard doesn\u0027t depend\non an unrelated middleware check remaining in place.\n\nAn empty token.methods list (e.g. an ec2credential-derived token that\nlost its methods on a fernet cache-miss round-trip -- ec2credential has\nno bit in the method bitmask) is also treated as delegated at all three\ncall sites: _PRIMARY_AUTH_METHODS.issuperset([]) is True, so without this\nan empty list would otherwise be accepted as \u0027all primary\u0027.\n\nConsolidated the three independent _PRIMARY_AUTH_METHODS copies (this\npatch, LP#2158538, LP#2159643) into keystone.api._shared.delegation,\nper gtema\u0027s review comment #16 -- now that all three land together the\nNameError-avoidance reason for keeping them separate no longer applies.\nAlso replaced the hardcoded method list with an operator-extensible one\n([auth] additional_primary_auth_methods): a hardcoded allowlist blocks\nany third-party auth plugin (e.g. a site-specific SSO integration) from\nreauthenticating/managing its own trusts, app-creds, and OAuth1 tokens,\nsince it can never appear in a list only keystone maintainers can edit.\n\nCloses-Bug: #2153453\nChange-Id: Ic8775eb0fdaa2330206023818ce18f76430fa45e\nAssisted-by: Claude Sonnet 5 \u003cnoreply@anthropic.com\u003e\nSigned-off-by: Grzegorz Grasza \u003cxek@redhat.com\u003e\nSigned-off-by: Artem Goncharov \u003cartem.goncharov@gmail.com\u003e\n","web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/c8872fabde992542b304895f90d5ac1651e87e24"}],"resolve_conflicts_web_links":[{"name":"gitea","tooltip":"Open in GitWeb","url":"https://opendev.org/openstack/keystone/commit/c8872fabde992542b304895f90d5ac1651e87e24"}]},"branch":"refs/heads/stable/2025.1"}},"requirements":[],"submit_records":[{"rule_name":"gerrit~DefaultSubmitRule","status":"CLOSED","labels":[{"label":"Verified","status":"MAY","applied_by":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]}},{"label":"Code-Review","status":"MAY","applied_by":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"}},{"label":"Workflow","status":"MAY","applied_by":{"_account_id":27900,"name":"Artem Goncharov","email":"artem.goncharov@gmail.com","username":"gtema"}}]}],"submit_requirements":[{"name":"Verified","description":"Verified in gate by CI","status":"SATISFIED","is_legacy":false,"submittability_expression_result":{"expression":"label:Verified\u003dMAX AND -label:Verified\u003dMIN","fulfilled":true,"status":"PASS","passing_atoms":["label:Verified\u003dMAX"],"failing_atoms":["label:Verified\u003dMIN"],"atom_explanations":{"label:Verified\u003dMAX":"","label:Verified\u003dMIN":""}}},{"name":"Code-Review","description":"Code reviewed by core reviewer","status":"SATISFIED","is_legacy":false,"submittability_expression_result":{"expression":"label:Code-Review\u003dMAX AND -label:Code-Review\u003dMIN","fulfilled":true,"status":"PASS","passing_atoms":["label:Code-Review\u003dMAX"],"failing_atoms":["label:Code-Review\u003dMIN"],"atom_explanations":{"label:Code-Review\u003dMAX":"","label:Code-Review\u003dMIN":""}}},{"name":"Workflow","description":"Approved for gate by core reviewer","status":"SATISFIED","is_legacy":false,"submittability_expression_result":{"expression":"label:Workflow\u003dMAX AND -label:Workflow\u003dMIN","fulfilled":true,"status":"PASS","passing_atoms":["label:Workflow\u003dMAX"],"failing_atoms":["label:Workflow\u003dMIN"],"atom_explanations":{"label:Workflow\u003dMAX":"","label:Workflow\u003dMIN":""}}}]}
