33import io .apimatic .core .security .DigestCodec ;
44import io .apimatic .core .security .DigestCodecFactory ;
55import io .apimatic .core .security .HmacSignatureVerifier ;
6+ import io .apimatic .core .utilities .CoreHelper ;
67import io .apimatic .coreinterfaces .http .HttpHeaders ;
8+ import io .apimatic .coreinterfaces .http .Method ;
79import io .apimatic .coreinterfaces .http .request .Request ;
810import io .apimatic .coreinterfaces .security .VerificationResult ;
911import org .junit .Assert ;
1416import org .mockito .Mockito ;
1517import org .mockito .junit .MockitoJUnitRunner ;
1618
19+ import java .nio .charset .StandardCharsets ;
1720import java .util .HashMap ;
1821import java .util .Map ;
22+ import java .util .function .Function ;
23+
24+ import static org .junit .Assert .assertNull ;
1925
2026@ RunWith (MockitoJUnitRunner .class )
2127public class HmacSignatureVerifierTest {
@@ -32,6 +38,7 @@ private Request mockRequest(Map<String, String> headers, String body) {
3238 HttpHeaders httpHeaders = Mockito .mock (HttpHeaders .class );
3339 Mockito .when (httpHeaders .asSimpleMap ()).thenReturn (headers );
3440 Mockito .when (request .getHeaders ()).thenReturn (httpHeaders );
41+ Mockito .when (request .getHttpMethod ()).thenReturn (Method .POST );
3542 Mockito .when (request .getBody ()).thenReturn (body );
3643 return request ;
3744 }
@@ -293,6 +300,113 @@ public void testVerifyAsync_WrongSignatureValueForTemplate() throws Exception {
293300 Assert .assertFalse (result .isSuccess ());
294301 Assert .assertEquals ("Malformed signature header '" + SIGNATURE_HEADER + "' value." , result .getErrors ().get (0 ));
295302 }
303+
304+ @ Test
305+ public void testVerifyAsync_SuccessRequestSignatureTemplateResolver_Body () throws Exception {
306+ DigestCodec codec = DigestCodecFactory .base64 ();
307+ Map <String , String > headers = new HashMap <>();
308+ String signature = computeSignature (SECRET_KEY ,
309+ "session=abc123:2025-09-17T12:34:56Z:POST:payment:{\" id\" :123,\" type\" :\" payment\" ,\" amount\" :100.5}" ,
310+ HmacSignatureVerifier .DEFAULT_ALGORITHM , codec );
311+ headers .put (SIGNATURE_HEADER , signature );
312+ headers .put ("Cookie" , "session=abc123" );
313+ headers .put ("X-Timestamp" , "2025-09-17T12:34:56Z" );
314+ Request req = mockRequest (headers , "{\" id\" :123,\" type\" :\" payment\" ,\" amount\" :100.5}" );
315+
316+ Function <Request , byte []> requestSignatureTemplateResolver =
317+ (request ) -> {
318+ if (request == null ) {
319+ throw new IllegalArgumentException ("request cannot be null" );
320+ }
321+
322+ // {request.Headers.Cookie}:{request.Headers.X-Timestamp}:{request.Method}:{$request.body#/type}:{$request.body}
323+ String cookie = request .getHeaders ().asSimpleMap ().get ("Cookie" );
324+ String timestamp = request .getHeaders ().asSimpleMap ().get ("X-Timestamp" );
325+ String resolvedBody = CoreHelper .resolveRequestPointer ("$request.body#/type" , request );
326+
327+ return String .join (":" ,
328+ cookie ,
329+ timestamp ,
330+ request .getHttpMethod ().toString (),
331+ resolvedBody == null ? "" : resolvedBody ,
332+ request .getBody ().toString ()
333+ ).getBytes (StandardCharsets .UTF_8 );
334+ };
335+
336+
337+ HmacSignatureVerifier verifier = new HmacSignatureVerifier (
338+ SECRET_KEY ,
339+ SIGNATURE_HEADER ,
340+ codec ,
341+ requestSignatureTemplateResolver ,
342+ HmacSignatureVerifier .DEFAULT_ALGORITHM ,
343+ HmacSignatureVerifier .SIGNATURE_VALUE_TEMPLATE );
344+
345+ VerificationResult result = verifier .verifyAsync (req ).get ();
346+ Assert .assertTrue (result .isSuccess ());
347+ }
348+
349+ @ Test
350+ public void testVerifyAsync_SuccessRequestSignatureTemplateResolver_Headers () throws Exception {
351+ DigestCodec codec = DigestCodecFactory .base64 ();
352+ Map <String , String > headers = new HashMap <>();
353+ String signature = computeSignature (SECRET_KEY ,
354+ "session=abc123:2025-09-17T12:34:56Z:POST:x-signature-header-value:{\" id\" :123,\" type\" :\" payment\" ,\" amount\" :100.5}" ,
355+ HmacSignatureVerifier .DEFAULT_ALGORITHM , codec );
356+ headers .put (SIGNATURE_HEADER , signature );
357+ headers .put ("Cookie" , "session=abc123" );
358+ headers .put ("x-signature" , "x-signature-header-value" );
359+ headers .put ("X-Timestamp" , "2025-09-17T12:34:56Z" );
360+ Request req = mockRequest (headers , "{\" id\" :123,\" type\" :\" payment\" ,\" amount\" :100.5}" );
361+
362+ Function <Request , byte []> requestSignatureTemplateResolver =
363+ (request ) -> {
364+ if (request == null ) {
365+ throw new IllegalArgumentException ("request cannot be null" );
366+ }
367+
368+ // {request.Headers.Cookie}:{request.Headers.X-Timestamp}:{request.Method}:{$request.headers#/x-signature}:{$request.body}
369+ String cookie = request .getHeaders ().asSimpleMap ().get ("Cookie" );
370+ String timestamp = request .getHeaders ().asSimpleMap ().get ("X-Timestamp" );
371+ String resolvedBody = CoreHelper .resolveRequestPointer ("$request.headers#/x-signature" , request );
372+
373+ return String .join (":" ,
374+ cookie ,
375+ timestamp ,
376+ request .getHttpMethod ().toString (),
377+ resolvedBody == null ? "" : resolvedBody ,
378+ request .getBody ().toString ()
379+ ).getBytes (StandardCharsets .UTF_8 );
380+ };
381+
382+
383+ HmacSignatureVerifier verifier = new HmacSignatureVerifier (
384+ SECRET_KEY ,
385+ SIGNATURE_HEADER ,
386+ codec ,
387+ requestSignatureTemplateResolver ,
388+ HmacSignatureVerifier .DEFAULT_ALGORITHM ,
389+ HmacSignatureVerifier .SIGNATURE_VALUE_TEMPLATE );
390+
391+ VerificationResult result = verifier .verifyAsync (req ).get ();
392+ Assert .assertTrue (result .isSuccess ());
393+ }
394+
395+ @ Test
396+ public void testResolveRequestPointer_NullPointer () {
397+ Map <String , String > headers = new HashMap <>();
398+ Request request = mockRequest (headers , BODY );
399+ String value = CoreHelper .resolveRequestPointer (null , request );
400+ assertNull (value );
401+ }
402+
403+ @ Test
404+ public void testResolveRequestPointer_InvalidPointer () {
405+ Map <String , String > headers = new HashMap <>();
406+ Request request = mockRequest (headers , BODY );
407+ String value = CoreHelper .resolveRequestPointer ("$request.method#" , request );
408+ assertNull (value );
409+ }
296410}
297411
298412
0 commit comments