1
21
22 package fosite_test
23
24 import (
25 "bytes"
26 "io/ioutil"
27 "net/url"
28 "strings"
29 "testing"
30
31 "github.com/ory/fosite"
32 "github.com/ory/fosite/internal"
33
34 "github.com/stretchr/testify/assert"
35 "github.com/stretchr/testify/require"
36 )
37
38 func TestIsLocalhost(t *testing.T) {
39 for k, c := range []struct {
40 expect bool
41 rawurl string
42 }{
43 {expect: false, rawurl: "https://foo.bar"},
44 {expect: true, rawurl: "https://localhost"},
45 {expect: true, rawurl: "https://localhost:1234"},
46 {expect: true, rawurl: "https://127.0.0.1:1234"},
47 {expect: true, rawurl: "https://127.0.0.1"},
48 {expect: true, rawurl: "https://test.localhost:1234"},
49 {expect: true, rawurl: "https://test.localhost"},
50 } {
51 u, _ := url.Parse(c.rawurl)
52 assert.Equal(t, c.expect, fosite.IsLocalhost(u), "case %d", k)
53 }
54 }
55
56
57
58
59
60
61
62
63
64
65
66
67 func TestDoesClientWhiteListRedirect(t *testing.T) {
68 for k, c := range []struct {
69 client fosite.Client
70 url string
71 isError bool
72 expected string
73 }{
74 {
75 client: &fosite.DefaultClient{RedirectURIs: []string{""}},
76 url: "https://foo.com/cb",
77 isError: true,
78 },
79 {
80 client: &fosite.DefaultClient{RedirectURIs: []string{"wta://auth"}},
81 url: "wta://auth",
82 expected: "wta://auth",
83 isError: false,
84 },
85 {
86 client: &fosite.DefaultClient{RedirectURIs: []string{"wta:///auth"}},
87 url: "wta:///auth",
88 expected: "wta:///auth",
89 isError: false,
90 },
91 {
92 client: &fosite.DefaultClient{RedirectURIs: []string{"wta://foo/auth"}},
93 url: "wta://foo/auth",
94 expected: "wta://foo/auth",
95 isError: false,
96 },
97 {
98 client: &fosite.DefaultClient{RedirectURIs: []string{"https://bar.com/cb"}},
99 url: "https://foo.com/cb",
100 isError: true,
101 },
102 {
103 client: &fosite.DefaultClient{RedirectURIs: []string{"https://bar.com/cb"}},
104 url: "",
105 isError: false,
106 expected: "https://bar.com/cb",
107 },
108 {
109 client: &fosite.DefaultClient{RedirectURIs: []string{""}},
110 url: "",
111 isError: true,
112 },
113 {
114 client: &fosite.DefaultClient{RedirectURIs: []string{"https://bar.com/cb"}},
115 url: "https://bar.com/cb",
116 isError: false,
117 expected: "https://bar.com/cb",
118 },
119 {
120 client: &fosite.DefaultClient{RedirectURIs: []string{"https://bar.com/cb"}},
121 url: "https://bar.com/cb123",
122 isError: true,
123 },
124 {
125 client: &fosite.DefaultClient{RedirectURIs: []string{"http://[::1]"}},
126 url: "http://[::1]:1024",
127 expected: "http://[::1]:1024",
128 isError: false,
129 },
130 {
131 client: &fosite.DefaultClient{RedirectURIs: []string{"http://[::1]"}},
132 url: "http://[::1]:1024/cb",
133 isError: true,
134 },
135 {
136 client: &fosite.DefaultClient{RedirectURIs: []string{"http://[::1]/cb"}},
137 url: "http://[::1]:1024/cb",
138 expected: "http://[::1]:1024/cb",
139 isError: false,
140 },
141 {
142 client: &fosite.DefaultClient{RedirectURIs: []string{"http://[::1]"}},
143 url: "http://foo.bar/bar",
144 isError: true,
145 },
146 {
147 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1"}},
148 url: "http://127.0.0.1:1024",
149 expected: "http://127.0.0.1:1024",
150 isError: false,
151 },
152 {
153 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1/cb"}},
154 url: "http://127.0.0.1:64000/cb",
155 expected: "http://127.0.0.1:64000/cb",
156 isError: false,
157 },
158 {
159 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1"}},
160 url: "http://127.0.0.1:64000/cb",
161 isError: true,
162 },
163 {
164 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1"}},
165 url: "http://127.0.0.1",
166 expected: "http://127.0.0.1",
167 isError: false,
168 },
169 {
170 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1/Cb"}},
171 url: "http://127.0.0.1:8080/Cb",
172 expected: "http://127.0.0.1:8080/Cb",
173 isError: false,
174 },
175 {
176 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1"}},
177 url: "http://foo.bar/bar",
178 isError: true,
179 },
180 {
181 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1"}},
182 url: ":/invalid.uri)bar",
183 isError: true,
184 },
185 {
186 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb"}},
187 url: "http://127.0.0.1:8080/Cb",
188 isError: true,
189 },
190 {
191 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb"}},
192 url: "http://127.0.0.1:8080/cb?foo=bar",
193 isError: true,
194 },
195 {
196 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb?foo=bar"}},
197 url: "http://127.0.0.1:8080/cb?foo=bar",
198 expected: "http://127.0.0.1:8080/cb?foo=bar",
199 isError: false,
200 },
201 {
202 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb?foo=bar"}},
203 url: "http://127.0.0.1:8080/cb?baz=bar&foo=bar",
204 isError: true,
205 },
206 {
207 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb?foo=bar&baz=bar"}},
208 url: "http://127.0.0.1:8080/cb?baz=bar&foo=bar",
209 isError: true,
210 },
211 {
212 client: &fosite.DefaultClient{RedirectURIs: []string{"https://www.ory.sh/cb"}},
213 url: "http://127.0.0.1:8080/cb",
214 isError: true,
215 },
216 {
217 client: &fosite.DefaultClient{RedirectURIs: []string{"http://127.0.0.1:8080/cb"}},
218 url: "https://www.ory.sh/cb",
219 isError: true,
220 },
221 {
222 client: &fosite.DefaultClient{RedirectURIs: []string{"web+application://callback"}},
223 url: "web+application://callback",
224 isError: false,
225 expected: "web+application://callback",
226 },
227 {
228 client: &fosite.DefaultClient{RedirectURIs: []string{"https://google.com/?foo=bar%20foo+baz"}},
229 url: "https://google.com/?foo=bar%20foo+baz",
230 isError: false,
231 expected: "https://google.com/?foo=bar%20foo+baz",
232 },
233 } {
234 redir, err := fosite.MatchRedirectURIWithClientRedirectURIs(c.url, c.client)
235 assert.Equal(t, c.isError, err != nil, "%d: %+v", k, c)
236 if err == nil {
237 require.NotNil(t, redir, "%d", k)
238 assert.Equal(t, c.expected, redir.String(), "%d", k)
239 }
240 t.Logf("Passed test case %d", k)
241 }
242 }
243
244 func TestIsRedirectURISecure(t *testing.T) {
245 for d, c := range []struct {
246 u string
247 err bool
248 }{
249 {u: "http://google.com", err: true},
250 {u: "https://google.com", err: false},
251 {u: "http://localhost", err: false},
252 {u: "http://test.localhost", err: false},
253 {u: "http://127.0.0.1/", err: false},
254 {u: "http://[::1]/", err: false},
255 {u: "http://127.0.0.1:8080/", err: false},
256 {u: "http://[::1]:8080/", err: false},
257 {u: "http://testlocalhost", err: true},
258 {u: "wta://auth", err: false},
259 } {
260 uu, err := url.Parse(c.u)
261 require.NoError(t, err)
262 assert.Equal(t, !c.err, fosite.IsRedirectURISecure(uu), "case %d", d)
263 }
264 }
265
266 func TestWriteAuthorizeFormPostResponse(t *testing.T) {
267 for d, c := range []struct {
268 parameters url.Values
269 check func(code string, state string, customParams url.Values, d int)
270 }{
271 {
272 parameters: url.Values{"code": {"lshr755nsg39fgur"}, "state": {"924659540232"}},
273 check: func(code string, state string, customParams url.Values, d int) {
274 assert.Equal(t, "lshr755nsg39fgur", code, "case %d", d)
275 assert.Equal(t, "924659540232", state, "case %d", d)
276 },
277 },
278 {
279 parameters: url.Values{"code": {"lshr75*ns-39f+ur"}, "state": {"9a:* <&)"}},
280 check: func(code string, state string, customParams url.Values, d int) {
281 assert.Equal(t, "lshr75*ns-39f+ur", code, "case %d", d)
282 assert.Equal(t, "9a:* <&)", state, "case %d", d)
283 },
284 },
285 {
286 parameters: url.Values{"code": {"1234"}, "custom": {"test2", "test3"}},
287 check: func(code string, state string, customParams url.Values, d int) {
288 assert.Equal(t, "1234", code, "case %d", d)
289 assert.Equal(t, []string{"test2", "test3"}, customParams["custom"], "case %d", d)
290 },
291 },
292 {
293 parameters: url.Values{"code": {"1234"}, "custom": {"<b>Bold</b>"}},
294 check: func(code string, state string, customParams url.Values, d int) {
295 assert.Equal(t, "1234", code, "case %d", d)
296 assert.Equal(t, "<b>Bold</b>", customParams.Get("custom"), "case %d", d)
297 },
298 },
299 } {
300 var responseBuffer bytes.Buffer
301 redirectURL := "https://localhost:8080/cb"
302
303 fosite.WriteAuthorizeFormPostResponse(redirectURL, c.parameters, fosite.FormPostDefaultTemplate, &responseBuffer)
304 code, state, _, _, customParams, _, err := internal.ParseFormPostResponse(redirectURL, ioutil.NopCloser(bytes.NewReader(responseBuffer.Bytes())))
305 assert.NoError(t, err, "case %d", d)
306 c.check(code, state, customParams, d)
307
308 }
309 }
310
311 func TestIsRedirectURISecureStrict(t *testing.T) {
312 for d, c := range []struct {
313 u string
314 err bool
315 }{
316 {u: "http://google.com", err: true},
317 {u: "https://google.com", err: false},
318 {u: "http://localhost", err: false},
319 {u: "http://test.localhost", err: false},
320 {u: "http://127.0.0.1/", err: false},
321 {u: "http://[::1]/", err: false},
322 {u: "http://127.0.0.1:8080/", err: false},
323 {u: "http://[::1]:8080/", err: false},
324 {u: "http://testlocalhost", err: true},
325 {u: "wta://auth", err: true},
326 } {
327 uu, err := url.Parse(c.u)
328 require.NoError(t, err)
329 assert.Equal(t, !c.err, fosite.IsRedirectURISecureStrict(uu), "case %d", d)
330 }
331 }
332
333 func TestURLSetFragment(t *testing.T) {
334 for d, c := range []struct {
335 u string
336 a string
337 f url.Values
338 }{
339 {u: "http://google.com", a: "http://google.com#code=567060896", f: url.Values{"code": []string{"567060896"}}},
340 {u: "http://google.com", a: "http://google.com#code=567060896&scope=read", f: url.Values{"code": []string{"567060896"}, "scope": []string{"read"}}},
341 {u: "http://google.com", a: "http://google.com#code=567060896&scope=read%20mail", f: url.Values{"code": []string{"567060896j"}, "scope": []string{"read mail"}}},
342 {u: "http://google.com", a: "http://google.com#code=567060896&scope=read+write", f: url.Values{"code": []string{"567060896"}, "scope": []string{"read+write"}}},
343 {u: "http://google.com", a: "http://google.com#code=567060896&scope=api:*", f: url.Values{"code": []string{"567060896"}, "scope": []string{"api:*"}}},
344 {u: "https://google.com?foo=bar", a: "https://google.com?foo=bar#code=567060896", f: url.Values{"code": []string{"567060896"}}},
345 {u: "http://localhost?foo=bar&baz=foo", a: "http://localhost?foo=bar&baz=foo#code=567060896", f: url.Values{"code": []string{"567060896"}}},
346 } {
347 uu, err := url.Parse(c.u)
348 require.NoError(t, err)
349 fosite.URLSetFragment(uu, c.f)
350 tURL, err := url.Parse(uu.String())
351 require.NoError(t, err)
352 r := ParseURLFragment(tURL.Fragment)
353 assert.Equal(t, c.f.Get("code"), r.Get("code"), "case %d", d)
354 assert.Equal(t, c.f.Get("scope"), r.Get("scope"), "case %d", d)
355 }
356 }
357 func ParseURLFragment(fragment string) url.Values {
358 r := url.Values{}
359 kvs := strings.Split(fragment, "&")
360 for _, kv := range kvs {
361 kva := strings.Split(kv, "=")
362 r.Add(kva[0], kva[1])
363 }
364 return r
365 }
366
View as plain text