diff --git a/.gitignore b/.gitignore index 80bed650..c0e81a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store bin +.idea/ diff --git a/claims.go b/claims.go index f0228f02..62489066 100644 --- a/claims.go +++ b/claims.go @@ -16,7 +16,7 @@ type Claims interface { // https://tools.ietf.org/html/rfc7519#section-4.1 // See examples for how to use this with your own claim types type StandardClaims struct { - Audience string `json:"aud,omitempty"` + Audience []string `json:"aud,omitempty"` ExpiresAt int64 `json:"exp,omitempty"` Id string `json:"jti,omitempty"` IssuedAt int64 `json:"iat,omitempty"` @@ -90,15 +90,17 @@ func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool { // ----- helpers -func verifyAud(aud string, cmp string, required bool) bool { - if aud == "" { +func verifyAud(aud []string, cmp string, required bool) bool { + if len(aud) == 0 { return !required } - if subtle.ConstantTimeCompare([]byte(aud), []byte(cmp)) != 0 { - return true - } else { - return false + + for _, a := range aud { + if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 { + return true + } } + return false } func verifyExp(exp int64, now int64, required bool) bool { diff --git a/map_claims.go b/map_claims.go index 291213c4..e1c80656 100644 --- a/map_claims.go +++ b/map_claims.go @@ -13,7 +13,13 @@ type MapClaims map[string]interface{} // Compares the aud claim against cmp. // If required is false, this method will return true if the value matches or is unset func (m MapClaims) VerifyAudience(cmp string, req bool) bool { - aud, _ := m["aud"].(string) + aud, _ := m["aud"].([]string) + + // special case where aud is a single string not list of strings + if aud == nil { + strAud, _ := m["aud"].(string) + aud = append(aud, strAud) + } return verifyAud(aud, cmp, req) } diff --git a/map_claims_test.go b/map_claims_test.go new file mode 100644 index 00000000..7fc1d837 --- /dev/null +++ b/map_claims_test.go @@ -0,0 +1,72 @@ +package jwt + +import "testing" + +func Test_mapClaims_list_aud(t *testing.T){ + mapClaims := MapClaims{ + "aud": []string{"foo"}, + } + want := true + got := mapClaims.VerifyAudience("foo", true) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} +func Test_mapClaims_string_aud(t *testing.T){ + mapClaims := MapClaims{ + "aud": "foo", + } + want := true + got := mapClaims.VerifyAudience("foo", true) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} + +func Test_mapClaims_list_aud_no_match(t *testing.T){ + mapClaims := MapClaims{ + "aud": []string{"bar"}, + } + want := false + got := mapClaims.VerifyAudience("foo", true) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} +func Test_mapClaims_string_aud_fail(t *testing.T){ + mapClaims := MapClaims{ + "aud": "bar", + } + want := false + got := mapClaims.VerifyAudience("foo", true) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} + +func Test_mapClaims_string_aud_no_claim(t *testing.T){ + mapClaims := MapClaims{ + } + want := false + got := mapClaims.VerifyAudience("foo", true) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} + +func Test_mapClaims_string_aud_no_claim_not_required(t *testing.T){ + mapClaims := MapClaims{ + //"aud": "", + } + want := false + got := mapClaims.VerifyAudience("foo", false) + + if want != got { + t.Fatalf("Failed to verify claims, wanted: %v got %v", want, got) + } +} \ No newline at end of file