@@ -650,7 +650,23 @@ void impersonatedCredentials_exchangeToken_masksSensitiveTokens()
650650
651651 assertEquals (3 , testAppender .events .size ());
652652
653- // Verify response payload has tokens masked
653+ // 1. Verify request log contains properly formatted payload (JsonHttpContent masking)
654+ ILoggingEvent requestLog = testAppender .events .get (0 );
655+ assertEquals (
656+ "Sending request to refresh access token" , requestLog .getMessage ());
657+ String requestPayload = null ;
658+ for (KeyValuePair kvp : requestLog .getKeyValuePairs ()) {
659+ if ("request.payload" .equals (kvp .key )) {
660+ requestPayload = (String ) kvp .value ;
661+ }
662+ }
663+ // When logged at DEBUG level, the request payload should be present and valid JSON
664+ // (the JsonHttpContent payload goes through parseGenericData for masking)
665+ if (requestPayload != null ) {
666+ assertTrue (isValidJson (requestPayload ), "Request payload should be valid JSON" );
667+ }
668+
669+ // 2. Verify response payload has tokens masked
654670 assertEquals ("Response payload for access token" , testAppender .events .get (2 ).getMessage ());
655671 boolean foundAccessToken = false ;
656672 for (KeyValuePair kvp : testAppender .events .get (2 ).getKeyValuePairs ()) {
@@ -669,4 +685,67 @@ void impersonatedCredentials_exchangeToken_masksSensitiveTokens()
669685 assertTrue (foundAccessToken , "Expected accessToken in response payload logs" );
670686 testAppender .stop ();
671687 }
688+
689+ @ Test
690+ void impersonatedCredentials_requestPayload_masksJsonHttpContentSensitiveKeys ()
691+ throws IOException , IllegalStateException {
692+ // Set DEBUG level to ensure request payloads are logged
693+ Logger logger = LoggerFactory .getLogger (ImpersonatedCredentials .class );
694+ ch .qos .logback .classic .Logger logbackLogger = (ch .qos .logback .classic .Logger ) logger ;
695+ ch .qos .logback .classic .Level previousLevel = logbackLogger .getLevel ();
696+ logbackLogger .setLevel (ch .qos .logback .classic .Level .DEBUG );
697+
698+ TestAppender testAppender = new TestAppender ();
699+ testAppender .start ();
700+ logbackLogger .addAppender (testAppender );
701+
702+ try {
703+ MockIAMCredentialsServiceTransportFactory mockTransportFactory =
704+ new MockIAMCredentialsServiceTransportFactory ();
705+ mockTransportFactory .getTransport ().setTargetPrincipal (IMPERSONATED_CLIENT_EMAIL );
706+ mockTransportFactory .getTransport ().setAccessToken (ACCESS_TOKEN );
707+ mockTransportFactory .getTransport ().setExpireTime (getDefaultExpireTime ());
708+ mockTransportFactory
709+ .getTransport ()
710+ .addStatusCodeAndMessage (HttpStatusCodes .STATUS_CODE_OK , "" );
711+ ImpersonatedCredentials targetCredentials =
712+ ImpersonatedCredentials .create (
713+ ImpersonatedCredentialsTest .getSourceCredentials (),
714+ IMPERSONATED_CLIENT_EMAIL ,
715+ null ,
716+ IMMUTABLE_SCOPES_LIST ,
717+ VALID_LIFETIME ,
718+ mockTransportFactory );
719+
720+ targetCredentials .refreshAccessToken ();
721+
722+ // Find the request log event
723+ ILoggingEvent requestLog = testAppender .events .get (0 );
724+ assertEquals ("Sending request to refresh access token" , requestLog .getMessage ());
725+
726+ // Extract request.payload
727+ String requestPayload = null ;
728+ for (KeyValuePair kvp : requestLog .getKeyValuePairs ()) {
729+ if ("request.payload" .equals (kvp .key )) {
730+ requestPayload = (String ) kvp .value ;
731+ }
732+ }
733+
734+ // At DEBUG level, request payload must be present
735+ assertNotNull (requestPayload , "Request payload should be logged at DEBUG level" );
736+ assertTrue (isValidJson (requestPayload ), "Request payload should be valid JSON" );
737+
738+ // The ImpersonatedCredentials request payload uses JsonHttpContent with fields:
739+ // delegates, scope, lifetime. None of these are in SENSITIVE_KEYS, so they should
740+ // appear as-is (not hashed). This validates that JsonHttpContent goes through
741+ // parseGenericData without breaking.
742+ assertFalse (
743+ requestPayload .contains ("\" delegates\" :null" ),
744+ "Payload should be properly serialized from JsonHttpContent" );
745+ } finally {
746+ logbackLogger .setLevel (previousLevel );
747+ testAppender .stop ();
748+ }
749+ }
672750}
751+
0 commit comments