1 package jws_test
2
3 import (
4 "context"
5 "reflect"
6 "testing"
7
8 "github.com/lestrrat-go/jwx/jwa"
9 "github.com/lestrrat-go/jwx/jwk"
10 "github.com/lestrrat-go/jwx/jws"
11 "github.com/stretchr/testify/assert"
12 )
13
14 var zeroval reflect.Value
15
16 func TestHeader(t *testing.T) {
17 publicKey := `{"kty":"RSA",
18 "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
19 "e":"AQAB",
20 "alg":"RS256",
21 "kid":"2011-04-29"}`
22 jwkPublicKey, err := jwk.ParseKey([]byte(publicKey))
23 if !assert.NoError(t, err, `jwk.ParseKey should succeed`) {
24 return
25 }
26 certChain := []string{
27 "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYwMTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3HKrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQmVZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpRSgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRTcDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEuMB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDSkdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IGOgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMUA2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTXRE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuHqDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWVU+4=",
28 "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoXDTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHUTBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMbVmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwgSW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlvbiBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEgMB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdvZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUdIAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4OWBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0VmsfSxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==",
29 "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd",
30 }
31
32 data := []struct {
33 Key string
34 Value interface{}
35 Expected interface{}
36 Method string
37 }{
38 {
39 Key: jws.AlgorithmKey,
40 Value: jwa.ES256,
41 Method: "Algorithm",
42 },
43 {
44 Key: jws.ContentTypeKey,
45 Value: "example",
46 Method: "ContentType",
47 },
48 {
49 Key: jws.CriticalKey,
50 Value: []string{"exp"},
51 Method: "Critical",
52 },
53 {
54 Key: jws.JWKKey,
55 Value: jwkPublicKey,
56 Method: "JWK",
57 },
58 {
59 Key: jws.JWKSetURLKey,
60 Value: "https://www.jwk.com/key.json",
61 Method: "JWKSetURL",
62 },
63 {
64 Key: jws.TypeKey,
65 Value: "JWT",
66 Method: "Type",
67 },
68 {
69 Key: jws.KeyIDKey,
70 Value: "e9bc097a-ce51-4036-9562-d2ade882db0d",
71 Method: "KeyID",
72 },
73 {
74 Key: jws.X509CertChainKey,
75 Value: certChain,
76 Method: "X509CertChain",
77 },
78 {
79 Key: jws.X509CertThumbprintKey,
80 Value: "QzY0NjREMjkyQTI4RTU2RkE4MUJBRDExNzY1MUY1N0I4QjFCODlBOQ",
81 Method: "X509CertThumbprint",
82 },
83 {
84 Key: jws.X509URLKey,
85 Value: "https://www.x509.com/key.pem",
86 Method: "X509URL",
87 },
88 {Key: "private", Value: "boofoo"},
89 }
90
91 base := jws.NewHeaders()
92
93 t.Run("Set values", func(t *testing.T) {
94
95 for _, tc := range data {
96 if !assert.NoError(t, base.Set(tc.Key, tc.Value), "Headers.Set should succeed") {
97 return
98 }
99 }
100 })
101
102 t.Run("Set/Get", func(t *testing.T) {
103 h := jws.NewHeaders()
104 ctx := context.Background()
105
106 for iter := base.Iterate(ctx); iter.Next(ctx); {
107 pair := iter.Pair()
108 if !assert.NoError(t, h.Set(pair.Key.(string), pair.Value), `h.Set should be successful`) {
109 return
110 }
111 }
112 for _, tc := range data {
113 var values []interface{}
114 viaGet, ok := h.Get(tc.Key)
115 if !assert.True(t, ok, "value for %s should exist", tc.Key) {
116 return
117 }
118 values = append(values, viaGet)
119
120 if method := tc.Method; method != "" {
121 m := reflect.ValueOf(h).MethodByName(method)
122 if !assert.NotEqual(t, m, zeroval, "method %s should be available", method) {
123 return
124 }
125
126 ret := m.Call(nil)
127 if !assert.Len(t, ret, 1, `should get exactly 1 value as return value`) {
128 return
129 }
130 values = append(values, ret[0].Interface())
131 }
132
133 expected := tc.Expected
134 if expected == nil {
135 expected = tc.Value
136 }
137 for i, got := range values {
138 if !assert.Equal(t, expected, got, "value %d should match", i) {
139 return
140 }
141 }
142 }
143 })
144 t.Run("PrivateParams", func(t *testing.T) {
145 h := base
146 pp, err := h.AsMap(context.Background())
147 if !assert.NoError(t, err, `h.AsMap should succeed`) {
148 return
149 }
150
151 v, ok := pp["private"]
152 if !assert.True(t, ok, "key 'private' should exists") {
153 return
154 }
155
156 if !assert.Equal(t, v, "boofoo", "value for 'private' should match") {
157 return
158 }
159 })
160
161 t.Run("Iterator", func(t *testing.T) {
162 expected := map[string]interface{}{}
163 for _, tc := range data {
164 v := tc.Value
165 if expected := tc.Expected; expected != nil {
166 v = expected
167 }
168 expected[tc.Key] = v
169 }
170
171 v := base
172 t.Run("Iterate", func(t *testing.T) {
173 seen := make(map[string]interface{})
174 for iter := v.Iterate(context.TODO()); iter.Next(context.TODO()); {
175 pair := iter.Pair()
176 seen[pair.Key.(string)] = pair.Value
177
178 getV, ok := v.Get(pair.Key.(string))
179 if !assert.True(t, ok, `v.Get should succeed for key %#v`, pair.Key) {
180 return
181 }
182 if !assert.Equal(t, pair.Value, getV, `pair.Value should match value from v.Get()`) {
183 return
184 }
185 }
186 if !assert.Equal(t, expected, seen, `values should match`) {
187 return
188 }
189 })
190 t.Run("Walk", func(t *testing.T) {
191 seen := make(map[string]interface{})
192 v.Walk(context.TODO(), jwk.HeaderVisitorFunc(func(key string, value interface{}) error {
193 seen[key] = value
194 return nil
195 }))
196 if !assert.Equal(t, expected, seen, `values should match`) {
197 return
198 }
199 })
200 t.Run("AsMap", func(t *testing.T) {
201 m, err := v.AsMap(context.TODO())
202 if !assert.NoError(t, err, `v.AsMap should succeed`) {
203 return
204 }
205 if !assert.Equal(t, expected, m, `values should match`) {
206 return
207 }
208 })
209 t.Run("Remove", func(t *testing.T) {
210 h := base
211 for iter := h.Iterate(context.TODO()); iter.Next(context.TODO()); {
212 pair := iter.Pair()
213 h.Remove(pair.Key.(string))
214 }
215
216 m, err := h.AsMap(context.TODO())
217 if !assert.NoError(t, err, `h.AsMap should succeed`) {
218 return
219 }
220 if !assert.Len(t, m, 0, `len should be zero`) {
221 return
222 }
223 })
224 })
225 }
226
View as plain text