@@ -805,3 +805,98 @@ func generateTestTLSArtifacts(t *testing.T, serverIP string) (caPEM, serverCertP
805805
806806 return caPEM , serverCertPEM , serverKeyPEM
807807}
808+
809+ func TestBearerJWTWildcardAudience (t * testing.T ) {
810+ mockOidcServer , _ := mockoidc .Run ()
811+ defer mockOidcServer .Shutdown () //nolint:errcheck
812+
813+ cfg := mockOidcServer .Config ()
814+
815+ pluginConfig , ok := New ().(* Config )
816+ assert .True (t , ok )
817+
818+ pluginConfig .Issuer = cfg .Issuer
819+ pluginConfig .ClientID = cfg .ClientID
820+ pluginConfig .ClientSecret = cfg .ClientSecret
821+ pluginConfig .RedirectURI = "http://localhost/cb"
822+ pluginConfig .Scopes = []string {"openid" , "profile" , "email" }
823+ // Explicitly configure the wildcard audience
824+ pluginConfig .BearerJWTAllowedAuds = []string {"*" }
825+ pluginConfig .ConsumerName = "oidcuser"
826+ pluginConfig .HeadersFromClaims = map [string ]string {
827+ "X-Oidc-Email" : "email" ,
828+ }
829+
830+ user := & mockoidc.MockUser {
831+ Subject : "1234567890" ,
832+ Email : "wildcard.user@example.com" ,
833+ EmailVerified : true ,
834+ }
835+ mockOidcServer .QueueUser (user )
836+
837+ provider , err := oidc .NewProvider (t .Context (), cfg .Issuer )
838+ require .NoError (t , err )
839+
840+ oauth2Config := oauth2.Config {
841+ ClientID : cfg .ClientID ,
842+ ClientSecret : cfg .ClientSecret ,
843+ RedirectURL : "http://localhost/cb" ,
844+ Endpoint : provider .Endpoint (),
845+ Scopes : pluginConfig .Scopes ,
846+ }
847+
848+ state := "state5678"
849+ pkceVerifier := "pkce5678"
850+
851+ authCodeURL := oauth2Config .AuthCodeURL (state ,
852+ oauth2 .S256ChallengeOption (pkceVerifier ))
853+
854+ httpClient := & http.Client {
855+ CheckRedirect : func (_ * http.Request , _ []* http.Request ) error { return http .ErrUseLastResponse },
856+ }
857+ resp , err := httpClient .Get (authCodeURL ) //nolint:noctx
858+ require .NoError (t , err )
859+
860+ defer resp .Body .Close ()
861+
862+ cbLocationHeader := resp .Header .Get ("Location" )
863+ parsedCBLoc , err := url .Parse (cbLocationHeader )
864+ require .NoError (t , err )
865+
866+ code := parsedCBLoc .Query ().Get ("code" )
867+
868+ token , err := oauth2Config .Exchange (t .Context (), code ,
869+ oauth2 .VerifierOption (pkceVerifier ))
870+ require .NoError (t , err )
871+
872+ rawIDToken , okToken := token .Extra ("id_token" ).(string )
873+ if ! okToken {
874+ t .Fatal ("no id_token in token response" )
875+ }
876+
877+ mockKong := NewMockKong (t )
878+
879+ ignoreLogCalls (mockKong )
880+ // Simulate a request with the Authorization header containing the JWT token
881+ mockKong .EXPECT ().RequestGetHeader ("authorization" ).Return ("Bearer " + rawIDToken , nil )
882+ mockKong .EXPECT ().CtxSetShared ("authenticated_groups" , []any {}).Return (nil )
883+ mockKong .EXPECT ().ServiceRequestSetHeader ("X-Oidc-Email" , "wildcard.user@example.com" ).Return (nil )
884+
885+ consumer := entities.Consumer {
886+ Id : "ffe30af5-d167-519a-8bdc-2fa89a3aa280" ,
887+ Username : "oidcuser" ,
888+ }
889+ mockKong .EXPECT ().ClientLoadConsumer ("oidcuser" , true ).Return (consumer , nil )
890+ mockKong .EXPECT ().ClientAuthenticate (& consumer , & client.AuthenticatedCredential {
891+ Id : "1234567890" ,
892+ ConsumerId : consumer .Id ,
893+ }).Return (nil )
894+ mockKong .EXPECT ().ServiceRequestSetHeader ("X-Consumer-Id" , consumer .Id ).Return (nil )
895+ mockKong .EXPECT ().ServiceRequestSetHeader ("X-Consumer-Username" , consumer .Username ).Return (nil )
896+ mockKong .EXPECT ().ServiceRequestSetHeader ("X-Credential-Identifier" , "1234567890" ).Return (nil )
897+ mockKong .EXPECT ().ServiceRequestClearHeader ("X-Anonymous-Consumer" ).Return (nil )
898+ mockKong .EXPECT ().ServiceRequestClearHeader ("X-Consumer-Custom-Id" ).Return (nil )
899+
900+ // Execution should not panic and should validate authentication despite strict audience missing
901+ pluginConfig .AccessWithInterface (mockKong )
902+ }
0 commit comments