lmccay commented on code in PR #1262:
URL: https://github.com/apache/knox/pull/1262#discussion_r3421469656


##########
gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java:
##########
@@ -405,6 +415,132 @@ private boolean 
authenticateWithCookies(HttpServletRequest request, HttpServletR
     return false;
   }
 
+  /**
+   * Handle RFC 8693 token exchange flow.
+   *
+   * <p>This method validates both the subject_token and actor_token 
parameters,
+   * creates a TokenExchangePrincipal with the identity information from both 
tokens,
+   * and establishes a Subject with the actor as the PrimaryPrincipal.</p>
+   *
+   * <p>The TokenExchangePrincipal signals to the identity assertion layer that
+   * impersonation should be established with the subject as the 
ImpersonatedPrincipal.</p>
+   *
+   * @param request the HTTP request containing subject_token and actor_token 
parameters
+   * @param response the HTTP response
+   * @param chain the filter chain
+   * @throws IOException if an I/O error occurs
+   * @throws ServletException if a servlet error occurs
+   */
+  private void handleTokenExchange(HttpServletRequest request, 
HttpServletResponse response, FilterChain chain)
+      throws IOException, ServletException {
+    // Extract subject_token (required)
+    String subjectTokenValue = request.getParameter(SUBJECT_TOKEN);
+    if (subjectTokenValue == null || subjectTokenValue.isEmpty()) {
+      handleValidationError(request, response, 
HttpServletResponse.SC_BAD_REQUEST,
+          "RFC 8693 token exchange requires subject_token parameter");
+      return;
+    }
+
+    // Extract actor_token (required for proper token exchange)
+    String actorTokenValue = request.getParameter(ACTOR_TOKEN);
+    if (actorTokenValue == null || actorTokenValue.isEmpty()) {
+      handleValidationError(request, response, 
HttpServletResponse.SC_BAD_REQUEST,
+          "RFC 8693 token exchange requires actor_token parameter");
+      return;
+    }
+
+    try {
+      // Parse and validate subject_token
+      JWT subjectToken = parseAndValidateJWT(request, response, chain, 
subjectTokenValue);
+      if (subjectToken == null) {
+        // Validation failed, error response already sent
+        return;
+      }
+
+      // Parse and validate actor_token
+      JWT actorToken = parseAndValidateJWT(request, response, chain, 
actorTokenValue);
+      if (actorToken == null) {
+        // Validation failed, error response already sent
+        return;
+      }
+
+      // Create Subject with actor as PrimaryPrincipal and 
TokenExchangePrincipal
+      Subject subject = createSubjectForTokenExchange(subjectToken, 
actorToken);
+
+      continueWithEstablishedSecurityContext(subject, request, response, 
chain);
+
+    } catch (ParseException e) {
+      LOGGER.failedToParsePasscodeToken(e);
+      handleValidationError(request, response, 
HttpServletResponse.SC_UNAUTHORIZED,
+          "Failed to parse token in token exchange: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Parse and validate a JWT token.
+   *
+   * @param request the HTTP request
+   * @param response the HTTP response
+   * @param chain the filter chain
+   * @param tokenValue the JWT string to parse
+   * @return the parsed and validated JWT, or null if validation failed
+   * @throws ParseException if the JWT cannot be parsed
+   * @throws IOException if an I/O error occurs during validation
+   * @throws ServletException if a servlet error occurs during validation
+   */
+  private JWT parseAndValidateJWT(HttpServletRequest request, 
HttpServletResponse response,
+                                  FilterChain chain, String tokenValue)
+      throws ParseException, IOException, ServletException {
+    JWT token = new JWTToken(tokenValue);
+    if (validateToken(request, response, chain, token)) {
+      return token;
+    }
+    // Validation failed - error response already sent by validateToken
+    return null;
+  }
+
+  /**
+   * Create a Subject for RFC 8693 token exchange with proper principal setup.
+   *
+   * @param subjectToken the validated subject token
+   * @param actorToken the validated actor token
+   * @return a Subject configured for token exchange
+   */
+  private Subject createSubjectForTokenExchange(JWT subjectToken, JWT 
actorToken) {
+    // Extract identities from the tokens
+    String subjectPrincipalName = subjectToken.getSubject();
+    String subjectIssuer = subjectToken.getIssuer();
+    String actorPrincipalName = actorToken.getSubject();
+    String actorIssuer = actorToken.getIssuer();
+    // Create principals for the Subject
+    // PrimaryPrincipal is the ACTOR (the authenticated party)
+    org.apache.knox.gateway.security.PrimaryPrincipal primaryPrincipal =
+        new 
org.apache.knox.gateway.security.PrimaryPrincipal(actorPrincipalName);

Review Comment:
   got it



##########
gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/JWTFederationFilter.java:
##########
@@ -405,6 +415,132 @@ private boolean 
authenticateWithCookies(HttpServletRequest request, HttpServletR
     return false;
   }
 
+  /**
+   * Handle RFC 8693 token exchange flow.
+   *
+   * <p>This method validates both the subject_token and actor_token 
parameters,
+   * creates a TokenExchangePrincipal with the identity information from both 
tokens,
+   * and establishes a Subject with the actor as the PrimaryPrincipal.</p>
+   *
+   * <p>The TokenExchangePrincipal signals to the identity assertion layer that
+   * impersonation should be established with the subject as the 
ImpersonatedPrincipal.</p>
+   *
+   * @param request the HTTP request containing subject_token and actor_token 
parameters
+   * @param response the HTTP response
+   * @param chain the filter chain
+   * @throws IOException if an I/O error occurs
+   * @throws ServletException if a servlet error occurs
+   */
+  private void handleTokenExchange(HttpServletRequest request, 
HttpServletResponse response, FilterChain chain)
+      throws IOException, ServletException {
+    // Extract subject_token (required)
+    String subjectTokenValue = request.getParameter(SUBJECT_TOKEN);
+    if (subjectTokenValue == null || subjectTokenValue.isEmpty()) {
+      handleValidationError(request, response, 
HttpServletResponse.SC_BAD_REQUEST,
+          "RFC 8693 token exchange requires subject_token parameter");
+      return;
+    }
+
+    // Extract actor_token (required for proper token exchange)
+    String actorTokenValue = request.getParameter(ACTOR_TOKEN);
+    if (actorTokenValue == null || actorTokenValue.isEmpty()) {
+      handleValidationError(request, response, 
HttpServletResponse.SC_BAD_REQUEST,
+          "RFC 8693 token exchange requires actor_token parameter");
+      return;
+    }
+
+    try {
+      // Parse and validate subject_token
+      JWT subjectToken = parseAndValidateJWT(request, response, chain, 
subjectTokenValue);
+      if (subjectToken == null) {
+        // Validation failed, error response already sent
+        return;
+      }
+
+      // Parse and validate actor_token
+      JWT actorToken = parseAndValidateJWT(request, response, chain, 
actorTokenValue);
+      if (actorToken == null) {
+        // Validation failed, error response already sent
+        return;
+      }
+
+      // Create Subject with actor as PrimaryPrincipal and 
TokenExchangePrincipal
+      Subject subject = createSubjectForTokenExchange(subjectToken, 
actorToken);
+
+      continueWithEstablishedSecurityContext(subject, request, response, 
chain);
+
+    } catch (ParseException e) {
+      LOGGER.failedToParsePasscodeToken(e);
+      handleValidationError(request, response, 
HttpServletResponse.SC_UNAUTHORIZED,
+          "Failed to parse token in token exchange: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Parse and validate a JWT token.
+   *
+   * @param request the HTTP request
+   * @param response the HTTP response
+   * @param chain the filter chain
+   * @param tokenValue the JWT string to parse
+   * @return the parsed and validated JWT, or null if validation failed
+   * @throws ParseException if the JWT cannot be parsed
+   * @throws IOException if an I/O error occurs during validation
+   * @throws ServletException if a servlet error occurs during validation
+   */
+  private JWT parseAndValidateJWT(HttpServletRequest request, 
HttpServletResponse response,
+                                  FilterChain chain, String tokenValue)
+      throws ParseException, IOException, ServletException {
+    JWT token = new JWTToken(tokenValue);
+    if (validateToken(request, response, chain, token)) {
+      return token;
+    }
+    // Validation failed - error response already sent by validateToken
+    return null;
+  }
+
+  /**
+   * Create a Subject for RFC 8693 token exchange with proper principal setup.
+   *
+   * @param subjectToken the validated subject token
+   * @param actorToken the validated actor token
+   * @return a Subject configured for token exchange
+   */
+  private Subject createSubjectForTokenExchange(JWT subjectToken, JWT 
actorToken) {
+    // Extract identities from the tokens
+    String subjectPrincipalName = subjectToken.getSubject();
+    String subjectIssuer = subjectToken.getIssuer();
+    String actorPrincipalName = actorToken.getSubject();
+    String actorIssuer = actorToken.getIssuer();
+    // Create principals for the Subject
+    // PrimaryPrincipal is the ACTOR (the authenticated party)
+    org.apache.knox.gateway.security.PrimaryPrincipal primaryPrincipal =
+        new 
org.apache.knox.gateway.security.PrimaryPrincipal(actorPrincipalName);
+
+    // TokenExchangePrincipal carries metadata for identity assertion layer
+    org.apache.knox.gateway.security.TokenExchangePrincipal 
tokenExchangePrincipal =
+        new org.apache.knox.gateway.security.TokenExchangePrincipalImpl(
+            subjectPrincipalName, subjectIssuer, actorPrincipalName, 
actorIssuer);
+
+    // Extract actor chain from subject_token (if present) using existing logic
+    java.util.List<java.util.Map<String, Object>> actorChain =
+        
org.apache.knox.gateway.services.security.token.TokenUtils.extractActorChain(subjectToken);

Review Comment:
   got it



-- 
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