github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/goauth2/oauth/oauth_test.go (about)

     1  // Copyright 2011 The goauth2 Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package oauth
     6  
     7  import (
     8  	"io"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"net/url"
    13  	"os"
    14  	"path/filepath"
    15  	"runtime"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  var requests = []struct {
    21  	path, query, auth string // request
    22  	contenttype, body string // response
    23  }{
    24  	{
    25  		path:        "/token",
    26  		query:       "grant_type=authorization_code&code=c0d3&client_id=cl13nt1d",
    27  		contenttype: "application/json",
    28  		body: `
    29  			{
    30  				"access_token":"token1",
    31  				"refresh_token":"refreshtoken1",
    32  				"id_token":"idtoken1",
    33  				"expires_in":3600
    34  			}
    35  		`,
    36  	},
    37  	{path: "/secure", auth: "Bearer token1", body: "first payload"},
    38  	{
    39  		path:        "/token",
    40  		query:       "grant_type=refresh_token&refresh_token=refreshtoken1&client_id=cl13nt1d",
    41  		contenttype: "application/json",
    42  		body: `
    43  			{
    44  				"access_token":"token2",
    45  				"refresh_token":"refreshtoken2",
    46  				"id_token":"idtoken2",
    47  				"expires_in":3600
    48  			}
    49  		`,
    50  	},
    51  	{path: "/secure", auth: "Bearer token2", body: "second payload"},
    52  	{
    53  		path:        "/token",
    54  		query:       "grant_type=refresh_token&refresh_token=refreshtoken2&client_id=cl13nt1d",
    55  		contenttype: "application/x-www-form-urlencoded",
    56  		body:        "access_token=token3&refresh_token=refreshtoken3&id_token=idtoken3&expires_in=3600",
    57  	},
    58  	{path: "/secure", auth: "Bearer token3", body: "third payload"},
    59  }
    60  
    61  func TestOAuth(t *testing.T) {
    62  	// Set up test server.
    63  	n := 0
    64  	handler := func(w http.ResponseWriter, r *http.Request) {
    65  		if n >= len(requests) {
    66  			t.Errorf("too many requests: %d", n)
    67  			return
    68  		}
    69  		req := requests[n]
    70  		n++
    71  
    72  		// Check request.
    73  		if g, w := r.URL.Path, req.path; g != w {
    74  			t.Errorf("request[%d] got path %s, want %s", n, g, w)
    75  		}
    76  		want, _ := url.ParseQuery(req.query)
    77  		for k := range want {
    78  			if g, w := r.FormValue(k), want.Get(k); g != w {
    79  				t.Errorf("query[%s] = %s, want %s", k, g, w)
    80  			}
    81  		}
    82  		if g, w := r.Header.Get("Authorization"), req.auth; w != "" && g != w {
    83  			t.Errorf("Authorization: %v, want %v", g, w)
    84  		}
    85  
    86  		// Send response.
    87  		w.Header().Set("Content-Type", req.contenttype)
    88  		io.WriteString(w, req.body)
    89  	}
    90  	server := httptest.NewServer(http.HandlerFunc(handler))
    91  	defer server.Close()
    92  
    93  	config := &Config{
    94  		ClientId:     "cl13nt1d",
    95  		ClientSecret: "s3cr3t",
    96  		Scope:        "https://example.net/scope",
    97  		AuthURL:      server.URL + "/auth",
    98  		TokenURL:     server.URL + "/token",
    99  	}
   100  
   101  	// TODO(adg): test AuthCodeURL
   102  
   103  	transport := &Transport{Config: config}
   104  	_, err := transport.Exchange("c0d3")
   105  	if err != nil {
   106  		t.Fatalf("Exchange: %v", err)
   107  	}
   108  	checkToken(t, transport.Token, "token1", "refreshtoken1", "idtoken1")
   109  
   110  	c := transport.Client()
   111  	resp, err := c.Get(server.URL + "/secure")
   112  	if err != nil {
   113  		t.Fatalf("Get: %v", err)
   114  	}
   115  	checkBody(t, resp, "first payload")
   116  
   117  	// test automatic refresh
   118  	transport.Expiry = time.Now().Add(-time.Hour)
   119  	resp, err = c.Get(server.URL + "/secure")
   120  	if err != nil {
   121  		t.Fatalf("Get: %v", err)
   122  	}
   123  	checkBody(t, resp, "second payload")
   124  	checkToken(t, transport.Token, "token2", "refreshtoken2", "idtoken2")
   125  
   126  	// refresh one more time, but get URL-encoded token instead of JSON
   127  	transport.Expiry = time.Now().Add(-time.Hour)
   128  	resp, err = c.Get(server.URL + "/secure")
   129  	if err != nil {
   130  		t.Fatalf("Get: %v", err)
   131  	}
   132  	checkBody(t, resp, "third payload")
   133  	checkToken(t, transport.Token, "token3", "refreshtoken3", "idtoken3")
   134  }
   135  
   136  func checkToken(t *testing.T, tok *Token, access, refresh, id string) {
   137  	if g, w := tok.AccessToken, access; g != w {
   138  		t.Errorf("AccessToken = %q, want %q", g, w)
   139  	}
   140  	if g, w := tok.RefreshToken, refresh; g != w {
   141  		t.Errorf("RefreshToken = %q, want %q", g, w)
   142  	}
   143  	if g, w := tok.Extra["id_token"], id; g != w {
   144  		t.Errorf("Extra['id_token'] = %q, want %q", g, w)
   145  	}
   146  	exp := tok.Expiry.Sub(time.Now())
   147  	if (time.Hour-time.Second) > exp || exp > time.Hour {
   148  		t.Errorf("Expiry = %v, want ~1 hour", exp)
   149  	}
   150  }
   151  
   152  func checkBody(t *testing.T, r *http.Response, body string) {
   153  	b, err := ioutil.ReadAll(r.Body)
   154  	if err != nil {
   155  		t.Error("reading reponse body: %v, want %q", err, body)
   156  	}
   157  	if g, w := string(b), body; g != w {
   158  		t.Errorf("request body mismatch: got %q, want %q", g, w)
   159  	}
   160  }
   161  
   162  func TestCachePermissions(t *testing.T) {
   163  	if runtime.GOOS == "windows" {
   164  		// Windows doesn't support file mode bits.
   165  		return
   166  	}
   167  
   168  	td, err := ioutil.TempDir("", "oauth-test")
   169  	if err != nil {
   170  		t.Fatalf("ioutil.TempDir: %v", err)
   171  	}
   172  	defer os.RemoveAll(td)
   173  	tempFile := filepath.Join(td, "cache-file")
   174  
   175  	cf := CacheFile(tempFile)
   176  	if err := cf.PutToken(new(Token)); err != nil {
   177  		t.Fatalf("PutToken: %v", err)
   178  	}
   179  	fi, err := os.Stat(tempFile)
   180  	if err != nil {
   181  		t.Fatalf("os.Stat: %v", err)
   182  	}
   183  	if fi.Mode()&0077 != 0 {
   184  		t.Errorf("Created cache file has mode %#o, want non-accessible to group+other", fi.Mode())
   185  	}
   186  }