...

Source file src/golang.org/x/oauth2/google/internal/stsexchange/sts_exchange_test.go

Documentation: golang.org/x/oauth2/google/internal/stsexchange

     1  // Copyright 2020 The Go 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 stsexchange
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"io/ioutil"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"net/url"
    14  	"testing"
    15  
    16  	"golang.org/x/oauth2"
    17  )
    18  
    19  var auth = ClientAuthentication{
    20  	AuthStyle:    oauth2.AuthStyleInHeader,
    21  	ClientID:     clientID,
    22  	ClientSecret: clientSecret,
    23  }
    24  
    25  var exchangeTokenRequest = TokenExchangeRequest{
    26  	ActingParty: struct {
    27  		ActorToken     string
    28  		ActorTokenType string
    29  	}{},
    30  	GrantType:          "urn:ietf:params:oauth:grant-type:token-exchange",
    31  	Resource:           "",
    32  	Audience:           "32555940559.apps.googleusercontent.com", //TODO: Make sure audience is correct in this test (might be mismatched)
    33  	Scope:              []string{"https://www.googleapis.com/auth/devstorage.full_control"},
    34  	RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
    35  	SubjectToken:       "Sample.Subject.Token",
    36  	SubjectTokenType:   "urn:ietf:params:oauth:token-type:jwt",
    37  }
    38  
    39  var exchangeRequestBody = "audience=32555940559.apps.googleusercontent.com&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Atoken-exchange&requested_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdevstorage.full_control&subject_token=Sample.Subject.Token&subject_token_type=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt"
    40  var exchangeResponseBody = `{"access_token":"Sample.Access.Token","issued_token_type":"urn:ietf:params:oauth:token-type:access_token","token_type":"Bearer","expires_in":3600,"scope":"https://www.googleapis.com/auth/cloud-platform"}`
    41  var expectedExchangeToken = Response{
    42  	AccessToken:     "Sample.Access.Token",
    43  	IssuedTokenType: "urn:ietf:params:oauth:token-type:access_token",
    44  	TokenType:       "Bearer",
    45  	ExpiresIn:       3600,
    46  	Scope:           "https://www.googleapis.com/auth/cloud-platform",
    47  	RefreshToken:    "",
    48  }
    49  
    50  var refreshToken = "ReFrEsHtOkEn"
    51  var refreshRequestBody = "grant_type=refresh_token&refresh_token=" + refreshToken
    52  var refreshResponseBody = `{"access_token":"Sample.Access.Token","issued_token_type":"urn:ietf:params:oauth:token-type:access_token","token_type":"Bearer","expires_in":3600,"scope":"https://www.googleapis.com/auth/cloud-platform","refresh_token":"REFRESHED_REFRESH"}`
    53  var expectedRefreshResponse = Response{
    54  	AccessToken:     "Sample.Access.Token",
    55  	IssuedTokenType: "urn:ietf:params:oauth:token-type:access_token",
    56  	TokenType:       "Bearer",
    57  	ExpiresIn:       3600,
    58  	Scope:           "https://www.googleapis.com/auth/cloud-platform",
    59  	RefreshToken:    "REFRESHED_REFRESH",
    60  }
    61  
    62  func TestExchangeToken(t *testing.T) {
    63  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    64  		if r.Method != "POST" {
    65  			t.Errorf("Unexpected request method, %v is found", r.Method)
    66  		}
    67  		if r.URL.String() != "/" {
    68  			t.Errorf("Unexpected request URL, %v is found", r.URL)
    69  		}
    70  		if got, want := r.Header.Get("Authorization"), "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ="; got != want {
    71  			t.Errorf("Unexpected authorization header, got %v, want %v", got, want)
    72  		}
    73  		if got, want := r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; got != want {
    74  			t.Errorf("Unexpected Content-Type header, got %v, want %v", got, want)
    75  		}
    76  		body, err := ioutil.ReadAll(r.Body)
    77  		if err != nil {
    78  			t.Errorf("Failed reading request body: %v.", err)
    79  		}
    80  		if got, want := string(body), exchangeRequestBody; got != want {
    81  			t.Errorf("Unexpected exchange payload, got %v but want %v", got, want)
    82  		}
    83  		w.Header().Set("Content-Type", "application/json")
    84  		w.Write([]byte(exchangeResponseBody))
    85  	}))
    86  	defer ts.Close()
    87  
    88  	headers := http.Header{}
    89  	headers.Add("Content-Type", "application/x-www-form-urlencoded")
    90  
    91  	resp, err := ExchangeToken(context.Background(), ts.URL, &exchangeTokenRequest, auth, headers, nil)
    92  	if err != nil {
    93  		t.Fatalf("exchangeToken failed with error: %v", err)
    94  	}
    95  
    96  	if expectedExchangeToken != *resp {
    97  		t.Errorf("mismatched messages received by mock server.  \nWant: \n%v\n\nGot:\n%v", expectedExchangeToken, *resp)
    98  	}
    99  
   100  	resp, err = ExchangeToken(context.Background(), ts.URL, &exchangeTokenRequest, auth, nil, nil)
   101  	if err != nil {
   102  		t.Fatalf("exchangeToken failed with error: %v", err)
   103  	}
   104  
   105  	if expectedExchangeToken != *resp {
   106  		t.Errorf("mismatched messages received by mock server.  \nWant: \n%v\n\nGot:\n%v", expectedExchangeToken, *resp)
   107  	}
   108  }
   109  
   110  func TestExchangeToken_Err(t *testing.T) {
   111  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   112  		w.Header().Set("Content-Type", "application/json")
   113  		w.Write([]byte("what's wrong with this response?"))
   114  	}))
   115  	defer ts.Close()
   116  
   117  	headers := http.Header{}
   118  	headers.Add("Content-Type", "application/x-www-form-urlencoded")
   119  	_, err := ExchangeToken(context.Background(), ts.URL, &exchangeTokenRequest, auth, headers, nil)
   120  	if err == nil {
   121  		t.Errorf("Expected handled error; instead got nil.")
   122  	}
   123  }
   124  
   125  /* Lean test specifically for options, as the other features are tested earlier. */
   126  type testOpts struct {
   127  	First  string `json:"first"`
   128  	Second string `json:"second"`
   129  }
   130  
   131  var optsValues = [][]string{{"foo", "bar"}, {"cat", "pan"}}
   132  
   133  func TestExchangeToken_Opts(t *testing.T) {
   134  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   135  		body, err := ioutil.ReadAll(r.Body)
   136  		if err != nil {
   137  			t.Fatalf("Failed reading request body: %v.", err)
   138  		}
   139  		data, err := url.ParseQuery(string(body))
   140  		if err != nil {
   141  			t.Fatalf("Failed to parse request body: %v", err)
   142  		}
   143  		strOpts, ok := data["options"]
   144  		if !ok {
   145  			t.Errorf("Server didn't recieve an \"options\" field.")
   146  		} else if len(strOpts) < 1 {
   147  			t.Errorf("\"options\" field has length 0.")
   148  		}
   149  		var opts map[string]interface{}
   150  		err = json.Unmarshal([]byte(strOpts[0]), &opts)
   151  		if err != nil {
   152  			t.Fatalf("Couldn't parse received \"options\" field.")
   153  		}
   154  		if len(opts) < 2 {
   155  			t.Errorf("Too few options received.")
   156  		}
   157  
   158  		val, ok := opts["one"]
   159  		if !ok {
   160  			t.Errorf("Couldn't find first option parameter.")
   161  		} else {
   162  			tOpts1, ok := val.(map[string]interface{})
   163  			if !ok {
   164  				t.Errorf("Failed to assert the first option parameter as type testOpts.")
   165  			} else {
   166  				if got, want := tOpts1["first"].(string), optsValues[0][0]; got != want {
   167  					t.Errorf("First value in first options field is incorrect; got %v but want %v", got, want)
   168  				}
   169  				if got, want := tOpts1["second"].(string), optsValues[0][1]; got != want {
   170  					t.Errorf("Second value in first options field is incorrect; got %v but want %v", got, want)
   171  				}
   172  			}
   173  		}
   174  
   175  		val2, ok := opts["two"]
   176  		if !ok {
   177  			t.Errorf("Couldn't find second option parameter.")
   178  		} else {
   179  			tOpts2, ok := val2.(map[string]interface{})
   180  			if !ok {
   181  				t.Errorf("Failed to assert the second option parameter as type testOpts.")
   182  			} else {
   183  				if got, want := tOpts2["first"].(string), optsValues[1][0]; got != want {
   184  					t.Errorf("First value in second options field is incorrect; got %v but want %v", got, want)
   185  				}
   186  				if got, want := tOpts2["second"].(string), optsValues[1][1]; got != want {
   187  					t.Errorf("Second value in second options field is incorrect; got %v but want %v", got, want)
   188  				}
   189  			}
   190  		}
   191  
   192  		// Send a proper reply so that no other errors crop up.
   193  		w.Header().Set("Content-Type", "application/json")
   194  		w.Write([]byte(exchangeResponseBody))
   195  
   196  	}))
   197  	defer ts.Close()
   198  	headers := http.Header{}
   199  	headers.Add("Content-Type", "application/x-www-form-urlencoded")
   200  
   201  	firstOption := testOpts{optsValues[0][0], optsValues[0][1]}
   202  	secondOption := testOpts{optsValues[1][0], optsValues[1][1]}
   203  	inputOpts := make(map[string]interface{})
   204  	inputOpts["one"] = firstOption
   205  	inputOpts["two"] = secondOption
   206  	ExchangeToken(context.Background(), ts.URL, &exchangeTokenRequest, auth, headers, inputOpts)
   207  }
   208  
   209  func TestRefreshToken(t *testing.T) {
   210  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   211  		if r.Method != "POST" {
   212  			t.Errorf("Unexpected request method, %v is found", r.Method)
   213  		}
   214  		if r.URL.String() != "/" {
   215  			t.Errorf("Unexpected request URL, %v is found", r.URL)
   216  		}
   217  		if got, want := r.Header.Get("Authorization"), "Basic cmJyZ25vZ25yaG9uZ28zYmk0Z2I5Z2hnOWc6bm90c29zZWNyZXQ="; got != want {
   218  			t.Errorf("Unexpected authorization header, got %v, want %v", got, want)
   219  		}
   220  		if got, want := r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; got != want {
   221  			t.Errorf("Unexpected Content-Type header, got %v, want %v", got, want)
   222  		}
   223  		body, err := ioutil.ReadAll(r.Body)
   224  		if err != nil {
   225  			t.Errorf("Failed reading request body: %v.", err)
   226  		}
   227  		if got, want := string(body), refreshRequestBody; got != want {
   228  			t.Errorf("Unexpected exchange payload, got %v but want %v", got, want)
   229  		}
   230  		w.Header().Set("Content-Type", "application/json")
   231  		w.Write([]byte(refreshResponseBody))
   232  	}))
   233  	defer ts.Close()
   234  
   235  	headers := http.Header{}
   236  	headers.Add("Content-Type", "application/x-www-form-urlencoded")
   237  
   238  	resp, err := RefreshAccessToken(context.Background(), ts.URL, refreshToken, auth, headers)
   239  	if err != nil {
   240  		t.Fatalf("exchangeToken failed with error: %v", err)
   241  	}
   242  
   243  	if expectedRefreshResponse != *resp {
   244  		t.Errorf("mismatched messages received by mock server.  \nWant: \n%v\n\nGot:\n%v", expectedRefreshResponse, *resp)
   245  	}
   246  
   247  	resp, err = RefreshAccessToken(context.Background(), ts.URL, refreshToken, auth, nil)
   248  	if err != nil {
   249  		t.Fatalf("exchangeToken failed with error: %v", err)
   250  	}
   251  
   252  	if expectedRefreshResponse != *resp {
   253  		t.Errorf("mismatched messages received by mock server.  \nWant: \n%v\n\nGot:\n%v", expectedRefreshResponse, *resp)
   254  	}
   255  }
   256  
   257  func TestRefreshToken_Err(t *testing.T) {
   258  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   259  		w.Header().Set("Content-Type", "application/json")
   260  		w.Write([]byte("what's wrong with this response?"))
   261  	}))
   262  	defer ts.Close()
   263  
   264  	headers := http.Header{}
   265  	headers.Add("Content-Type", "application/x-www-form-urlencoded")
   266  
   267  	_, err := RefreshAccessToken(context.Background(), ts.URL, refreshToken, auth, headers)
   268  	if err == nil {
   269  		t.Errorf("Expected handled error; instead got nil.")
   270  	}
   271  }
   272  

View as plain text