auth

Paddy 2015-01-24 Parent:23c1a07c8a61 Child:f474ce964dcf

129:4f5d13d2f7c7 Go to Latest

auth/client_test.go

Test our getClientAuth helper, switch to table-based tests. Our getClientAuth helper was being tested implicitly when we tested our verifyClient helper, but let's test them separately. While we're at it, let's use table based tests instead of copy and paste. I noticed a lot of copy/paste errors while I was updating this, and the less test code we have and the easier we make it to test new edge cases, the better of we are.

History
     1.1 --- a/client_test.go	Mon Jan 19 06:42:42 2015 -0500
     1.2 +++ b/client_test.go	Sat Jan 24 09:13:23 2015 -0500
     1.3 @@ -469,8 +469,84 @@
     1.4  	}
     1.5  }
     1.6  
     1.7 +func TestGetClientAuth(t *testing.T) {
     1.8 +	t.Parallel()
     1.9 +	type clientAuthRequest struct {
    1.10 +		username                 string
    1.11 +		pass                     string
    1.12 +		clientID                 string
    1.13 +		allowPublic              bool
    1.14 +		expectedClientID         uuid.ID
    1.15 +		expectedClientSecret     string
    1.16 +		expectedValid            bool
    1.17 +		expectedCode             int
    1.18 +		expectedBody             string
    1.19 +		expectAuthenticateHeader bool
    1.20 +	}
    1.21 +	id := uuid.NewID()
    1.22 +	tests := []clientAuthRequest{
    1.23 +		{"", "", "", false, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
    1.24 +		{"", "", "", true, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
    1.25 +		{"", "no clientID set", "", false, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
    1.26 +		{"", "no clientID set", "", true, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
    1.27 +		{"not an actual id", "invalid client ID set", "", false, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
    1.28 +		{"not an actual id", "invalid client ID set", "", true, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
    1.29 +		{"", "", "not an actual id", true, nil, "", false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
    1.30 +		{id.String(), "secret", "", true, id, "secret", true, http.StatusOK, "", false},
    1.31 +		{id.String(), "secret", "", false, id, "secret", true, http.StatusOK, "", false},
    1.32 +		{"", "", id.String(), true, id, "", true, http.StatusOK, "", false},
    1.33 +		{"", "", id.String(), false, nil, "", false, http.StatusBadRequest, `{"error":"unauthorized_client"}`, false},
    1.34 +	}
    1.35 +	for pos, test := range tests {
    1.36 +		t.Logf("Running test #%d, with request %+v", pos, test)
    1.37 +		w := httptest.NewRecorder()
    1.38 +		r, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
    1.39 +		if err != nil {
    1.40 +			t.Fatal("Can't build request:", err)
    1.41 +		}
    1.42 +		if test.username != "" || test.pass != "" {
    1.43 +			r.SetBasicAuth(test.username, test.pass)
    1.44 +		}
    1.45 +		r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    1.46 +		params := url.Values{}
    1.47 +		params.Set("client_id", test.clientID)
    1.48 +		body := bytes.NewBufferString(params.Encode())
    1.49 +		r.Body = ioutil.NopCloser(body)
    1.50 +		respID, respSecret, success := getClientAuth(w, r, test.allowPublic)
    1.51 +		if (respID == nil && test.expectedClientID != nil) || (respID != nil && test.expectedClientID == nil) || !respID.Equal(test.expectedClientID) {
    1.52 +			t.Errorf("Expected response ID to be %v, got %v", test.expectedClientID, respID)
    1.53 +		}
    1.54 +		if test.expectedClientSecret != respSecret {
    1.55 +			t.Errorf("Expected response secret to be '%s', got '%s'", test.expectedClientSecret, respSecret)
    1.56 +		}
    1.57 +		if test.expectedValid != success {
    1.58 +			t.Errorf("Expected success result to be %v, got %v", test.expectedValid, success)
    1.59 +		}
    1.60 +		if test.expectedCode != w.Code {
    1.61 +			t.Errorf("Expected response code to be %d, got %d", test.expectedCode, w.Code)
    1.62 +		}
    1.63 +		if test.expectedBody != strings.TrimSpace(w.Body.String()) {
    1.64 +			t.Errorf("Expected body to be '%s', got '%s'", test.expectedBody, strings.TrimSpace(w.Body.String()))
    1.65 +		}
    1.66 +		if test.expectAuthenticateHeader && w.Header().Get("WWW-Authenticate") != "Basic" {
    1.67 +			t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
    1.68 +		}
    1.69 +	}
    1.70 +}
    1.71 +
    1.72  func TestVerifyClient(t *testing.T) {
    1.73  	t.Parallel()
    1.74 +	type verifyClientRequest struct {
    1.75 +		username                 string
    1.76 +		pass                     string
    1.77 +		clientID                 string
    1.78 +		allowPublic              bool
    1.79 +		expectedClientID         uuid.ID
    1.80 +		expectedValid            bool
    1.81 +		expectedCode             int
    1.82 +		expectedBody             string
    1.83 +		expectAuthenticateHeader bool
    1.84 +	}
    1.85  	memstore := NewMemstore()
    1.86  	context := Context{
    1.87  		clients: memstore,
    1.88 @@ -501,366 +577,57 @@
    1.89  	if err != nil {
    1.90  		t.Fatal("Could not save client:", err)
    1.91  	}
    1.92 -
    1.93 -	// verifyClient with no auth header, no public clients
    1.94 -	w := httptest.NewRecorder()
    1.95 -	r, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
    1.96 -	if err != nil {
    1.97 -		t.Fatal("Can't build request:", err)
    1.98 -	}
    1.99 -	resp, success := verifyClient(w, r, false, context)
   1.100 -	if success {
   1.101 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.102 -	}
   1.103 -	if resp != nil {
   1.104 -		t.Error("Expected nil client ID, got", resp)
   1.105 -	}
   1.106 -	if w.Code != http.StatusUnauthorized {
   1.107 -		t.Errorf("Expected status code of %d, got %d", http.StatusUnauthorized, w.Code)
   1.108 -	}
   1.109 -	expectedBody := `{"error":"invalid_client"}`
   1.110 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.111 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.112 +	id := uuid.NewID()
   1.113 +	tests := []verifyClientRequest{
   1.114 +		{"", "", "", false, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
   1.115 +		{"", "", "", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
   1.116 +		{"", "no clientID set", "", false, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.117 +		{"", "no clientID set", "", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.118 +		{"not an actual id", "invalid client ID set", "", false, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.119 +		{"not an actual id", "invalid client ID set", "", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.120 +		{id.String(), "unsaved client ID set", "", false, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.121 +		{id.String(), "unsaved client ID set", "", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.122 +		{client.ID.String(), "wrong secret", "", false, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.123 +		{client.ID.String(), "wrong secret", "", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, true},
   1.124 +		{"", "", "not an actual id", true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
   1.125 +		{"", "", id.String(), true, nil, false, http.StatusUnauthorized, `{"error":"invalid_client"}`, false},
   1.126 +		{client.ID.String(), client.Secret, "", true, client.ID, true, http.StatusOK, "", false},
   1.127 +		{client.ID.String(), client.Secret, "", false, client.ID, true, http.StatusOK, "", false},
   1.128 +		{"", "", publicClient.ID.String(), true, publicClient.ID, true, http.StatusOK, "", false},
   1.129 +		{"", "", publicClient.ID.String(), false, nil, false, http.StatusBadRequest, `{"error":"unauthorized_client"}`, false},
   1.130  	}
   1.131  
   1.132 -	// verifyClient with no auth header, public clients, empty client_id
   1.133 -	w = httptest.NewRecorder()
   1.134 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.135 -	if err != nil {
   1.136 -		t.Fatal("Can't build request:", err)
   1.137 -	}
   1.138 -	resp, success = verifyClient(w, r, true, context)
   1.139 -	if success {
   1.140 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.141 -	}
   1.142 -	if resp != nil {
   1.143 -		t.Error("Expected nil client ID, got", resp)
   1.144 -	}
   1.145 -	if w.Code != http.StatusUnauthorized {
   1.146 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.147 -	}
   1.148 -	expectedBody = `{"error":"invalid_client"}`
   1.149 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.150 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.151 -	}
   1.152 -
   1.153 -	// verifyClient with auth header, no public clients, empty client id
   1.154 -	w = httptest.NewRecorder()
   1.155 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.156 -	if err != nil {
   1.157 -		t.Fatal("Can't build request:", err)
   1.158 -	}
   1.159 -	r.SetBasicAuth("", "no client ID set")
   1.160 -	resp, success = verifyClient(w, r, false, context)
   1.161 -	if success {
   1.162 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.163 -	}
   1.164 -	if resp != nil {
   1.165 -		t.Error("Expected nil client ID, got", resp)
   1.166 -	}
   1.167 -	if w.Code != http.StatusUnauthorized {
   1.168 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.169 -	}
   1.170 -	expectedBody = `{"error":"invalid_client"}`
   1.171 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.172 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.173 -	}
   1.174 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.175 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.176 -	}
   1.177 -
   1.178 -	// verifyClient with auth header, public clients, empty client id
   1.179 -	w = httptest.NewRecorder()
   1.180 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.181 -	if err != nil {
   1.182 -		t.Fatal("Can't build request:", err)
   1.183 -	}
   1.184 -	r.SetBasicAuth("", "no client ID set")
   1.185 -	resp, success = verifyClient(w, r, true, context)
   1.186 -	if success {
   1.187 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.188 -	}
   1.189 -	if resp != nil {
   1.190 -		t.Error("Expected nil client ID, got", resp)
   1.191 -	}
   1.192 -	if w.Code != http.StatusUnauthorized {
   1.193 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.194 -	}
   1.195 -	expectedBody = `{"error":"invalid_client"}`
   1.196 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.197 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.198 -	}
   1.199 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.200 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.201 -	}
   1.202 -
   1.203 -	// verifyClient with auth header, no public clients, invalid client ID
   1.204 -	w = httptest.NewRecorder()
   1.205 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.206 -	if err != nil {
   1.207 -		t.Fatal("Can't build request:", err)
   1.208 -	}
   1.209 -	r.SetBasicAuth("not an actual id", "invalid client ID set")
   1.210 -	resp, success = verifyClient(w, r, false, context)
   1.211 -	if success {
   1.212 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.213 -	}
   1.214 -	if resp != nil {
   1.215 -		t.Error("Expected nil client ID, got", resp)
   1.216 -	}
   1.217 -	if w.Code != http.StatusUnauthorized {
   1.218 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.219 -	}
   1.220 -	expectedBody = `{"error":"invalid_client"}`
   1.221 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.222 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.223 -	}
   1.224 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.225 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.226 -	}
   1.227 -
   1.228 -	// verifyClient with auth header, public clients, invalid client ID
   1.229 -	w = httptest.NewRecorder()
   1.230 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.231 -	if err != nil {
   1.232 -		t.Fatal("Can't build request:", err)
   1.233 -	}
   1.234 -	r.SetBasicAuth("not an actual id", "invalid client ID set")
   1.235 -	resp, success = verifyClient(w, r, true, context)
   1.236 -	if success {
   1.237 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.238 -	}
   1.239 -	if resp != nil {
   1.240 -		t.Error("Expected nil client ID, got", resp)
   1.241 -	}
   1.242 -	if w.Code != http.StatusUnauthorized {
   1.243 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.244 -	}
   1.245 -	expectedBody = `{"error":"invalid_client"}`
   1.246 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.247 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.248 -	}
   1.249 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.250 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.251 -	}
   1.252 -
   1.253 -	// verifyClient with auth header, no public clients, client ID valid but not in clientStore
   1.254 -	w = httptest.NewRecorder()
   1.255 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.256 -	if err != nil {
   1.257 -		t.Fatal("Can't build request:", err)
   1.258 -	}
   1.259 -	r.SetBasicAuth(uuid.NewID().String(), "non existent client ID set")
   1.260 -	resp, success = verifyClient(w, r, false, context)
   1.261 -	if success {
   1.262 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.263 -	}
   1.264 -	if resp != nil {
   1.265 -		t.Error("Expected nil client ID, got", resp)
   1.266 -	}
   1.267 -	if w.Code != http.StatusUnauthorized {
   1.268 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.269 -	}
   1.270 -	expectedBody = `{"error":"invalid_client"}`
   1.271 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.272 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.273 -	}
   1.274 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.275 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.276 -	}
   1.277 -
   1.278 -	// verifyClient with auth header, public clients, client ID valid but not in clientStore
   1.279 -	w = httptest.NewRecorder()
   1.280 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.281 -	if err != nil {
   1.282 -		t.Fatal("Can't build request:", err)
   1.283 -	}
   1.284 -	r.SetBasicAuth(uuid.NewID().String(), "non existent client ID set")
   1.285 -	resp, success = verifyClient(w, r, true, context)
   1.286 -	if success {
   1.287 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.288 -	}
   1.289 -	if resp != nil {
   1.290 -		t.Error("Expected nil client ID, got", resp)
   1.291 -	}
   1.292 -	if w.Code != http.StatusUnauthorized {
   1.293 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.294 -	}
   1.295 -	expectedBody = `{"error":"invalid_client"}`
   1.296 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.297 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.298 -	}
   1.299 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.300 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.301 -	}
   1.302 -
   1.303 -	// verifyClient with auth header, no public clients, client secret wrong
   1.304 -	w = httptest.NewRecorder()
   1.305 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.306 -	if err != nil {
   1.307 -		t.Fatal("Can't build request:", err)
   1.308 -	}
   1.309 -	r.SetBasicAuth(client.ID.String(), "not actually the secret")
   1.310 -	resp, success = verifyClient(w, r, false, context)
   1.311 -	if success {
   1.312 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.313 -	}
   1.314 -	if resp != nil {
   1.315 -		t.Error("Expected nil client ID, got", resp)
   1.316 -	}
   1.317 -	if w.Code != http.StatusUnauthorized {
   1.318 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.319 -	}
   1.320 -	expectedBody = `{"error":"invalid_client"}`
   1.321 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.322 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.323 -	}
   1.324 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.325 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.326 -	}
   1.327 -
   1.328 -	// verifyClient with auth header, public clients, client secret wrong
   1.329 -	w = httptest.NewRecorder()
   1.330 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.331 -	if err != nil {
   1.332 -		t.Fatal("Can't build request:", err)
   1.333 -	}
   1.334 -	r.SetBasicAuth(client.ID.String(), "not actually the secret")
   1.335 -	resp, success = verifyClient(w, r, true, context)
   1.336 -	if success {
   1.337 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.338 -	}
   1.339 -	if resp != nil {
   1.340 -		t.Error("Expected nil client ID, got", resp)
   1.341 -	}
   1.342 -	if w.Code != http.StatusUnauthorized {
   1.343 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.344 -	}
   1.345 -	expectedBody = `{"error":"invalid_client"}`
   1.346 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.347 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.348 -	}
   1.349 -	if w.Header().Get("WWW-Authenticate") != "Basic" {
   1.350 -		t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.351 -	}
   1.352 -
   1.353 -	// verifyClient with no auth header, public clients, invalid client_id post form value
   1.354 -	w = httptest.NewRecorder()
   1.355 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.356 -	if err != nil {
   1.357 -		t.Fatal("Can't build request:", err)
   1.358 -	}
   1.359 -	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   1.360 -	params := url.Values{}
   1.361 -	params.Set("client_id", "not an actual id")
   1.362 -	body := bytes.NewBufferString(params.Encode())
   1.363 -	r.Body = ioutil.NopCloser(body)
   1.364 -	resp, success = verifyClient(w, r, true, context)
   1.365 -	if success {
   1.366 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.367 -	}
   1.368 -	if resp != nil {
   1.369 -		t.Error("Expected nil client ID, got", resp)
   1.370 -	}
   1.371 -	if w.Code != http.StatusUnauthorized {
   1.372 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.373 -	}
   1.374 -	expectedBody = `{"error":"invalid_client"}`
   1.375 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.376 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.377 -	}
   1.378 -
   1.379 -	// verifyClient with no auth header, public clients, client_id valid but not in clientStore
   1.380 -	w = httptest.NewRecorder()
   1.381 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.382 -	if err != nil {
   1.383 -		t.Fatal("Can't build request:", err)
   1.384 -	}
   1.385 -	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   1.386 -	params = url.Values{}
   1.387 -	params.Set("client_id", uuid.NewID().String())
   1.388 -	body = bytes.NewBufferString(params.Encode())
   1.389 -	r.Body = ioutil.NopCloser(body)
   1.390 -	resp, success = verifyClient(w, r, true, context)
   1.391 -	if success {
   1.392 -		t.Error("Expected verification to fail, but succeeded with client ID:", resp)
   1.393 -	}
   1.394 -	if resp != nil {
   1.395 -		t.Error("Expected nil client ID, got", resp)
   1.396 -	}
   1.397 -	if w.Code != http.StatusUnauthorized {
   1.398 -		t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code)
   1.399 -	}
   1.400 -	expectedBody = `{"error":"invalid_client"}`
   1.401 -	if expectedBody != strings.TrimSpace(w.Body.String()) {
   1.402 -		t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String()))
   1.403 -	}
   1.404 -
   1.405 -	// verifyClient with auth header, public clients, valid client_id and secret
   1.406 -	w = httptest.NewRecorder()
   1.407 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.408 -	if err != nil {
   1.409 -		t.Fatal("Can't build request:", err)
   1.410 -	}
   1.411 -	r.SetBasicAuth(client.ID.String(), client.Secret)
   1.412 -	resp, success = verifyClient(w, r, true, context)
   1.413 -	if !success {
   1.414 -		t.Error("Expected verification to succeed, but it failed")
   1.415 -	}
   1.416 -	if !client.ID.Equal(resp) {
   1.417 -		t.Errorf("Expected client ID to be %s, got %s", client.ID, resp)
   1.418 -	}
   1.419 -	if w.Code != http.StatusOK {
   1.420 -		t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code)
   1.421 -	}
   1.422 -	if w.Body.String() != "" {
   1.423 -		t.Errorf(`Expected empty body, got "%s"`, w.Body.String())
   1.424 -	}
   1.425 -
   1.426 -	// verifyClient with auth header, no public clients, valid client_id and secret
   1.427 -	w = httptest.NewRecorder()
   1.428 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.429 -	if err != nil {
   1.430 -		t.Fatal("Can't build request:", err)
   1.431 -	}
   1.432 -	r.SetBasicAuth(client.ID.String(), client.Secret)
   1.433 -	resp, success = verifyClient(w, r, true, context)
   1.434 -	if !success {
   1.435 -		t.Error("Expected verification to succeed, but it failed")
   1.436 -	}
   1.437 -	if !client.ID.Equal(resp) {
   1.438 -		t.Errorf("Expected client ID to be %s, got %s", client.ID, resp)
   1.439 -	}
   1.440 -	if w.Code != http.StatusOK {
   1.441 -		t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code)
   1.442 -	}
   1.443 -	if w.Body.String() != "" {
   1.444 -		t.Errorf(`Expected empty body, got "%s"`, w.Body.String())
   1.445 -	}
   1.446 -
   1.447 -	// verifyClient with no auth header, public clients, valid client_id and secret
   1.448 -	w = httptest.NewRecorder()
   1.449 -	r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.450 -	if err != nil {
   1.451 -		t.Fatal("Can't build request:", err)
   1.452 -	}
   1.453 -	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   1.454 -	params = url.Values{}
   1.455 -	params.Set("client_id", publicClient.ID.String())
   1.456 -	body = bytes.NewBufferString(params.Encode())
   1.457 -	r.Body = ioutil.NopCloser(body)
   1.458 -	resp, success = verifyClient(w, r, true, context)
   1.459 -	if !success {
   1.460 -		t.Error("Expected verification to succeed, but it failed")
   1.461 -	}
   1.462 -	if !publicClient.ID.Equal(resp) {
   1.463 -		t.Errorf("Expected client ID to be %s, got %s", publicClient.ID, resp)
   1.464 -	}
   1.465 -	if w.Code != http.StatusOK {
   1.466 -		t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code)
   1.467 -	}
   1.468 -	if w.Body.String() != "" {
   1.469 -		t.Errorf(`Expected empty body, got "%s"`, w.Body.String())
   1.470 +	for pos, test := range tests {
   1.471 +		t.Logf("Running test #%d, with request %+v", pos, test)
   1.472 +		w := httptest.NewRecorder()
   1.473 +		r, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil)
   1.474 +		if err != nil {
   1.475 +			t.Fatal("Can't build request:", err)
   1.476 +		}
   1.477 +		if test.username != "" || test.pass != "" {
   1.478 +			r.SetBasicAuth(test.username, test.pass)
   1.479 +		}
   1.480 +		r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   1.481 +		params := url.Values{}
   1.482 +		params.Set("client_id", test.clientID)
   1.483 +		body := bytes.NewBufferString(params.Encode())
   1.484 +		r.Body = ioutil.NopCloser(body)
   1.485 +		respID, success := verifyClient(w, r, test.allowPublic, context)
   1.486 +		if (respID == nil && test.expectedClientID != nil) || (respID != nil && test.expectedClientID == nil) || !respID.Equal(test.expectedClientID) {
   1.487 +			t.Errorf("Expected response ID to be %v, got %v", test.expectedClientID, respID)
   1.488 +		}
   1.489 +		if test.expectedValid != success {
   1.490 +			t.Errorf("Expected success result to be %v, got %v", test.expectedValid, success)
   1.491 +		}
   1.492 +		if test.expectedCode != w.Code {
   1.493 +			t.Errorf("Expected response code to be %d, got %d", test.expectedCode, w.Code)
   1.494 +		}
   1.495 +		if test.expectedBody != strings.TrimSpace(w.Body.String()) {
   1.496 +			t.Errorf("Expected body to be '%s', got '%s'", test.expectedBody, strings.TrimSpace(w.Body.String()))
   1.497 +		}
   1.498 +		if test.expectAuthenticateHeader && w.Header().Get("WWW-Authenticate") != "Basic" {
   1.499 +			t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate"))
   1.500 +		}
   1.501  	}
   1.502  }
   1.503