[ 
https://issues.apache.org/jira/browse/KNOX-3399?focusedWorklogId=1032993&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1032993
 ]

ASF GitHub Bot logged work on KNOX-3399:
----------------------------------------

                Author: ASF GitHub Bot
            Created on: 30/Jul/26 10:05
            Start Date: 30/Jul/26 10:05
    Worklog Time Spent: 10m 
      Work Description: 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/snehmpMAme0Pc6ys6WCRLvOJWMXZHlR0w1bGUYsUC4QGAcKVS5GP27FXijigxoCVfoBkJ2NvsK62Uc3Pz1hFtzu+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","managed":"true","endpoint_public_cert":"MIIDZDCCAkygAwIBAgIIAbJD1h0J2cAwDQYJKoZIhvcNAQELBQAwXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMB4XDTI2MDQxNjEyNTIyOVoXDTI3MDQxNjEyNTIyOVowXzESMBAGA1UEAwwJbG9jYWxob3N0MQ0wCwYDVQQLDARUZXN0MQ8wDQYDVQQKDAZIYWRvb3AxDTALBgNVBAcMBFRlc3QxDTALBgNVBAgMBFRlc3QxCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm5XaN8VbAwwERG5e88U8IlKLpq3PvdT9nxjkp7DiVxkRaJAQkSrDOv9UUK8g9VV/xMD6No1yS6PhoufrxUd2e14L4QmXrwW/Qh2V9W7RQMHgUDmxt+5tr3hTbrM9UjavXkOh2d/XDpt/yb/v6MkxH3KUH/snU9iN6KRjdCrITRQ5JneHXzedwDxpGRIH1m4X90086HLUWfLwaxtmjXchokSeg+6s44XuO3oaeCJMpITJQEOKmsOigWx3RZwTRK3MrK/MOrRuF0lOphXVrMw1vvVmeTJQs1UzFuQOE9w7THo3qak+dANnq+rfIXd7M+Hinw6L9QrfQqSoEtLg4piTZQIDAQABoyQwIjAgBgNVHREEGTAXggpLNjM1MlA2SjQxgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAAwjRAziVRGeB9IfZYRM/1yLy9KGf8nzVhWTRzRa2Y8NLgjLt1yG62iS7t8M1CjLEYAowvR4a+GrRC2TRaOgOAsIYLt5yLbT4YaFxprTBajdz55Xqeiy7AgETfLE8FYfQTVGWp/snehmpMAme0Pc6ys6WCRLvOJWMXZHlR0w1bGUYsUC4QGAcKVS5GP27FXijigxoCVfoBkJ2NvsK62Uc3Pz1hFtzu+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




Issue Time Tracking
-------------------

            Worklog Id:     (was: 1032993)
    Remaining Estimate: 0h
            Time Spent: 10m

> RFC 8693 token exchange (handleTokenExchange) unreachable for 
> x-www-form-urlencoded POSTs
> -----------------------------------------------------------------------------------------
>
>                 Key: KNOX-3399
>                 URL: https://issues.apache.org/jira/browse/KNOX-3399
>             Project: Apache Knox
>          Issue Type: Bug
>          Components: Server
>    Affects Versions: 3.0.0
>            Reporter: Sandor Molnar
>            Assignee: Sandor Molnar
>            Priority: Major
>             Fix For: 3.0.0
>
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> {{JWTFederationFilter.doFilter}} reads {{grant_type}} via {{getParameter}} on 
> the wrapped request. Form-encoded requests are wrapped in 
> {{UrlEncodedFormRequest}}, whose {{getParameter}} returns query-string values 
> only and ignores the body (by design). So for a standard RFC 8693 POST (grant 
> + tokens in the body), {{grant_type}} reads back {{null}}, the 
> {{handleTokenExchange}} branch is skipped, and the request falls through to 
> the single-token path - which validates only {{subject_token}} and silently 
> ignores {{actor_token}}.
> *Impact:* the two-token OBO flow never runs over the normal content type. A 
> POST with *no* {{actor_token}} still returns 200:
> {code}
> $ 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&subject_token=$SUBJECT_TOKEN"
> {"access_token":"eyJqa3UiOi...","token_id":"e313ffbc-b27e-468e-a684-192b8939ca87","managed":"true","endpoint_public_cert":"MIIDZDE...ETTA="
> {code}
> *Evidence (remote debugger, on v3.0.0 branch):* 
> {{httpRequest.getParameter("grant_type") → null}} whereas 
> {{ServletRequestUtils.unwrapHttpServletRequest(request).getParameter("grant_type")
>  → the expected URN}}.
> *Fix direction:* in {{doFilter}}, read {{grant_type}} from the unwrapped 
> request (guard on absent Authorization header so proxied bodies aren't 
> consumed); read subject_token/actor_token from the unwrapped request in 
> {{handleTokenExchange}}; keep passing the wrapped request downstream. Add a 
> regression test in {{OAuthFlowsFederationFilterTest}} posting grant + both 
> tokens in the body (wrapped in {{UrlEncodedFormRequest}}).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to