ramackri opened a new pull request, #1081:
URL: https://github.com/apache/ranger/pull/1081

   ## Summary
   
   - Remove logging of the full serialized JWT bearer token 
(`header.payload.signature`) when `RangerJwtAuthHandler` validation fails 
(CWE-532).
   - Log only non-sensitive metadata plus a SHA-256 hash for correlation: 
`subject`, `audience`, `issuer`, `keyId`, `jwtId`, `tokenHash`.
   - Add null-safety in `validateAudiences()` when a token has no `aud` claim 
but audiences are configured.
   - Add unit tests for safe logging and missing-audience handling.
   
   **JIRA:** https://issues.apache.org/jira/browse/RANGER-5693
   
   ## Problem
   
   On validation failure, `RangerJwtAuthHandler.authenticate()` logged:
   
   ```
   RangerJwtAuthHandler.authenticate(): Validation failed for JWT token: [<full 
serialized JWT>]
   ```
   
   `validateToken()` checks claims in order: **expiration → signature → 
audience → issuer**. A cryptographically valid, unexpired token rejected only 
for **audience mismatch** still hit this WARN path. The full bearer credential 
in logs could be replayed against another Ranger JWT consumer that trusts the 
same signing material and accepts the token's audience.
   
   Reported via ASF Security (Andrew Rukin, Arenadata). Verified on Ranger 
2.8.0; same pattern existed on 2.8, 2.9, and master.
   
   ## Fix
   
   **Before:**
   
   ```java
   LOG.warn("... Validation failed for JWT token: [{}] ", jwtToken.serialize());
   ```
   
   **After:**
   
   ```java
   LOG.warn("JWT validation failed ({})", safeJwtLogContext(jwtToken, 
serializedJWT));
   ```
   
   `safeJwtLogContext()` emits diagnostic fields only, for example:
   
   ```
   JWT validation failed (subject=f015_replay_user, audience=service-a, 
issuer=test-issuer, keyId=kid-abc, jwtId=jti-123, tokenHash=<sha256-hex>)
   ```
   
   The raw bearer string is never written to operational logs. `tokenHash` is a 
one-way SHA-256 digest used only for log correlation.
   
   ### Null-safety
   
   - `validateAudiences()`: guard `tokenAudienceList != null` before iterating 
(avoids NPE when `aud` claim is absent).
   - `safeJwtLogContext()`: guard `jwtToken.getHeader()` before reading 
`keyId`; use `StringUtils.join()` for audience list (JDK 8 compatible, 
tolerates null list entries).
   
   ## Files changed (2)
   
   | File | Change |
   |------|--------|
   | `ranger-authn/.../RangerJwtAuthHandler.java` | Safe logging, 
`safeJwtLogContext()`, `sha256Hex()`, audience null guard |
   | `ranger-authn/.../TestRangerJwtAuthHandler.java` | Unit tests for safe 
context and missing audience |
   
   ## Test plan
   
   ### Unit tests (automated)
   
   ```bash
   mvn -pl ranger-authn test -Dtest=TestRangerJwtAuthHandler
   ```
   
   **Result:** 6/6 tests pass.
   
   | Test | Verifies |
   |------|----------|
   | `validateIssuerTrue_whenIssuerNotConfigured` | Issuer validation baseline |
   | `validateIssuerTrue_whenIssuerMatches` | Matching issuer accepted |
   | `validateIssuerFalse_whenIssuerDoesNotMatch` | Mismatched issuer rejected |
   | `validateIssuerFalse_whenJwtClaimsCannotBeParsed` | Malformed claims 
handled |
   | `validateAudiencesFalse_whenTokenAudienceMissingAndAudiencesConfigured` | 
No NPE when `aud` missing; returns false |
   | `safeJwtLogContext_includesMetadataWithoutRawToken` | Metadata present; 
raw token/header/payload/signature absent |
   
   ### Static analysis
   
   ```bash
   mvn -pl ranger-authn checkstyle:check pmd:check
   ```
   
   | Check | Result |
   |-------|--------|
   | **PMD** | PASS — no violations in changed files |
   | **Checkstyle** | `TestRangerJwtAuthHandler.java`: 0 violations. 
`RangerJwtAuthHandler.java`: only pre-existing module violations plus 
`LineLength` on new single-line statements (intentional, no line-wrapping) |
   
   ### Reporter-equivalent manual E2E (recommended before release)
   
   Mirrors the private security report verification:
   
   1. Generate RS256 key pair and PEM certificate for `jwt.public-key`.
   2. Create JWT: `sub=f015_replay_user`, `aud=service-a`, future `exp`, valid 
RS256 signature.
   3. **Handler A** (`jwt.audiences=service-b`): call 
`RangerDefaultJwtAuthHandler.authenticate("Bearer <token>")` → expect `null`.
   4. Inspect logs → expect `JWT validation failed (subject=..., 
audience=service-a, keyId=..., tokenHash=...)` and **no** full serialized JWT.
   5. **Handler B** (`jwt.audiences=service-a`): same token → expect 
`f015_replay_user` (proves token was live; only logging changed).
   
   ### Live HTTP E2E (optional)
   
   Deploy patched `ranger-authn` with PDP or Admin JWT auth enabled:
   
   ```bash
   # Wrong audience — expect 401, no raw token in logs
   curl -H "Authorization: Bearer $TOKEN" http://localhost:6500/policy/evaluate
   grep -F "$TOKEN" pdp.log && echo FAIL || echo PASS
   
   # Correct audience — expect authenticated response
   # (reconfigure jwt.audiences=service-a or use second instance)
   ```
   
   ### Regression scope
   
   - `RangerDefaultJwtAuthHandler` (Admin `RangerJwtAuthFilter`, PDP 
`JwtAuthNHandler`, audit paths) all delegate to the fixed 
`authenticate(String)` path.
   - Other JWT filters (`RangerSSOAuthenticationFilter`, `AuditJwtAuthFilter`) 
already log failure reasons without serializing tokens; unchanged.
   
   ## Security / disclosure
   
   Private security report (CWE-532). Coordinate advisory/CVE and backports per 
PMC process. Credit reporter **Andrew Rukin (Arenadata)** in advisory if 
accepted.
   


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