istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/common/jwt/jwt_token_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package jwt 16 17 import ( 18 "encoding/json" 19 "os" 20 "reflect" 21 "testing" 22 23 "github.com/lestrrat-go/jwx/jwa" 24 "github.com/lestrrat-go/jwx/jwk" 25 "github.com/lestrrat-go/jwx/jws" 26 ) 27 28 func getKey(jwksFile string, t *testing.T) any { 29 t.Helper() 30 31 data, err := os.ReadFile(jwksFile) 32 if err != nil { 33 t.Fatalf("failed to read jwks: %s", err) 34 } 35 jwks, err := jwk.Parse(data) 36 if err != nil { 37 t.Fatalf("failed to parse jwks: %s", err) 38 } 39 var key any 40 k, _ := jwks.Get(0) 41 if err := k.Raw(&key); err != nil { 42 t.Fatalf("failed to materialize jwks: %s", err) 43 } 44 return key 45 } 46 47 func TestSampleJwtToken(t *testing.T) { 48 testCases := []struct { 49 name string 50 token string 51 wantClaims map[string]any 52 wantInvalid bool 53 }{ 54 { 55 name: "TokenIssuer1", 56 token: TokenIssuer1, 57 wantClaims: map[string]any{ 58 "groups": []any{"group-1"}, 59 "iss": "test-issuer-1@istio.io", 60 "sub": "sub-1", 61 "exp": 4715782722.0, 62 }, 63 }, 64 { 65 name: "TokenIssuer1NestedClaims1", 66 token: TokenIssuer1WithNestedClaims1, 67 wantClaims: map[string]any{ 68 "nested": map[string]any{ 69 "key1": []any{"valueA", "valueB"}, 70 "nested-2": map[string]any{ 71 "key1": []any{"valueA", "valueB"}, 72 }, 73 }, 74 "iss": "test-issuer-1@istio.io", 75 "sub": "sub-1", 76 "exp": 4757607896.0, 77 }, 78 }, 79 { 80 name: "TokenIssuer1NestedClaims2", 81 token: TokenIssuer1WithNestedClaims2, 82 wantClaims: map[string]any{ 83 "nested": map[string]any{ 84 "key2": "valueC", 85 "nested-2": map[string]any{ 86 "key2": "valueC", 87 }, 88 }, 89 "iss": "test-issuer-1@istio.io", 90 "sub": "sub-1", 91 "exp": 4757608018.0, 92 }, 93 }, 94 { 95 name: "TokenIssuer2", 96 token: TokenIssuer2, 97 wantClaims: map[string]any{ 98 "groups": []any{"group-2"}, 99 "iss": "test-issuer-2@istio.io", 100 "sub": "sub-2", 101 "exp": 4715782783.0, 102 }, 103 }, 104 { 105 name: "TokenExpired", 106 token: TokenExpired, 107 wantClaims: map[string]any{ 108 "groups": []any{"group-1"}, 109 "iss": "test-issuer-1@istio.io", 110 "sub": "sub-1", 111 "exp": 1562182856.0, 112 }, 113 }, 114 { 115 name: "TokenInvalid", 116 token: TokenInvalid, 117 wantInvalid: true, 118 }, 119 } 120 121 key := getKey("jwks.json", t) 122 for _, tc := range testCases { 123 token, err := jws.Verify([]byte(tc.token), jwa.RS256, key) 124 if tc.wantInvalid { 125 if err == nil { 126 t.Errorf("%s: got valid token but want invalid", tc.name) 127 } 128 continue 129 } 130 if err != nil { 131 t.Fatalf("%s: failed to parse token: %v", tc.name, err) 132 } 133 134 claims := map[string]any{} 135 err = json.Unmarshal(token, &claims) 136 if err != nil { 137 t.Fatalf("%s: failed to parse payload: %v", tc.name, err) 138 } 139 140 for k, v := range tc.wantClaims { 141 got, ok := claims[k] 142 if ok { 143 if !reflect.DeepEqual(got, v) { 144 t.Errorf("%s: claim %q got value %v but want %v", tc.name, k, got, v) 145 } 146 } else { 147 t.Errorf("%s: want claim %s but not found", tc.name, k) 148 } 149 } 150 } 151 }