@@ -558,3 +558,295 @@ func TestRateLimiting_Disabled(t *testing.T) {
558558 assert .Equal (t , 200 , w .Code , "Request %d should succeed when rate limiting disabled" , i + 1 )
559559 }
560560}
561+
562+ // TestParseX5CFromArray tests the parseX5CFromArray function
563+ func TestParseX5CFromArray (t * testing.T ) {
564+ tests := []struct {
565+ name string
566+ key []interface {}
567+ wantErr bool
568+ errMsg string
569+ }{
570+ {
571+ name : "empty key array" ,
572+ key : []interface {}{},
573+ wantErr : true ,
574+ errMsg : "resource.key is empty" ,
575+ },
576+ {
577+ name : "nil key array" ,
578+ key : nil ,
579+ wantErr : true ,
580+ errMsg : "resource.key is empty" ,
581+ },
582+ {
583+ name : "non-string element" ,
584+ key : []interface {}{123 },
585+ wantErr : true ,
586+ errMsg : "resource.key[0] is not a string" ,
587+ },
588+ {
589+ name : "invalid base64" ,
590+ key : []interface {}{"not-valid-base64!!!" },
591+ wantErr : true ,
592+ errMsg : "failed to base64 decode" ,
593+ },
594+ {
595+ name : "invalid certificate" ,
596+ key : []interface {}{base64 .StdEncoding .EncodeToString ([]byte ("not a certificate" ))},
597+ wantErr : true ,
598+ errMsg : "failed to parse certificate" ,
599+ },
600+ {
601+ name : "valid certificate" ,
602+ key : []interface {}{testCertBase64 },
603+ wantErr : false ,
604+ },
605+ }
606+
607+ for _ , tt := range tests {
608+ t .Run (tt .name , func (t * testing.T ) {
609+ certs , err := parseX5CFromArray (tt .key )
610+ if tt .wantErr {
611+ assert .Error (t , err )
612+ if tt .errMsg != "" {
613+ assert .Contains (t , err .Error (), tt .errMsg )
614+ }
615+ } else {
616+ assert .NoError (t , err )
617+ assert .Len (t , certs , 1 )
618+ assert .Equal (t , "Test Cert" , certs [0 ].Subject .CommonName )
619+ }
620+ })
621+ }
622+ }
623+
624+ // TestParseX5CFromJWK tests the parseX5CFromJWK function
625+ func TestParseX5CFromJWK (t * testing.T ) {
626+ tests := []struct {
627+ name string
628+ key []interface {}
629+ wantErr bool
630+ errMsg string
631+ }{
632+ {
633+ name : "empty key array" ,
634+ key : []interface {}{},
635+ wantErr : true ,
636+ errMsg : "resource.key is empty" ,
637+ },
638+ {
639+ name : "nil key array" ,
640+ key : nil ,
641+ wantErr : true ,
642+ errMsg : "resource.key is empty" ,
643+ },
644+ {
645+ name : "non-map element" ,
646+ key : []interface {}{"not a map" },
647+ wantErr : true ,
648+ errMsg : "resource.key[0] is not a JWK object (map)" ,
649+ },
650+ {
651+ name : "no x5c claim" ,
652+ key : []interface {}{
653+ map [string ]interface {}{
654+ "kty" : "RSA" ,
655+ "n" : "somevalue" ,
656+ },
657+ },
658+ wantErr : true ,
659+ errMsg : "JWK does not contain x5c claim" ,
660+ },
661+ {
662+ name : "x5c is not array" ,
663+ key : []interface {}{
664+ map [string ]interface {}{
665+ "kty" : "RSA" ,
666+ "x5c" : "not an array" ,
667+ },
668+ },
669+ wantErr : true ,
670+ errMsg : "JWK x5c claim is not an array" ,
671+ },
672+ {
673+ name : "x5c element is not string" ,
674+ key : []interface {}{
675+ map [string ]interface {}{
676+ "kty" : "RSA" ,
677+ "x5c" : []interface {}{123 },
678+ },
679+ },
680+ wantErr : true ,
681+ errMsg : "JWK x5c[0] is not a string" ,
682+ },
683+ {
684+ name : "invalid base64 in x5c" ,
685+ key : []interface {}{
686+ map [string ]interface {}{
687+ "kty" : "RSA" ,
688+ "x5c" : []interface {}{"not-valid-base64!!!" },
689+ },
690+ },
691+ wantErr : true ,
692+ errMsg : "failed to base64 decode JWK x5c[0]" ,
693+ },
694+ {
695+ name : "invalid certificate in x5c" ,
696+ key : []interface {}{
697+ map [string ]interface {}{
698+ "kty" : "RSA" ,
699+ "x5c" : []interface {}{base64 .StdEncoding .EncodeToString ([]byte ("not a cert" ))},
700+ },
701+ },
702+ wantErr : true ,
703+ errMsg : "failed to parse certificate from JWK x5c[0]" ,
704+ },
705+ {
706+ name : "valid JWK with x5c" ,
707+ key : []interface {}{
708+ map [string ]interface {}{
709+ "kty" : "RSA" ,
710+ "x5c" : []interface {}{testCertBase64 },
711+ },
712+ },
713+ wantErr : false ,
714+ },
715+ }
716+
717+ for _ , tt := range tests {
718+ t .Run (tt .name , func (t * testing.T ) {
719+ certs , err := parseX5CFromJWK (tt .key )
720+ if tt .wantErr {
721+ assert .Error (t , err )
722+ if tt .errMsg != "" {
723+ assert .Contains (t , err .Error (), tt .errMsg )
724+ }
725+ } else {
726+ assert .NoError (t , err )
727+ assert .Len (t , certs , 1 )
728+ assert .Equal (t , "Test Cert" , certs [0 ].Subject .CommonName )
729+ }
730+ })
731+ }
732+ }
733+
734+ // TestServerContext_WithLogger tests the WithLogger method
735+ func TestServerContext_WithLogger (t * testing.T ) {
736+ logger := logging .NewLogger (logging .DebugLevel )
737+ serverCtx := NewServerContext (logger )
738+
739+ // Apply WithLogger method to create a new context with a different logger
740+ newLogger := logging .NewLogger (logging .InfoLevel )
741+ newCtx := serverCtx .WithLogger (newLogger )
742+
743+ assert .NotNil (t , newCtx .Logger )
744+ assert .NotSame (t , serverCtx , newCtx , "WithLogger should return a new ServerContext" )
745+ }
746+
747+ // TestServerContext_WithLogger_NilLogger tests that WithLogger handles nil logger
748+ func TestServerContext_WithLogger_NilLogger (t * testing.T ) {
749+ logger := logging .NewLogger (logging .DebugLevel )
750+ serverCtx := NewServerContext (logger )
751+
752+ // Pass nil logger - should use default
753+ newCtx := serverCtx .WithLogger (nil )
754+
755+ assert .NotNil (t , newCtx .Logger , "WithLogger(nil) should use default logger" )
756+ }
757+
758+ // TestNewServerContext_DefaultValues tests NewServerContext default values
759+ func TestNewServerContext_DefaultValues (t * testing.T ) {
760+ logger := logging .NewLogger (logging .InfoLevel )
761+ serverCtx := NewServerContext (logger )
762+
763+ assert .NotNil (t , serverCtx .Logger )
764+ assert .NotNil (t , serverCtx .LastProcessed )
765+ }
766+
767+ // TestLegacyEvaluate tests the legacy evaluation path (when RegistryManager is nil)
768+ func TestLegacyEvaluate (t * testing.T ) {
769+ gin .SetMode (gin .TestMode )
770+
771+ logger := logging .NewLogger (logging .InfoLevel )
772+ serverCtx := NewServerContext (logger )
773+ // Note: RegistryManager is nil, so legacyEvaluate will be called
774+ serverCtx .RegistryManager = nil
775+
776+ router := gin .New ()
777+ RegisterAPIRoutes (router , serverCtx )
778+
779+ // Test the evaluation endpoint without RegistryManager - should trigger legacy path
780+ body := `{
781+ "subject": {
782+ "type": "key",
783+ "id": "did:example:test"
784+ },
785+ "resource": {
786+ "type": "x5c",
787+ "id": "did:example:test",
788+ "key": ["dGVzdA=="]
789+ }
790+ }`
791+
792+ req := httptest .NewRequest ("POST" , "/evaluation" , strings .NewReader (body ))
793+ req .Header .Set ("Content-Type" , "application/json" )
794+ w := httptest .NewRecorder ()
795+ router .ServeHTTP (w , req )
796+
797+ // Legacy endpoint should return 200 with decision=false and error message
798+ assert .Equal (t , 200 , w .Code )
799+
800+ var resp authzen.EvaluationResponse
801+ err := json .Unmarshal (w .Body .Bytes (), & resp )
802+ assert .NoError (t , err )
803+ assert .False (t , resp .Decision , "Legacy mode should return false decision" )
804+ assert .NotNil (t , resp .Context )
805+ assert .NotNil (t , resp .Context .Reason )
806+ assert .Contains (t , resp .Context .Reason ["error" ], "legacy mode not supported" )
807+ }
808+
809+ // TestTSLsHandler_EmptyRegistryManager tests TSLsHandler when no ETSI registries exist
810+ func TestTSLsHandler_EmptyRegistryManager (t * testing.T ) {
811+ gin .SetMode (gin .TestMode )
812+
813+ logger := logging .NewLogger (logging .InfoLevel )
814+ serverCtx := NewServerContext (logger )
815+
816+ // Create registry manager with non-ETSI registry
817+ mgr := registry .NewRegistryManager (registry .FirstMatch , 10 * time .Second )
818+ mockReg := & mockTrustRegistry {certPool : x509 .NewCertPool ()}
819+ mgr .Register (mockReg )
820+ serverCtx .RegistryManager = mgr
821+
822+ router := gin .New ()
823+ RegisterAPIRoutes (router , serverCtx )
824+
825+ req := httptest .NewRequest ("GET" , "/tsls" , nil )
826+ w := httptest .NewRecorder ()
827+ router .ServeHTTP (w , req )
828+
829+ assert .Equal (t , 200 , w .Code )
830+ // The response contains registry information
831+ assert .Contains (t , w .Body .String (), "registries" )
832+ }
833+
834+ // TestTSLsHandler_NilRegistryManager tests TSLsHandler when RegistryManager is nil
835+ func TestTSLsHandler_NilRegistryManager (t * testing.T ) {
836+ gin .SetMode (gin .TestMode )
837+
838+ logger := logging .NewLogger (logging .InfoLevel )
839+ serverCtx := NewServerContext (logger )
840+ serverCtx .RegistryManager = nil
841+
842+ router := gin .New ()
843+ RegisterAPIRoutes (router , serverCtx )
844+
845+ req := httptest .NewRequest ("GET" , "/tsls" , nil )
846+ w := httptest .NewRecorder ()
847+ router .ServeHTTP (w , req )
848+
849+ // When RegistryManager is nil, it returns 200 with empty registries
850+ assert .Equal (t , 200 , w .Code )
851+ assert .Contains (t , w .Body .String (), "count" )
852+ }
0 commit comments