smolnar82 opened a new pull request, #1334:
URL: https://github.com/apache/knox/pull/1334

   [KNOX-3399](https://issues.apache.org/jira/browse/KNOX-3399) - Fix and 
complete RFC 8693 token exchange
   
   ## What changes were proposed in this pull request?
   
   RFC 8693 token exchange did not work when a client sent the request the 
normal, standards-compliant way — a `POST` with an 
`application/x-www-form-urlencoded` body. The request was silently treated as a 
plain single-token request and the `actor_token` was ignored, so the 
on-behalf-of (OBO) flow never actually ran.
   
   This PR fixes that and brings the flow in line with the RFC:
   - **Fix:** the token-exchange request is now correctly recognized when 
`grant_type`, `subject_token`, and `actor_token` are sent in the request body 
(previously only the URL query string was inspected, which no real client uses).
   - **Spec alignment:** `actor_token` is now **optional** (per RFC 8693). With 
an actor token the exchange is a delegation/OBO exchange; without one, the 
subject token is simply exchanged for a new token representing the subject.
   - **Spec alignment:** `subject_token_type` (required) and `actor_token_type` 
(required only when an actor token is present) are now honored and validated. 
Only standard JWT token types are accepted; anything else is rejected with a 
clear error.
   - **Cleanup:** the token-exchange logic was moved out of 
`JWTFederationFilter` into a small, dedicated `TokenExchangeHandler` class, 
which the filter delegates to. This slims the filter down and makes the 
exchange logic easy to test in isolation.
   
   **Note for reviewers - behavior change:** token exchange now requires a JWT 
`subject_token` and a `subject_token_type`. Passcode-style subject tokens are 
no longer accepted through this grant (they continue to work via normal 
Bearer/passcode authentication). Callers must now include `subject_token_type` 
(and `actor_token_type` when sending an actor token).
   
   ## How was this patch tested?
   
   The original problem was reproduced and root-caused against a running 
gateway with a remote debugger (confirmed the request body parameters were not 
visible where the grant type was being read).
   1. New unit tests:
     - `TokenExchangeHandlerTest`: covers all the request-validation rules and 
both the delegation (with actor) and plain (no actor) exchange paths.
     - `JWTFederationFilterTokenExchangeRoutingTest`: verifies the filter 
routes a body-based token-exchange request to the handler, and does not route 
other requests to it.
     - The full `gateway-provider-security-jwt` module test suite passes (272 
tests, 0 failures) and Checkstyle is clean.
   
   2. Manual testing:
   ```
   export 
SUBJECT_TOKEN="eyJqa3UiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2dhdGV3YXkvaG9tZXBhZ2Uva25veHRva2VuL2FwaS92Mi9qd2tzLmpzb24iLCJraWQiOiJHcE9sOFhmc05BT0Z6Uk9WaGItSE03dko1Q1JxUjFHTU03cFhIZFEyOVZRIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJhZG1pbiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMvZ2F0ZXdheS9ob21lcGFnZS9rbm94dG9rZW4vYXBpL3YyL2p3a3MuanNvbiIsImtpZCI6IkdwT2w4WGZzTkFPRnpST1ZoYi1ITTd2SjVDUnFSMUdNTTdwWEhkUTI5VlEiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNzg1NDIzNDcxLCJtYW5hZ2VkLnRva2VuIjoidHJ1ZSIsImtub3guaWQiOiIyMzU3NGEyZS01OGVlLTQzYTMtOTNkZi01NjhmYmU2OTk4ZTYifQ.QPVU56NA4O5APfpYZXsoqlDHgaM5arRng3Apk3kDu5xvJUK22aHSZFzEGIZbwUyWB4xJ8syfTB-K9s_9jFn7SzzCxNKjcjWrsDOic1GL-dTa2PcTFBGIVUOQNlCeFnrASyodR6HDE3b1-ITN8P7bLTqpys3JSRgDpgnebbjO4_tWcNXmGNJCaGQUX8ugijysNrcvxY9-3FABtRtx6dKqNqD_RwwI1MVCcjDJ8FUHFjchO1GzfRS9m_XwD5ruG1ShXumthSBJep0eaWuGb0tdKTepuhqzQuPekpuck4kbxk9N-817G0aPYC4cvR9UBwKcqBDPHhjcx7RmZhs5WD_tiQ"
   export 
ACTOR_TOKEN="eyJqa3UiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2dhdGV3YXkvaG9tZXBhZ2Uva25veHRva2VuL2FwaS92Mi9qd2tzLmpzb24iLCJraWQiOiJHcE9sOFhmc05BT0Z6Uk9WaGItSE03dko1Q1JxUjFHTU03cFhIZFEyOVZRIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJzYW0iLCJqa3UiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2dhdGV3YXkvaG9tZXBhZ2Uva25veHRva2VuL2FwaS92Mi9qd2tzLmpzb24iLCJraWQiOiJHcE9sOFhmc05BT0Z6Uk9WaGItSE03dko1Q1JxUjFHTU03cFhIZFEyOVZRIiwiaXNzIjoiS05PWFNTTyIsImV4cCI6MTc4NTQ5MTQxOSwibWFuYWdlZC50b2tlbiI6InRydWUiLCJrbm94LmlkIjoiY2U1NDJlYjctZjdhOS00NWM1LWEzODQtMWVmNTY4NmIwZjIxIn0.ARIJdwglq0-9vWZa38yk8722w_BX7aiFoS8X1NRSCbA92ETUD0OwiFCeweydKie6WTU__vhqZp8PDL0pWhj0W4K7GecoPyHkz-PgRdPEDXDMjLVTzbFit47ioADuK-icHE3LS6vRuWNde6F3ejaMqKs0F_qp5j0ps-tXwIvlOGy8WTp0tAM-mN-KJ4B83rBRtr669qk4GYLajbVACN5LQHzh5NCnuZR_f3rAbBvhqo6pcOmVBrfCOyQeChVs2k4BTnbZui7o85kHTROi3X_u9-jvxdoNR-xkOJamO4bXnHLzLanuegfSUWW96MAeakqR141LnHL4DcCBpbg5g_jEig"
   
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN"
   <html>
   <head>
   <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
   <title>Error 400 invalid_request: the subject_token_type parameter is 
required</title>
   </head>
   <body><h2>HTTP ERROR 400 invalid_request: the subject_token_type parameter 
is required</h2>
   <table>
   <tr><th>URI:</th><td>/gateway/tokenexchange/knoxtoken/api/v2/token</td></tr>
   <tr><th>STATUS:</th><td>400</td></tr>
   <tr><th>MESSAGE:</th><td>invalid_request: the subject_token_type parameter 
is required</td></tr>
   <tr><th>SERVLET:</th><td>tokenexchange-knox-gateway-servlet</td></tr>
   </table>
   
   </body>
   </html>
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN" \
   > -d "subject_token_type=urn:ietf:params:oauth:token-type:invalid"
   <html>
   <head>
   <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
   <title>Error 400 unsupported_token_type: unsupported subject_token_type 
urn:ietf:params:oauth:token-type:invalid</title>
   </head>
   <body><h2>HTTP ERROR 400 unsupported_token_type: unsupported 
subject_token_type urn:ietf:params:oauth:token-type:invalid</h2>
   <table>
   <tr><th>URI:</th><td>/gateway/tokenexchange/knoxtoken/api/v2/token</td></tr>
   <tr><th>STATUS:</th><td>400</td></tr>
   <tr><th>MESSAGE:</th><td>unsupported_token_type: unsupported 
subject_token_type urn:ietf:params:oauth:token-type:invalid</td></tr>
   <tr><th>SERVLET:</th><td>tokenexchange-knox-gateway-servlet</td></tr>
   </table>
   
   </body>
   </html>
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN" \
   > -d "subject_token_type=urn:ietf:params:oauth:token-type:jwt"
   
{"access_token":"eyJqa3UiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2dhdGV3YXkvdG9rZW5leGNoYW5nZS9rbm94dG9rZW4vYXBpL3YyL2p3a3MuanNvbiIsImtpZCI6IkdwT2w4WGZzTkFPRnpST1ZoYi1ITTd2SjVDUnFSMUdNTTdwWEhkUTI5VlEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImprdSI6Imh0dHBzOi8vbG9jYWxob3N0Ojg0NDMvZ2F0ZXdheS90b2tlbmV4Y2hhbmdlL2tub3h0b2tlbi9hcGkvdjIvandrcy5qc29uIiwia2lkIjoiR3BPbDhYZnNOQU9GelJPVmhiLUhNN3ZKNUNScVIxR01NN3BYSGRRMjlWUSIsImlzcyI6IktOT1hTU08iLCJleHAiOjE3OTU3NzIxODEsIm1hbmFnZWQudG9rZW4iOiJ0cnVlIiwia25veC5pZCI6IjY4NGVlY2M4LTNiYmUtNDczZC1hOWZhLTdjNzU3MTZjNDM2OCJ9.mHcADoy9-q136i8Z2oux8clORuP7FZ_3ernCKjAzErXX1xX957B6iMxCTKojLWcT8D-0B9zujYtqpZclwXYB7OSFR031N8VrTDMJwLFLclm8XBMJ4F_4lT7DwWeYMIhH61w58TKdPsBDIRQDFnfP18v6cdSHd3IUno5CRXu2ZlOs6j2yThk7SvJq8NOFbsS5PS3NQHwdzWoeAzneXtzrOEOPw9QdbPnn9RzcKm9IOZFqPOcVxyg3B1jz2zahZThGmBSzjLm0ojLvBFJfloTSoaJgmb1n446enE1JJNTP8BApHNuOGSJNoqbRMwK3_4QdRJ_eT8wWWvHENPfCuGWdAA","token_id":"684eecc8-3bbe-473d-a9fa-7c75716c4368","managed":"true","endpoint_public_
 
cert":"MIIDZDCCAkygAwIBAgIIAbJD1h0J2cAwDQYJKoZIhvcNAQELBQAwXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMB4XDTI2MDQxNjEyNTIyOVoXDTI3MDQxNjEyNTIyOVowXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm5XaN8VbAwwERG5e88U8IlKLpq3PvdT9nxjkp7DiVxkRaJAQkSrDOv9UUK8g9VV/xMD6No1yS6PhoufrxUd2e14L4QmXrwW/Qh2V9W7RQMHgUDmxt+5tr3hTbrM9UjavXkOh2d/XDpt/yb/v6MkxH3KUH/snU9iN6KRjdCrITRQ5JneHXzedwDxpGRIH1m4X90086HLUWfLwaxtmjXchokSeg+6s44XuO3oaeCJMpITJQEOKmsOigWx3RZwTRK3MrK/MOrRuF0lOphXVrMw1vvVmeTJQs1UzFuQOE9w7THo3qak+dANnq+rfIXd7M+Hinw6L9QrfQqSoEtLg4piTZQIDAQABoyQwIjAgBgNVHREEGTAXggpLNjM1MlA2SjQxgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAAwjRAziVRGeB9IfZYRM/1yLy9KGf8nzVhWTRzRa2Y8NLgjLt1yG62iS7t8M1CjLEYAowvR4a+GrRC2TRaOgOAsIYLt5yLbT4YaFxprTBajdz55Xqeiy7AgETfLE8FYfQTVGWp/snehmpMAme0Pc6ys6WCRLvOJWMXZHlR0w1b
 
GUYsUC4QGAcKVS5GP27FXijigxoCVfoBkJ2NvsK62Uc3Pz1hFtzu+pY4+CrdockdHzrDZnJrpmmYH/g+B4hXWjouAkEoYUDtdwyQ1zdrE/BTiD3ozPdcmAnEH7utWChIzPcFr0KlpIYcYiySGBTf4PcJPGd6qeEgXTu3MGVQ6uMO8=","token_type":"Bearer","expires_in":1795772181545,"passcode":"TmpnMFpXVmpZemd0TTJKaVpTMDBOek5rTFdFNVptRXROMk0zTlRjeE5tTTBNelk0OjpOamcxTlRjeFpqVXRaakptTkMwME9HTTRMVGcxWmpRdFpURXlaR1kyTkRreVpXUXk="}$
 
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN" \
   > -d "subject_token_type=urn:ietf:params:oauth:token-type:jwt" \
   > -d "actor_token=$ACTOR_TOKEN"
   <html>
   <head>
   <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
   <title>Error 400 invalid_request: actor_token_type is required when 
actor_token is present</title>
   </head>
   <body><h2>HTTP ERROR 400 invalid_request: actor_token_type is required when 
actor_token is present</h2>
   <table>
   <tr><th>URI:</th><td>/gateway/tokenexchange/knoxtoken/api/v2/token</td></tr>
   <tr><th>STATUS:</th><td>400</td></tr>
   <tr><th>MESSAGE:</th><td>invalid_request: actor_token_type is required when 
actor_token is present</td></tr>
   <tr><th>SERVLET:</th><td>tokenexchange-knox-gateway-servlet</td></tr>
   </table>
   
   </body>
   </html>
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN" \
   > -d "subject_token_type=urn:ietf:params:oauth:token-type:jwt" \
   > -d "actor_token=$ACTOR_TOKEN" \
   > -d "actor_token_type=urn:ietf:params:oauth:token-type:dummy"
   <html>
   <head>
   <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
   <title>Error 400 unsupported_token_type: unsupported actor_token_type 
urn:ietf:params:oauth:token-type:dummy</title>
   </head>
   <body><h2>HTTP ERROR 400 unsupported_token_type: unsupported 
actor_token_type urn:ietf:params:oauth:token-type:dummy</h2>
   <table>
   <tr><th>URI:</th><td>/gateway/tokenexchange/knoxtoken/api/v2/token</td></tr>
   <tr><th>STATUS:</th><td>400</td></tr>
   <tr><th>MESSAGE:</th><td>unsupported_token_type: unsupported 
actor_token_type urn:ietf:params:oauth:token-type:dummy</td></tr>
   <tr><th>SERVLET:</th><td>tokenexchange-knox-gateway-servlet</td></tr>
   </table>
   
   </body>
   </html>
   
   $ curl -k -X POST \
   > "https://localhost:8443/gateway/tokenexchange/knoxtoken/api/v2/token"; \
   > -H "Content-Type: application/x-www-form-urlencoded" \
   > -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
   > -d "subject_token=$SUBJECT_TOKEN" \
   > -d "subject_token_type=urn:ietf:params:oauth:token-type:jwt" \
   > -d "actor_token=$ACTOR_TOKEN" \
   > -d "actor_token_type=urn:ietf:params:oauth:token-type:jwt"
   
{"access_token":"eyJqa3UiOiJodHRwczovL2xvY2FsaG9zdDo4NDQzL2dhdGV3YXkvdG9rZW5leGNoYW5nZS9rbm94dG9rZW4vYXBpL3YyL2p3a3MuanNvbiIsImtpZCI6IkdwT2w4WGZzTkFPRnpST1ZoYi1ITTd2SjVDUnFSMUdNTTdwWEhkUTI5VlEiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImFjdCI6eyJzdWIiOiJzYW0ifSwiamt1IjoiaHR0cHM6Ly9sb2NhbGhvc3Q6ODQ0My9nYXRld2F5L3Rva2VuZXhjaGFuZ2Uva25veHRva2VuL2FwaS92Mi9qd2tzLmpzb24iLCJraWQiOiJHcE9sOFhmc05BT0Z6Uk9WaGItSE03dko1Q1JxUjFHTU03cFhIZFEyOVZRIiwiaXNzIjoiS05PWFNTTyIsImV4cCI6MTc5NTc3MzA1MywibWFuYWdlZC50b2tlbiI6InRydWUiLCJrbm94LmlkIjoiYmExMmQ2YjktODdhYy00YTBhLWFmYmUtZDQ2MDRkZWZlZmZlIn0.AHQhDm3YEIrQhBSJ4dFpPumjZMfT60kiC3mkPdTziPk1v-r8AsFtPdyFPvctUvaG-jDinJojgGh0fQ-65YiC3j0uZ-6dXi5uD6X9M4pSs8MRuD_vfvKwUdMrynoZJIo35Dd7JO773eNAMTNQcvDtN1mmiZ_fsiuzwkHXyQUMqvXI4M0rtWe-Nmqm-GUMZQumW8tFheg1XN-3P3F7HeLEjmj8mCv-9a9pVccUO_DXe1B3mRWxw2jOs5qUVkLqyFBglAa-RdaattqgullPec6hWQ2dfJsiOvSVu19Na7obuPR8eR5wX5eNor6q4Lb71mo7QDR6lFbjo_Ahe-lTiKoMYQ","token_id":"ba12d6b9-87ac-4a0a-afbe-d4604defeffe","manage
 
d":"true","endpoint_public_cert":"MIIDZDCCAkygAwIBAgIIAbJD1h0J2cAwDQYJKoZIhvcNAQELBQAwXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMB4XDTI2MDQxNjEyNTIyOVoXDTI3MDQxNjEyNTIyOVowXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm5XaN8VbAwwERG5e88U8IlKLpq3PvdT9nxjkp7DiVxkRaJAQkSrDOv9UUK8g9VV/xMD6No1yS6PhoufrxUd2e14L4QmXrwW/Qh2V9W7RQMHgUDmxt+5tr3hTbrM9UjavXkOh2d/XDpt/yb/v6MkxH3KUH/snU9iN6KRjdCrITRQ5JneHXzedwDxpGRIH1m4X90086HLUWfLwaxtmjXchokSeg+6s44XuO3oaeCJMpITJQEOKmsOigWx3RZwTRK3MrK/MOrRuF0lOphXVrMw1vvVmeTJQs1UzFuQOE9w7THo3qak+dANnq+rfIXd7M+Hinw6L9QrfQqSoEtLg4piTZQIDAQABoyQwIjAgBgNVHREEGTAXggpLNjM1MlA2SjQxgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAAwjRAziVRGeB9IfZYRM/1yLy9KGf8nzVhWTRzRa2Y8NLgjLt1yG62iS7t8M1CjLEYAowvR4a+GrRC2TRaOgOAsIYLt5yLbT4YaFxprTBajdz55Xqeiy7AgETfLE8FYfQTVGWp/snehmpMA
 
me0Pc6ys6WCRLvOJWMXZHlR0w1bGUYsUC4QGAcKVS5GP27FXijigxoCVfoBkJ2NvsK62Uc3Pz1hFtzu+pY4+CrdockdHzrDZnJrpmmYH/g+B4hXWjouAkEoYUDtdwyQ1zdrE/BTiD3ozPdcmAnEH7utWChIzPcFr0KlpIYcYiySGBTf4PcJPGd6qeEgXTu3MGVQ6uMO8=","token_type":"Bearer","expires_in":1795773053429,"passcode":"WW1FeE1tUTJZamt0T0RkaFl5MDBZVEJoTFdGbVltVXRaRFEyTURSa1pXWmxabVpsOjpNMlprTmpBd056Y3RZVFprTnkwME9UWXpMV0kxT1RrdE5XWTVPV05oT1Rsa01EazQ="}
   ```
   
   Decoded access tokens:
   <img width="1340" height="552" alt="image" 
src="https://github.com/user-attachments/assets/7e6539ca-e9f7-4035-9843-367780e275a8";
 />
   
   <img width="1318" height="616" alt="image" 
src="https://github.com/user-attachments/assets/322de74d-896e-460f-8a08-6cc5f2a2cbd6";
 />
   
   
   ## Integration Tests
   N/A
   
   ## UI changes
   N/A


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to