Commit 8d78740
committed
Revoke application artifacts through administration flows
Deleting an application or rotating its client secret are security events:
artifacts already issued to that application's OAuth client must stop being
accepted. Carry both out through administration flows so the revocation, the
session detachment and the action itself run as one orchestrated sequence.
Resolve an artifact's lifetime through an injected collaborator rather than by reading
the server runtime. Sizing a revocation needs the longest an artifact issued to a client
can live, which is a fact about OAuth token configuration, so the computation belongs to
tokenservice and the application declares only the resolver it calls. The composition
root is the one place that sees both domains, so it supplies it: the application package
carries no OAuth configuration dependency and reads no global state.
One preparatory executor serves both flows, selected by the node's revocation mode.
The mode states the breadth of the revocation, and each breadth belongs to exactly one
action: a deletion retires the client id, so every artifact it ever carried is denied,
while a secret regeneration denies only what was issued before the rotation. It
declares no default mode, so flow creation requires a node to state one.
Add two shipped ADMINISTRATION flows, default-application-deletion-flow and
default-client-secret-regeneration-flow, built from four new executors. The
preparatory node validates the target and publishes a trusted revocation plan;
the criteria and session nodes act on that plan; the final node performs the
delete or the rotation. Deletion revokes terminally, since a retired client id
can carry no future artifact. Rotation revokes only up to a cutoff, so tokens
minted with the new secret still pass.
Name both flows in the flow server-config section, alongside userDeletionFlow,
and drive them from the console: the delete action and the regenerate-secret
action resolve their configured handle and execute the flow, falling back to the
native endpoint only when no such flow is configured. The rotation flow returns
the new secret, generated with the server's entropy rather than the browser's,
in the only response that exposes it.
The native application endpoints are left unchanged, so revocation has exactly
one home.
A refused step reports its executor error in the response's error envelope, not
in a failureReason field that the API never sends. Read the real envelope and
carry the code on the thrown error so the console shows why a flow refused
instead of a generic failure, and apply the same fix to the user deletion path.
Cover the detachment in the integration suite. Deleting an application through
the flow was only ever exercised against an application nobody had logged into,
so the session node returned on an empty participation list and the work it
exists to do never ran. Two tests now establish a real session: one where a
second application shares it, which must survive the deletion, and one where the
deleted application was its only participant, which must not. Rotation refusals
for an application with no OAuth component, for a public client and for an
unknown application are covered alongside them.
Keep the seam internal. The administration executors declare the application
contract they consume in the executor package, so the flow's dependency on the
application service adds nothing to pkg, where anything added is exported from the
library and cannot be changed without a major release.
Name the credential operations for the credential rather than for the one action
they perform today, and report what validation found rather than what a revocation
needs. Validation answers whether an action may proceed and describes the artifacts
the application has issued; sizing a deny-list row from that description is one
consumer's business, not validation's. Further credential actions, a rotation that
keeps the old secret briefly valid and additional secrets, arrive as actions on the
same pair of methods instead of methods of their own.
Refuse the deletion while a dependent forbids it, the check userService already
performs before a user is deleted. The cascade removes the dependents that cascade;
this refuses the ones that must not go silently, and fails closed when a provider
cannot report its usage, since deleting on an unknown answer is what the check exists
to prevent.
Cover the branches an integration test can reach: the declarative refusal on both
administration flows, a target that is not an application, and the client-credentials
and refresh-token validity paths that decide how long a deny-list row must outlive the
artifacts it denies.
What remains uncovered in the application and session packages is error handling the
integration suite has no way to provoke: a failing dependency lookup, a corrupt
attribute blob, a failing client-secret write, a failing participation query, a failing
token-family revocation, a failing transaction. Reaching those needs fault injection,
which lives in the unit suite, and the integration patch-coverage check deliberately
does not load unit coverage. No threshold entry is recorded for them, so that check
reports both packages below its bar.
Size the deny-list row from both access-token subject configurations. Access token
validity is configured per token subject, and client_credentials reads the client
sub-config while the row was sized from the user one alone. A machine-to-machine
application with a longer client-token validity therefore got a row that went inert
while the tokens it denies were still valid, which is the failure this sizing exists
to avoid.
Carry the validator's own refusal out of the preparatory node. Every client-side
refusal became the executor's single error, so an application owned by a declarative
file, and one that no longer exists, were both reported as having no client secret to
rotate. The console resolves these codes to messages, so the reason it showed was
wrong rather than merely vague.
Refuse rather than fall back when a configured administration flow cannot be resolved.
An unset handle is the documented opt-out and still falls back to the native endpoint.
A handle that names a missing flow is the opposite: the deployment asked for flow-based
revocation, and deleting or rotating natively would strip the application or mint a new
secret while leaving every issued artifact valid, and report it as a success.
Name the secret executor for the artifact it acts on rather than the one action it
performs today. An executor name is persisted into stored flow definitions and their
version history, so a deployment that authors a flow against
ClientSecretRegenerationExecutor pins that name, and renaming it once further secret
actions exist would break those flows and need a migration. ClientSecretExecutor
carries the same behaviour under a name that already fits the rotation and additional
secrets that arrive later as executor modes.
Signed-off-by: Indeewai Wijesiri <indeewari@wso2.com>1 parent edaf54c commit 8d78740
81 files changed
Lines changed: 5657 additions & 2056 deletions
File tree
- backend
- cmd/server
- bootstrap
- dbscripts/runtime_persistent
- internal
- application
- model
- flow
- common
- config
- executor
- mgt
- session
- oauth/oauth2
- revocation
- tokenservice
- revocation
- system
- i18n/core
- revocationcache
- security
- tests/mocks
- applicationmock
- flow
- executormock
- sessionmock
- frontend
- apps/console/src/features
- applications
- api
- __tests__
- components
- models
- utils
- __tests__
- flows
- data
- models
- __tests__
- packages
- configure-users/src
- api/__tests__
- models
- utils
- __tests__
- i18n/src/locales
- tests/integration
- flow/execution
- oauth/sso
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
404 | 404 | | |
405 | 405 | | |
406 | 406 | | |
| 407 | + | |
| 408 | + | |
407 | 409 | | |
408 | 410 | | |
409 | | - | |
410 | 411 | | |
411 | 412 | | |
412 | 413 | | |
413 | 414 | | |
| 415 | + | |
| 416 | + | |
414 | 417 | | |
415 | 418 | | |
416 | 419 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1991 | 1991 | | |
1992 | 1992 | | |
1993 | 1993 | | |
| 1994 | + | |
| 1995 | + | |
| 1996 | + | |
| 1997 | + | |
| 1998 | + | |
| 1999 | + | |
| 2000 | + | |
| 2001 | + | |
| 2002 | + | |
| 2003 | + | |
| 2004 | + | |
| 2005 | + | |
| 2006 | + | |
| 2007 | + | |
| 2008 | + | |
| 2009 | + | |
| 2010 | + | |
| 2011 | + | |
| 2012 | + | |
| 2013 | + | |
| 2014 | + | |
| 2015 | + | |
| 2016 | + | |
| 2017 | + | |
| 2018 | + | |
| 2019 | + | |
| 2020 | + | |
| 2021 | + | |
| 2022 | + | |
| 2023 | + | |
| 2024 | + | |
| 2025 | + | |
| 2026 | + | |
| 2027 | + | |
| 2028 | + | |
| 2029 | + | |
| 2030 | + | |
| 2031 | + | |
| 2032 | + | |
| 2033 | + | |
| 2034 | + | |
| 2035 | + | |
| 2036 | + | |
| 2037 | + | |
| 2038 | + | |
| 2039 | + | |
| 2040 | + | |
| 2041 | + | |
| 2042 | + | |
| 2043 | + | |
| 2044 | + | |
| 2045 | + | |
| 2046 | + | |
| 2047 | + | |
| 2048 | + | |
| 2049 | + | |
| 2050 | + | |
| 2051 | + | |
| 2052 | + | |
| 2053 | + | |
| 2054 | + | |
| 2055 | + | |
| 2056 | + | |
| 2057 | + | |
| 2058 | + | |
| 2059 | + | |
| 2060 | + | |
| 2061 | + | |
| 2062 | + | |
| 2063 | + | |
| 2064 | + | |
| 2065 | + | |
| 2066 | + | |
| 2067 | + | |
| 2068 | + | |
| 2069 | + | |
| 2070 | + | |
| 2071 | + | |
| 2072 | + | |
| 2073 | + | |
| 2074 | + | |
| 2075 | + | |
| 2076 | + | |
| 2077 | + | |
| 2078 | + | |
| 2079 | + | |
| 2080 | + | |
| 2081 | + | |
| 2082 | + | |
| 2083 | + | |
| 2084 | + | |
| 2085 | + | |
| 2086 | + | |
| 2087 | + | |
| 2088 | + | |
| 2089 | + | |
| 2090 | + | |
| 2091 | + | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
| 2106 | + | |
| 2107 | + | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
| 2111 | + | |
| 2112 | + | |
| 2113 | + | |
| 2114 | + | |
| 2115 | + | |
| 2116 | + | |
| 2117 | + | |
| 2118 | + | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
| 2134 | + | |
| 2135 | + | |
| 2136 | + | |
| 2137 | + | |
| 2138 | + | |
| 2139 | + | |
| 2140 | + | |
| 2141 | + | |
| 2142 | + | |
| 2143 | + | |
| 2144 | + | |
| 2145 | + | |
| 2146 | + | |
| 2147 | + | |
| 2148 | + | |
| 2149 | + | |
| 2150 | + | |
| 2151 | + | |
| 2152 | + | |
| 2153 | + | |
| 2154 | + | |
| 2155 | + | |
1994 | 2156 | | |
1995 | 2157 | | |
1996 | 2158 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| 67 | + | |
67 | 68 | | |
68 | 69 | | |
69 | 70 | | |
| |||
417 | 418 | | |
418 | 419 | | |
419 | 420 | | |
420 | | - | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
421 | 425 | | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
422 | 429 | | |
423 | 430 | | |
424 | 431 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
98 | 102 | | |
99 | 103 | | |
100 | 104 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
98 | 102 | | |
99 | 103 | | |
100 | 104 | | |
| |||
0 commit comments