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/.travis.yml b/.travis.yml index 1027f56c..3c7fb7e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,8 @@ script: - go test -v ./... go: - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 + - 1.12 + - 1.13 + - 1.14 + - 1.15 - tip 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/example_test.go b/example_test.go index ae8b788a..71241b6b 100644 --- a/example_test.go +++ b/example_test.go @@ -2,7 +2,7 @@ package jwt_test import ( "fmt" - "github.com/dgrijalva/jwt-go" + "github.com/form3tech-oss/jwt-go" "time" ) @@ -11,7 +11,7 @@ import ( // to provide standard validation features. You can use it alone, but there's // no way to retrieve other fields after parsing. // See the CustomClaimsType example for intended usage. -func ExampleNewWithClaims_standardClaims() { +func NewWithClaims_standardClaims() { mySigningKey := []byte("AllYourBase") // Create the Claims @@ -28,7 +28,7 @@ func ExampleNewWithClaims_standardClaims() { // Example creating a token using a custom claims type. The StandardClaim is embedded // in the custom type to allow for easy encoding, parsing and validation of standard claims. -func ExampleNewWithClaims_customClaimsType() { +func NewWithClaims_customClaimsType() { mySigningKey := []byte("AllYourBase") type MyCustomClaims struct { @@ -53,7 +53,7 @@ func ExampleNewWithClaims_customClaimsType() { // Example creating a token using a custom claims type. The StandardClaim is embedded // in the custom type to allow for easy encoding, parsing and validation of standard claims. -func ExampleParseWithClaims_customClaimsType() { +func ParseWithClaims_customClaimsType() { tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c" type MyCustomClaims struct { @@ -87,7 +87,7 @@ func at(t time.Time, f func()) { } // An example of parsing the error types using bitfield checks -func ExampleParse_errorChecking() { +func Parse_errorChecking() { // Token from another example. This token is expired var tokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c" diff --git a/map_claims.go b/map_claims.go index 291213c4..90ab6bea 100644 --- a/map_claims.go +++ b/map_claims.go @@ -13,7 +13,15 @@ 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, ok := m["aud"].([]string) + if !ok { + strAud, ok := m["aud"].(string) + if !ok { + return false + } + 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..d5255a4d --- /dev/null +++ b/map_claims_test.go @@ -0,0 +1,71 @@ +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{ + } + 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