...

Source file src/github.com/ory/fosite/authorize_helper_test.go

Documentation: github.com/ory/fosite

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   *
    20   */
    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  // rfc6749 10.6.
    57  // Authorization Code Redirection URI Manipulation
    58  // The authorization server	MUST require public clients and SHOULD require confidential clients
    59  // to register their redirection URIs.  If a redirection URI is provided
    60  // in the request, the authorization server MUST validate it against the
    61  // registered value.
    62  //
    63  // rfc6819 4.4.1.7.
    64  // Threat: Authorization "code" Leakage through Counterfeit Client
    65  // The authorization server may also enforce the usage and validation
    66  // of pre-registered redirect URIs (see Section 5.2.3.5).
    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  		//parameters :=
   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