@@ -253,70 +253,117 @@ func TestValidateAudienceForService(t *testing.T) {
253253 issuer := "https://mcp.company.com"
254254
255255 tests := []struct {
256- name string
257- requestPath string
258- tokenAudience []string
259- wantErr bool
260- errContains string
256+ name string
257+ requestPath string
258+ tokenAudience []string
259+ acceptIssuerAudience bool
260+ wantErr bool
261+ errContains string
261262 }{
262263 {
263- name : "matching audience" ,
264- requestPath : "/postgres/sse" ,
265- tokenAudience : []string {"https://mcp.company.com/postgres" },
266- wantErr : false ,
264+ name : "matching audience" ,
265+ requestPath : "/postgres/sse" ,
266+ tokenAudience : []string {"https://mcp.company.com/postgres" },
267+ acceptIssuerAudience : false ,
268+ wantErr : false ,
267269 },
268270 {
269- name : "matching audience with message endpoint" ,
270- requestPath : "/postgres/message" ,
271- tokenAudience : []string {"https://mcp.company.com/postgres" },
272- wantErr : false ,
271+ name : "matching audience with message endpoint" ,
272+ requestPath : "/postgres/message" ,
273+ tokenAudience : []string {"https://mcp.company.com/postgres" },
274+ acceptIssuerAudience : false ,
275+ wantErr : false ,
273276 },
274277 {
275- name : "matching audience in multi-audience token" ,
276- requestPath : "/postgres/sse" ,
277- tokenAudience : []string {"https://mcp.company.com/linear" , "https://mcp.company.com/postgres" },
278- wantErr : false ,
278+ name : "matching audience in multi-audience token" ,
279+ requestPath : "/postgres/sse" ,
280+ tokenAudience : []string {"https://mcp.company.com/linear" , "https://mcp.company.com/postgres" },
281+ acceptIssuerAudience : false ,
282+ wantErr : false ,
279283 },
280284 {
281- name : "wrong audience" ,
282- requestPath : "/postgres/sse" ,
283- tokenAudience : []string {"https://mcp.company.com/linear" },
284- wantErr : true ,
285- errContains : "does not include required resource" ,
285+ name : "wrong audience" ,
286+ requestPath : "/postgres/sse" ,
287+ tokenAudience : []string {"https://mcp.company.com/linear" },
288+ acceptIssuerAudience : false ,
289+ wantErr : true ,
290+ errContains : "does not include required resource" ,
286291 },
287292 {
288- name : "empty audience" ,
289- requestPath : "/postgres/sse" ,
290- tokenAudience : []string {},
291- wantErr : true ,
292- errContains : "does not include required resource" ,
293+ name : "empty audience" ,
294+ requestPath : "/postgres/sse" ,
295+ tokenAudience : []string {},
296+ acceptIssuerAudience : false ,
297+ wantErr : true ,
298+ errContains : "does not include required resource" ,
293299 },
294300 {
295- name : "nil audience" ,
296- requestPath : "/postgres/sse" ,
297- tokenAudience : nil ,
298- wantErr : true ,
299- errContains : "does not include required resource" ,
301+ name : "nil audience" ,
302+ requestPath : "/postgres/sse" ,
303+ tokenAudience : nil ,
304+ acceptIssuerAudience : false ,
305+ wantErr : true ,
306+ errContains : "does not include required resource" ,
300307 },
301308 {
302- name : "malformed request path" ,
303- requestPath : "/" ,
304- tokenAudience : []string {"https://mcp.company.com/postgres" },
305- wantErr : true ,
306- errContains : "does not contain service name" ,
309+ name : "malformed request path" ,
310+ requestPath : "/" ,
311+ tokenAudience : []string {"https://mcp.company.com/postgres" },
312+ acceptIssuerAudience : false ,
313+ wantErr : true ,
314+ errContains : "does not contain service name" ,
307315 },
308316 {
309- name : "empty request path" ,
310- requestPath : "" ,
311- tokenAudience : []string {"https://mcp.company.com/postgres" },
312- wantErr : true ,
313- errContains : "does not contain service name" ,
317+ name : "empty request path" ,
318+ requestPath : "" ,
319+ tokenAudience : []string {"https://mcp.company.com/postgres" },
320+ acceptIssuerAudience : false ,
321+ wantErr : true ,
322+ errContains : "does not contain service name" ,
323+ },
324+ // Tests for acceptIssuerAudience workaround
325+ {
326+ name : "issuer audience accepted when enabled" ,
327+ requestPath : "/postgres/sse" ,
328+ tokenAudience : []string {"https://mcp.company.com" },
329+ acceptIssuerAudience : true ,
330+ wantErr : false ,
331+ },
332+ {
333+ name : "issuer audience rejected when disabled" ,
334+ requestPath : "/postgres/sse" ,
335+ tokenAudience : []string {"https://mcp.company.com" },
336+ acceptIssuerAudience : false ,
337+ wantErr : true ,
338+ errContains : "does not include required resource" ,
339+ },
340+ {
341+ name : "per-service audience still works when issuer fallback enabled" ,
342+ requestPath : "/postgres/sse" ,
343+ tokenAudience : []string {"https://mcp.company.com/postgres" },
344+ acceptIssuerAudience : true ,
345+ wantErr : false ,
346+ },
347+ {
348+ name : "issuer audience works for any service when enabled" ,
349+ requestPath : "/linear/sse" ,
350+ tokenAudience : []string {"https://mcp.company.com" },
351+ acceptIssuerAudience : true ,
352+ wantErr : false ,
353+ },
354+ {
355+ name : "wrong issuer still rejected even when fallback enabled" ,
356+ requestPath : "/postgres/sse" ,
357+ tokenAudience : []string {"https://other.company.com" },
358+ acceptIssuerAudience : true ,
359+ wantErr : true ,
360+ errContains : "does not include required resource" ,
314361 },
315362 }
316363
317364 for _ , tt := range tests {
318365 t .Run (tt .name , func (t * testing.T ) {
319- err := ValidateAudienceForService (tt .requestPath , tt .tokenAudience , issuer )
366+ err := ValidateAudienceForService (tt .requestPath , tt .tokenAudience , issuer , tt . acceptIssuerAudience )
320367 if (err != nil ) != tt .wantErr {
321368 t .Errorf ("ValidateAudienceForService() error = %v, wantErr %v" , err , tt .wantErr )
322369 return
0 commit comments