auth
auth/client_test.go
Turn AddEndpoint into AddEndpoints. Because one is a special case of many, it makes sense to be able to add multiple endpoints in a single call to the database. So we've converted the AddEndpoint method into an AddEndpoints method and updated our tests appropriately. We also filled in the errors when creating a client through the API, and moved things around to optimize for the maximum number of errors returned in a single call.
| paddy@31 | 1 package auth |
| paddy@31 | 2 |
| paddy@31 | 3 import ( |
| paddy@113 | 4 "bytes" |
| paddy@39 | 5 "fmt" |
| paddy@113 | 6 "io/ioutil" |
| paddy@113 | 7 "net/http" |
| paddy@113 | 8 "net/http/httptest" |
| paddy@41 | 9 "net/url" |
| paddy@82 | 10 "sort" |
| paddy@113 | 11 "strings" |
| paddy@31 | 12 "testing" |
| paddy@41 | 13 "time" |
| paddy@31 | 14 |
| paddy@107 | 15 "code.secondbit.org/uuid.hg" |
| paddy@31 | 16 ) |
| paddy@31 | 17 |
| paddy@39 | 18 const ( |
| paddy@39 | 19 clientChangeSecret = 1 << iota |
| paddy@39 | 20 clientChangeOwnerID |
| paddy@39 | 21 clientChangeName |
| paddy@39 | 22 clientChangeLogo |
| paddy@39 | 23 clientChangeWebsite |
| paddy@39 | 24 ) |
| paddy@39 | 25 |
| paddy@57 | 26 var clientStores = []clientStore{NewMemstore()} |
| paddy@31 | 27 |
| paddy@33 | 28 func compareClients(client1, client2 Client) (success bool, field string, val1, val2 interface{}) { |
| paddy@33 | 29 if !client1.ID.Equal(client2.ID) { |
| paddy@33 | 30 return false, "ID", client1.ID, client2.ID |
| paddy@33 | 31 } |
| paddy@33 | 32 if client1.Secret != client2.Secret { |
| paddy@33 | 33 return false, "secret", client1.Secret, client2.Secret |
| paddy@33 | 34 } |
| paddy@33 | 35 if !client1.OwnerID.Equal(client2.OwnerID) { |
| paddy@33 | 36 return false, "owner ID", client1.OwnerID, client2.OwnerID |
| paddy@33 | 37 } |
| paddy@33 | 38 if client1.Name != client2.Name { |
| paddy@33 | 39 return false, "name", client1.Name, client2.Name |
| paddy@33 | 40 } |
| paddy@33 | 41 if client1.Logo != client2.Logo { |
| paddy@33 | 42 return false, "logo", client1.Logo, client2.Logo |
| paddy@33 | 43 } |
| paddy@33 | 44 if client1.Website != client2.Website { |
| paddy@33 | 45 return false, "website", client1.Website, client2.Website |
| paddy@33 | 46 } |
| paddy@41 | 47 if client1.Type != client2.Type { |
| paddy@41 | 48 return false, "type", client1.Type, client2.Type |
| paddy@41 | 49 } |
| paddy@41 | 50 return true, "", nil, nil |
| paddy@41 | 51 } |
| paddy@41 | 52 |
| paddy@41 | 53 func compareEndpoints(endpoint1, endpoint2 Endpoint) (success bool, field string, val1, val2 interface{}) { |
| paddy@41 | 54 if !endpoint1.ID.Equal(endpoint2.ID) { |
| paddy@41 | 55 return false, "ID", endpoint1.ID, endpoint2.ID |
| paddy@41 | 56 } |
| paddy@41 | 57 if !endpoint1.ClientID.Equal(endpoint2.ClientID) { |
| paddy@41 | 58 return false, "OwnerID", endpoint1.ClientID, endpoint2.ClientID |
| paddy@41 | 59 } |
| paddy@41 | 60 if !endpoint1.Added.Equal(endpoint2.Added) { |
| paddy@41 | 61 return false, "Added", endpoint1.Added, endpoint2.Added |
| paddy@41 | 62 } |
| paddy@41 | 63 if endpoint1.URI.String() != endpoint2.URI.String() { |
| paddy@41 | 64 return false, "URI", endpoint1.URI, endpoint2.URI |
| paddy@41 | 65 } |
| paddy@33 | 66 return true, "", nil, nil |
| paddy@33 | 67 } |
| paddy@33 | 68 |
| paddy@31 | 69 func TestClientStoreSuccess(t *testing.T) { |
| paddy@36 | 70 t.Parallel() |
| paddy@31 | 71 client := Client{ |
| paddy@41 | 72 ID: uuid.NewID(), |
| paddy@41 | 73 Secret: "secret", |
| paddy@41 | 74 OwnerID: uuid.NewID(), |
| paddy@41 | 75 Name: "name", |
| paddy@41 | 76 Logo: "logo", |
| paddy@41 | 77 Website: "website", |
| paddy@31 | 78 } |
| paddy@31 | 79 for _, store := range clientStores { |
| paddy@57 | 80 err := store.saveClient(client) |
| paddy@31 | 81 if err != nil { |
| paddy@41 | 82 t.Fatalf("Error saving client to %T: %s", store, err) |
| paddy@31 | 83 } |
| paddy@57 | 84 err = store.saveClient(client) |
| paddy@33 | 85 if err != ErrClientAlreadyExists { |
| paddy@41 | 86 t.Fatalf("Expected ErrClientAlreadyExists, got %v from %T", err, store) |
| paddy@33 | 87 } |
| paddy@57 | 88 retrieved, err := store.getClient(client.ID) |
| paddy@31 | 89 if err != nil { |
| paddy@41 | 90 t.Fatalf("Error retrieving client from %T: %s", store, err) |
| paddy@31 | 91 } |
| paddy@33 | 92 success, field, expectation, result := compareClients(client, retrieved) |
| paddy@33 | 93 if !success { |
| paddy@41 | 94 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@33 | 95 } |
| paddy@57 | 96 clients, err := store.listClientsByOwner(client.OwnerID, 25, 0) |
| paddy@31 | 97 if err != nil { |
| paddy@41 | 98 t.Fatalf("Error retrieving clients by owner from %T: %s", store, err) |
| paddy@31 | 99 } |
| paddy@31 | 100 if len(clients) != 1 { |
| paddy@41 | 101 t.Fatalf("Expected 1 client in response from %T, got %+v", store, clients) |
| paddy@31 | 102 } |
| paddy@33 | 103 success, field, expectation, result = compareClients(client, clients[0]) |
| paddy@33 | 104 if !success { |
| paddy@41 | 105 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@33 | 106 } |
| paddy@57 | 107 err = store.deleteClient(client.ID) |
| paddy@31 | 108 if err != nil { |
| paddy@41 | 109 t.Fatalf("Error deleting client from %T: %s", store, err) |
| paddy@31 | 110 } |
| paddy@57 | 111 err = store.deleteClient(client.ID) |
| paddy@33 | 112 if err != ErrClientNotFound { |
| paddy@41 | 113 t.Fatalf("Expected ErrClientNotFound, got %s from %T", err, store) |
| paddy@33 | 114 } |
| paddy@57 | 115 retrieved, err = store.getClient(client.ID) |
| paddy@31 | 116 if err != ErrClientNotFound { |
| paddy@41 | 117 t.Fatalf("Expected ErrClientNotFound from %T, got %+v and %s", store, retrieved, err) |
| paddy@31 | 118 } |
| paddy@57 | 119 clients, err = store.listClientsByOwner(client.OwnerID, 25, 0) |
| paddy@31 | 120 if err != nil { |
| paddy@41 | 121 t.Fatalf("Error listing clients by owner from %T: %s", store, err) |
| paddy@31 | 122 } |
| paddy@31 | 123 if len(clients) != 0 { |
| paddy@41 | 124 t.Fatalf("Expected 0 clients in response from %T, got %+v", store, clients) |
| paddy@41 | 125 } |
| paddy@41 | 126 } |
| paddy@41 | 127 } |
| paddy@41 | 128 |
| paddy@41 | 129 func TestEndpointStoreSuccess(t *testing.T) { |
| paddy@41 | 130 t.Parallel() |
| paddy@41 | 131 client := Client{ |
| paddy@41 | 132 ID: uuid.NewID(), |
| paddy@41 | 133 Secret: "secret", |
| paddy@41 | 134 OwnerID: uuid.NewID(), |
| paddy@41 | 135 Name: "name", |
| paddy@41 | 136 Logo: "logo", |
| paddy@41 | 137 Website: "website", |
| paddy@41 | 138 } |
| paddy@41 | 139 uri1, _ := url.Parse("https://www.example.com/") |
| paddy@41 | 140 uri2, _ := url.Parse("https://www.example.com/my/full/path") |
| paddy@41 | 141 endpoint1 := Endpoint{ |
| paddy@41 | 142 ID: uuid.NewID(), |
| paddy@41 | 143 ClientID: client.ID, |
| paddy@41 | 144 Added: time.Now(), |
| paddy@41 | 145 URI: *uri1, |
| paddy@41 | 146 } |
| paddy@41 | 147 endpoint2 := Endpoint{ |
| paddy@41 | 148 ID: uuid.NewID(), |
| paddy@41 | 149 ClientID: client.ID, |
| paddy@41 | 150 Added: time.Now(), |
| paddy@41 | 151 URI: *uri2, |
| paddy@41 | 152 } |
| paddy@41 | 153 for _, store := range clientStores { |
| paddy@57 | 154 err := store.saveClient(client) |
| paddy@41 | 155 if err != nil { |
| paddy@41 | 156 t.Fatalf("Error saving client to %T: %s", store, err) |
| paddy@41 | 157 } |
| paddy@115 | 158 err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) |
| paddy@41 | 159 if err != nil { |
| paddy@41 | 160 t.Fatalf("Error adding endpoint to client in %T: %s", store, err) |
| paddy@41 | 161 } |
| paddy@57 | 162 endpoints, err := store.listEndpoints(client.ID, 10, 0) |
| paddy@41 | 163 if err != nil { |
| paddy@41 | 164 t.Fatalf("Error retrieving endpoints from %T: %s", store, err) |
| paddy@41 | 165 } |
| paddy@41 | 166 if len(endpoints) != 1 { |
| paddy@41 | 167 t.Fatalf("Expected %d endpoints, got %+v from %T", 1, endpoints, store) |
| paddy@41 | 168 } |
| paddy@41 | 169 success, field, expectation, result := compareEndpoints(endpoint1, endpoints[0]) |
| paddy@41 | 170 if !success { |
| paddy@41 | 171 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@41 | 172 } |
| paddy@115 | 173 err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) |
| paddy@41 | 174 if err != nil { |
| paddy@41 | 175 t.Fatalf("Error adding endpoint to client in %T: %s", store, err) |
| paddy@41 | 176 } |
| paddy@57 | 177 endpoints, err = store.listEndpoints(client.ID, 10, 0) |
| paddy@41 | 178 if err != nil { |
| paddy@41 | 179 t.Fatalf("Error retrieving endpoints from %T: %s", store, err) |
| paddy@41 | 180 } |
| paddy@41 | 181 if len(endpoints) != 2 { |
| paddy@41 | 182 t.Fatalf("Expected %d endpoints, got %+v from %T", 2, endpoints, store) |
| paddy@41 | 183 } |
| paddy@41 | 184 sortedEnd := sortedEndpoints(endpoints) |
| paddy@41 | 185 sort.Sort(sortedEnd) |
| paddy@41 | 186 endpoints = []Endpoint(sortedEnd) |
| paddy@41 | 187 success, field, expectation, result = compareEndpoints(endpoint1, endpoints[0]) |
| paddy@41 | 188 if !success { |
| paddy@41 | 189 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@41 | 190 } |
| paddy@41 | 191 success, field, expectation, result = compareEndpoints(endpoint2, endpoints[1]) |
| paddy@41 | 192 if !success { |
| paddy@41 | 193 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@41 | 194 } |
| paddy@57 | 195 err = store.removeEndpoint(client.ID, endpoint1.ID) |
| paddy@41 | 196 if err != nil { |
| paddy@41 | 197 t.Fatalf("Error removing endpoint from client in %T: %s", store, err) |
| paddy@41 | 198 } |
| paddy@57 | 199 endpoints, err = store.listEndpoints(client.ID, 10, 0) |
| paddy@41 | 200 if err != nil { |
| paddy@41 | 201 t.Fatalf("Error listing endpoints in %T: %s", store, err) |
| paddy@41 | 202 } |
| paddy@41 | 203 if len(endpoints) != 1 { |
| paddy@41 | 204 t.Fatalf("Expected %d endpoints, got %+v from %T", 1, endpoints, store) |
| paddy@41 | 205 } |
| paddy@41 | 206 success, field, expectation, result = compareEndpoints(endpoint2, endpoints[0]) |
| paddy@41 | 207 if !success { |
| paddy@41 | 208 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) |
| paddy@41 | 209 } |
| paddy@57 | 210 err = store.removeEndpoint(client.ID, endpoint2.ID) |
| paddy@41 | 211 if err != nil { |
| paddy@41 | 212 t.Fatalf("Error removing endpoint from client in %T: %s", store, err) |
| paddy@41 | 213 } |
| paddy@57 | 214 endpoints, err = store.listEndpoints(client.ID, 10, 0) |
| paddy@41 | 215 if err != nil { |
| paddy@41 | 216 t.Fatalf("Error listing endpoints in %T: %s", store, err) |
| paddy@41 | 217 } |
| paddy@41 | 218 if len(endpoints) != 0 { |
| paddy@41 | 219 t.Fatalf("Expected %d endpoints, got %+v from %T", 0, endpoints, store) |
| paddy@31 | 220 } |
| paddy@31 | 221 } |
| paddy@31 | 222 } |
| paddy@39 | 223 |
| paddy@39 | 224 func TestClientUpdates(t *testing.T) { |
| paddy@39 | 225 t.Parallel() |
| paddy@41 | 226 variations := 1 << 5 |
| paddy@39 | 227 client := Client{ |
| paddy@41 | 228 ID: uuid.NewID(), |
| paddy@41 | 229 Secret: "secret", |
| paddy@41 | 230 OwnerID: uuid.NewID(), |
| paddy@41 | 231 Name: "name", |
| paddy@41 | 232 Logo: "logo", |
| paddy@41 | 233 Website: "website", |
| paddy@39 | 234 } |
| paddy@39 | 235 for i := 0; i < variations; i++ { |
| paddy@41 | 236 var secret, name, logo, website string |
| paddy@39 | 237 change := ClientChange{} |
| paddy@39 | 238 expectation := client |
| paddy@39 | 239 result := client |
| paddy@39 | 240 if i&clientChangeSecret != 0 { |
| paddy@39 | 241 secret = fmt.Sprintf("secret-%d", i) |
| paddy@39 | 242 change.Secret = &secret |
| paddy@39 | 243 expectation.Secret = secret |
| paddy@39 | 244 } |
| paddy@39 | 245 if i&clientChangeOwnerID != 0 { |
| paddy@39 | 246 change.OwnerID = uuid.NewID() |
| paddy@39 | 247 expectation.OwnerID = change.OwnerID |
| paddy@39 | 248 } |
| paddy@39 | 249 if i&clientChangeName != 0 { |
| paddy@39 | 250 name = fmt.Sprintf("name-%d", i) |
| paddy@39 | 251 change.Name = &name |
| paddy@39 | 252 expectation.Name = name |
| paddy@39 | 253 } |
| paddy@39 | 254 if i&clientChangeLogo != 0 { |
| paddy@39 | 255 logo = fmt.Sprintf("logo-%d", i) |
| paddy@39 | 256 change.Logo = &logo |
| paddy@39 | 257 expectation.Logo = logo |
| paddy@39 | 258 } |
| paddy@39 | 259 if i&clientChangeWebsite != 0 { |
| paddy@39 | 260 website = fmt.Sprintf("website-%d", i) |
| paddy@39 | 261 change.Website = &website |
| paddy@39 | 262 expectation.Website = website |
| paddy@39 | 263 } |
| paddy@39 | 264 result.ApplyChange(change) |
| paddy@39 | 265 match, field, expected, got := compareClients(expectation, result) |
| paddy@39 | 266 if !match { |
| paddy@41 | 267 t.Fatalf("Expected field `%s` to be `%v`, got `%v`", field, expected, got) |
| paddy@39 | 268 } |
| paddy@39 | 269 for _, store := range clientStores { |
| paddy@57 | 270 err := store.saveClient(client) |
| paddy@39 | 271 if err != nil { |
| paddy@41 | 272 t.Fatalf("Error saving client in %T: %s", store, err) |
| paddy@39 | 273 } |
| paddy@57 | 274 err = store.updateClient(client.ID, change) |
| paddy@39 | 275 if err != nil { |
| paddy@41 | 276 t.Fatalf("Error updating client in %T: %s", store, err) |
| paddy@39 | 277 } |
| paddy@57 | 278 retrieved, err := store.getClient(client.ID) |
| paddy@39 | 279 if err != nil { |
| paddy@41 | 280 t.Fatalf("Error getting profile from %T: %s", store, err) |
| paddy@39 | 281 } |
| paddy@39 | 282 match, field, expected, got = compareClients(expectation, retrieved) |
| paddy@39 | 283 if !match { |
| paddy@41 | 284 t.Fatalf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store) |
| paddy@39 | 285 } |
| paddy@57 | 286 err = store.deleteClient(client.ID) |
| paddy@39 | 287 if err != nil { |
| paddy@41 | 288 t.Fatalf("Error deleting client from %T: %s", store, err) |
| paddy@39 | 289 } |
| paddy@57 | 290 err = store.updateClient(client.ID, change) |
| paddy@39 | 291 if err != ErrClientNotFound { |
| paddy@41 | 292 t.Fatalf("Expected ErrClientNotFound, got %v from %T", err, store) |
| paddy@39 | 293 } |
| paddy@39 | 294 } |
| paddy@39 | 295 } |
| paddy@39 | 296 } |
| paddy@41 | 297 |
| paddy@41 | 298 func TestClientEndpointChecks(t *testing.T) { |
| paddy@41 | 299 t.Parallel() |
| paddy@41 | 300 client := Client{ |
| paddy@41 | 301 ID: uuid.NewID(), |
| paddy@41 | 302 Secret: "secret", |
| paddy@41 | 303 OwnerID: uuid.NewID(), |
| paddy@41 | 304 Name: "name", |
| paddy@41 | 305 Logo: "logo", |
| paddy@41 | 306 Website: "website", |
| paddy@41 | 307 } |
| paddy@41 | 308 uri1, _ := url.Parse("https://www.example.com/first") |
| paddy@41 | 309 uri2, _ := url.Parse("https://www.example.com/my/full/path") |
| paddy@41 | 310 endpoint1 := Endpoint{ |
| paddy@41 | 311 ID: uuid.NewID(), |
| paddy@41 | 312 ClientID: client.ID, |
| paddy@41 | 313 Added: time.Now(), |
| paddy@41 | 314 URI: *uri1, |
| paddy@41 | 315 } |
| paddy@41 | 316 endpoint2 := Endpoint{ |
| paddy@41 | 317 ID: uuid.NewID(), |
| paddy@41 | 318 ClientID: client.ID, |
| paddy@41 | 319 Added: time.Now(), |
| paddy@41 | 320 URI: *uri2, |
| paddy@41 | 321 } |
| paddy@41 | 322 candidates := map[string]bool{ |
| paddy@41 | 323 "https://www.example.com/": false, |
| paddy@41 | 324 "https://www.example.com/first": true, |
| paddy@58 | 325 "https://www.example.com/first/extra/path": false, |
| paddy@41 | 326 "https://www.example.com/my": false, |
| paddy@41 | 327 "https://www.example.com/my/full/path": true, |
| paddy@41 | 328 } |
| paddy@41 | 329 for _, store := range clientStores { |
| paddy@57 | 330 err := store.saveClient(client) |
| paddy@41 | 331 if err != nil { |
| paddy@41 | 332 t.Fatalf("Error saving client in %T: %s", store, err) |
| paddy@41 | 333 } |
| paddy@115 | 334 err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) |
| paddy@41 | 335 if err != nil { |
| paddy@41 | 336 t.Fatalf("Error saving endpoint in %T: %s", store, err) |
| paddy@41 | 337 } |
| paddy@115 | 338 err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) |
| paddy@41 | 339 if err != nil { |
| paddy@41 | 340 t.Fatalf("Error saving endpoint in %T: %s", store, err) |
| paddy@41 | 341 } |
| paddy@41 | 342 for candidate, expectation := range candidates { |
| paddy@58 | 343 result, err := store.checkEndpoint(client.ID, candidate) |
| paddy@54 | 344 if err != nil { |
| paddy@54 | 345 t.Fatalf("Error checking endpoint %s in %T: %s", candidate, store, err) |
| paddy@54 | 346 } |
| paddy@54 | 347 if result != expectation { |
| paddy@54 | 348 expectStr := "no" |
| paddy@54 | 349 resultStr := "a" |
| paddy@54 | 350 if expectation { |
| paddy@54 | 351 expectStr = "a" |
| paddy@54 | 352 resultStr = "no" |
| paddy@54 | 353 } |
| paddy@54 | 354 t.Errorf("Expected %s match for %s in %T, got %s match", expectStr, candidate, store, resultStr) |
| paddy@54 | 355 } |
| paddy@54 | 356 } |
| paddy@54 | 357 } |
| paddy@54 | 358 } |
| paddy@54 | 359 |
| paddy@54 | 360 func TestClientEndpointChecksStrict(t *testing.T) { |
| paddy@54 | 361 t.Parallel() |
| paddy@54 | 362 client := Client{ |
| paddy@54 | 363 ID: uuid.NewID(), |
| paddy@54 | 364 Secret: "secret", |
| paddy@54 | 365 OwnerID: uuid.NewID(), |
| paddy@54 | 366 Name: "name", |
| paddy@54 | 367 Logo: "logo", |
| paddy@54 | 368 Website: "website", |
| paddy@54 | 369 } |
| paddy@54 | 370 uri1, _ := url.Parse("https://www.example.com/first") |
| paddy@54 | 371 uri2, _ := url.Parse("https://www.example.com/my/full/path") |
| paddy@54 | 372 endpoint1 := Endpoint{ |
| paddy@54 | 373 ID: uuid.NewID(), |
| paddy@54 | 374 ClientID: client.ID, |
| paddy@54 | 375 Added: time.Now(), |
| paddy@54 | 376 URI: *uri1, |
| paddy@54 | 377 } |
| paddy@54 | 378 endpoint2 := Endpoint{ |
| paddy@54 | 379 ID: uuid.NewID(), |
| paddy@54 | 380 ClientID: client.ID, |
| paddy@54 | 381 Added: time.Now(), |
| paddy@54 | 382 URI: *uri2, |
| paddy@54 | 383 } |
| paddy@54 | 384 candidates := map[string]bool{ |
| paddy@54 | 385 "https://www.example.com/": false, |
| paddy@54 | 386 "https://www.example.com/first": true, |
| paddy@54 | 387 "https://www.example.com/first/extra/path": false, |
| paddy@54 | 388 "https://www.example.com/my": false, |
| paddy@54 | 389 "https://www.example.com/my/full/path": true, |
| paddy@54 | 390 } |
| paddy@54 | 391 for _, store := range clientStores { |
| paddy@57 | 392 err := store.saveClient(client) |
| paddy@54 | 393 if err != nil { |
| paddy@54 | 394 t.Fatalf("Error saving client in %T: %s", store, err) |
| paddy@54 | 395 } |
| paddy@115 | 396 err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) |
| paddy@54 | 397 if err != nil { |
| paddy@54 | 398 t.Fatalf("Error saving endpoint in %T: %s", store, err) |
| paddy@54 | 399 } |
| paddy@115 | 400 err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) |
| paddy@54 | 401 if err != nil { |
| paddy@54 | 402 t.Fatalf("Error saving endpoint in %T: %s", store, err) |
| paddy@54 | 403 } |
| paddy@54 | 404 for candidate, expectation := range candidates { |
| paddy@58 | 405 result, err := store.checkEndpoint(client.ID, candidate) |
| paddy@41 | 406 if err != nil { |
| paddy@41 | 407 t.Fatalf("Error checking endpoint %s in %T: %s", candidate, store, err) |
| paddy@41 | 408 } |
| paddy@41 | 409 if result != expectation { |
| paddy@41 | 410 expectStr := "no" |
| paddy@41 | 411 resultStr := "a" |
| paddy@41 | 412 if expectation { |
| paddy@41 | 413 expectStr = "a" |
| paddy@41 | 414 resultStr = "no" |
| paddy@41 | 415 } |
| paddy@41 | 416 t.Errorf("Expected %s match for %s in %T, got %s match", expectStr, candidate, store, resultStr) |
| paddy@41 | 417 } |
| paddy@41 | 418 } |
| paddy@41 | 419 } |
| paddy@41 | 420 } |
| paddy@43 | 421 |
| paddy@43 | 422 func TestClientChangeValidation(t *testing.T) { |
| paddy@43 | 423 t.Parallel() |
| paddy@43 | 424 change := ClientChange{} |
| paddy@43 | 425 if err := change.Validate(); err != ErrEmptyChange { |
| paddy@43 | 426 t.Errorf("Expected %s to give an error of %s, gave %s", "empty change", ErrEmptyChange, err) |
| paddy@43 | 427 } |
| paddy@43 | 428 names := map[string]error{ |
| paddy@43 | 429 "a": ErrClientNameTooShort, |
| paddy@43 | 430 "ab": nil, |
| paddy@43 | 431 "abc": nil, |
| paddy@43 | 432 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopq": ErrClientNameTooLong, |
| paddy@43 | 433 } |
| paddy@43 | 434 for name, expectation := range names { |
| paddy@43 | 435 change = ClientChange{Name: &name} |
| paddy@43 | 436 if err := change.Validate(); err != expectation { |
| paddy@43 | 437 t.Errorf("Expected %s to give an error of %s, gave %s", name, expectation, err) |
| paddy@43 | 438 } |
| paddy@43 | 439 } |
| paddy@43 | 440 longPath := "" |
| paddy@43 | 441 for i := 0; i < 1025; i++ { |
| paddy@43 | 442 longPath = fmt.Sprintf("%s%d", longPath, i) |
| paddy@43 | 443 } |
| paddy@43 | 444 logos := map[string]error{ |
| paddy@43 | 445 "https://www.example.com/" + longPath: ErrClientLogoTooLong, |
| paddy@43 | 446 "https://www.example.com/ab": nil, |
| paddy@43 | 447 "www.example.com/ab": ErrClientLogoNotURL, |
| paddy@43 | 448 "test": ErrClientLogoNotURL, |
| paddy@43 | 449 "": nil, |
| paddy@43 | 450 } |
| paddy@43 | 451 for logo, expectation := range logos { |
| paddy@43 | 452 change = ClientChange{Logo: &logo} |
| paddy@43 | 453 if err := change.Validate(); err != expectation { |
| paddy@43 | 454 t.Errorf("Expected %s to give an error of %s, gave %s", logo, expectation, err) |
| paddy@43 | 455 } |
| paddy@43 | 456 } |
| paddy@43 | 457 websites := map[string]error{ |
| paddy@43 | 458 "https://www.example.com/" + longPath: ErrClientWebsiteTooLong, |
| paddy@43 | 459 "https://www.example.com/ab": nil, |
| paddy@43 | 460 "www.example.com/ab": ErrClientWebsiteNotURL, |
| paddy@43 | 461 "test": ErrClientWebsiteNotURL, |
| paddy@43 | 462 "": nil, |
| paddy@43 | 463 } |
| paddy@43 | 464 for website, expectation := range websites { |
| paddy@43 | 465 change = ClientChange{Website: &website} |
| paddy@43 | 466 if err := change.Validate(); err != expectation { |
| paddy@43 | 467 t.Errorf("Expected %s to give an error of %s, gave %s", website, expectation, err) |
| paddy@43 | 468 } |
| paddy@43 | 469 } |
| paddy@43 | 470 } |
| paddy@113 | 471 |
| paddy@113 | 472 func TestVerifyClient(t *testing.T) { |
| paddy@113 | 473 t.Parallel() |
| paddy@113 | 474 memstore := NewMemstore() |
| paddy@113 | 475 context := Context{ |
| paddy@113 | 476 clients: memstore, |
| paddy@113 | 477 } |
| paddy@113 | 478 client := Client{ |
| paddy@113 | 479 ID: uuid.NewID(), |
| paddy@113 | 480 Secret: "super secret!", |
| paddy@113 | 481 OwnerID: uuid.NewID(), |
| paddy@113 | 482 Name: "My test client", |
| paddy@113 | 483 Logo: "https://secondbit.org/logo.png", |
| paddy@113 | 484 Website: "https://secondbit.org/", |
| paddy@113 | 485 Type: "confidential", |
| paddy@113 | 486 } |
| paddy@113 | 487 err := context.SaveClient(client) |
| paddy@113 | 488 if err != nil { |
| paddy@113 | 489 t.Fatal("Could not save client:", err) |
| paddy@113 | 490 } |
| paddy@113 | 491 publicClient := Client{ |
| paddy@113 | 492 ID: uuid.NewID(), |
| paddy@113 | 493 Secret: "", |
| paddy@113 | 494 OwnerID: uuid.NewID(), |
| paddy@113 | 495 Name: "A public client", |
| paddy@113 | 496 Logo: "https://secondbit.org/logo.png", |
| paddy@113 | 497 Website: "https://secondbit.org/", |
| paddy@113 | 498 Type: "public", |
| paddy@113 | 499 } |
| paddy@113 | 500 err = context.SaveClient(publicClient) |
| paddy@113 | 501 if err != nil { |
| paddy@113 | 502 t.Fatal("Could not save client:", err) |
| paddy@113 | 503 } |
| paddy@113 | 504 |
| paddy@113 | 505 // verifyClient with no auth header, no public clients |
| paddy@113 | 506 w := httptest.NewRecorder() |
| paddy@113 | 507 r, err := http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 508 if err != nil { |
| paddy@113 | 509 t.Fatal("Can't build request:", err) |
| paddy@113 | 510 } |
| paddy@113 | 511 resp, success := verifyClient(w, r, false, context) |
| paddy@113 | 512 if success { |
| paddy@113 | 513 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 514 } |
| paddy@113 | 515 if resp != nil { |
| paddy@113 | 516 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 517 } |
| paddy@113 | 518 if w.Code != http.StatusBadRequest { |
| paddy@113 | 519 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 520 } |
| paddy@113 | 521 expectedBody := `{"error":"unauthorized_client"}` |
| paddy@113 | 522 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 523 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 524 } |
| paddy@113 | 525 |
| paddy@113 | 526 // verifyClient with no auth header, public clients, empty client_id |
| paddy@113 | 527 w = httptest.NewRecorder() |
| paddy@113 | 528 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 529 if err != nil { |
| paddy@113 | 530 t.Fatal("Can't build request:", err) |
| paddy@113 | 531 } |
| paddy@113 | 532 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 533 if success { |
| paddy@113 | 534 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 535 } |
| paddy@113 | 536 if resp != nil { |
| paddy@113 | 537 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 538 } |
| paddy@113 | 539 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 540 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 541 } |
| paddy@113 | 542 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 543 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 544 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 545 } |
| paddy@113 | 546 |
| paddy@113 | 547 // verifyClient with auth header, no public clients, empty client id |
| paddy@113 | 548 w = httptest.NewRecorder() |
| paddy@113 | 549 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 550 if err != nil { |
| paddy@113 | 551 t.Fatal("Can't build request:", err) |
| paddy@113 | 552 } |
| paddy@113 | 553 r.SetBasicAuth("", "no client ID set") |
| paddy@113 | 554 resp, success = verifyClient(w, r, false, context) |
| paddy@113 | 555 if success { |
| paddy@113 | 556 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 557 } |
| paddy@113 | 558 if resp != nil { |
| paddy@113 | 559 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 560 } |
| paddy@113 | 561 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 562 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 563 } |
| paddy@113 | 564 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 565 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 566 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 567 } |
| paddy@113 | 568 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 569 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 570 } |
| paddy@113 | 571 |
| paddy@113 | 572 // verifyClient with auth header, public clients, empty client id |
| paddy@113 | 573 w = httptest.NewRecorder() |
| paddy@113 | 574 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 575 if err != nil { |
| paddy@113 | 576 t.Fatal("Can't build request:", err) |
| paddy@113 | 577 } |
| paddy@113 | 578 r.SetBasicAuth("", "no client ID set") |
| paddy@113 | 579 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 580 if success { |
| paddy@113 | 581 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 582 } |
| paddy@113 | 583 if resp != nil { |
| paddy@113 | 584 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 585 } |
| paddy@113 | 586 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 587 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 588 } |
| paddy@113 | 589 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 590 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 591 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 592 } |
| paddy@113 | 593 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 594 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 595 } |
| paddy@113 | 596 |
| paddy@113 | 597 // verifyClient with auth header, no public clients, invalid client ID |
| paddy@113 | 598 w = httptest.NewRecorder() |
| paddy@113 | 599 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 600 if err != nil { |
| paddy@113 | 601 t.Fatal("Can't build request:", err) |
| paddy@113 | 602 } |
| paddy@113 | 603 r.SetBasicAuth("not an actual id", "invalid client ID set") |
| paddy@113 | 604 resp, success = verifyClient(w, r, false, context) |
| paddy@113 | 605 if success { |
| paddy@113 | 606 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 607 } |
| paddy@113 | 608 if resp != nil { |
| paddy@113 | 609 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 610 } |
| paddy@113 | 611 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 612 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 613 } |
| paddy@113 | 614 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 615 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 616 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 617 } |
| paddy@113 | 618 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 619 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 620 } |
| paddy@113 | 621 |
| paddy@113 | 622 // verifyClient with auth header, public clients, invalid client ID |
| paddy@113 | 623 w = httptest.NewRecorder() |
| paddy@113 | 624 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 625 if err != nil { |
| paddy@113 | 626 t.Fatal("Can't build request:", err) |
| paddy@113 | 627 } |
| paddy@113 | 628 r.SetBasicAuth("not an actual id", "invalid client ID set") |
| paddy@113 | 629 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 630 if success { |
| paddy@113 | 631 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 632 } |
| paddy@113 | 633 if resp != nil { |
| paddy@113 | 634 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 635 } |
| paddy@113 | 636 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 637 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 638 } |
| paddy@113 | 639 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 640 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 641 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 642 } |
| paddy@113 | 643 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 644 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 645 } |
| paddy@113 | 646 |
| paddy@113 | 647 // verifyClient with auth header, no public clients, client ID valid but not in clientStore |
| paddy@113 | 648 w = httptest.NewRecorder() |
| paddy@113 | 649 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 650 if err != nil { |
| paddy@113 | 651 t.Fatal("Can't build request:", err) |
| paddy@113 | 652 } |
| paddy@113 | 653 r.SetBasicAuth(uuid.NewID().String(), "non existent client ID set") |
| paddy@113 | 654 resp, success = verifyClient(w, r, false, context) |
| paddy@113 | 655 if success { |
| paddy@113 | 656 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 657 } |
| paddy@113 | 658 if resp != nil { |
| paddy@113 | 659 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 660 } |
| paddy@113 | 661 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 662 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 663 } |
| paddy@113 | 664 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 665 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 666 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 667 } |
| paddy@113 | 668 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 669 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 670 } |
| paddy@113 | 671 |
| paddy@113 | 672 // verifyClient with auth header, public clients, client ID valid but not in clientStore |
| paddy@113 | 673 w = httptest.NewRecorder() |
| paddy@113 | 674 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 675 if err != nil { |
| paddy@113 | 676 t.Fatal("Can't build request:", err) |
| paddy@113 | 677 } |
| paddy@113 | 678 r.SetBasicAuth(uuid.NewID().String(), "non existent client ID set") |
| paddy@113 | 679 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 680 if success { |
| paddy@113 | 681 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 682 } |
| paddy@113 | 683 if resp != nil { |
| paddy@113 | 684 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 685 } |
| paddy@113 | 686 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 687 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 688 } |
| paddy@113 | 689 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 690 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 691 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 692 } |
| paddy@113 | 693 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 694 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 695 } |
| paddy@113 | 696 |
| paddy@113 | 697 // verifyClient with auth header, no public clients, client secret wrong |
| paddy@113 | 698 w = httptest.NewRecorder() |
| paddy@113 | 699 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 700 if err != nil { |
| paddy@113 | 701 t.Fatal("Can't build request:", err) |
| paddy@113 | 702 } |
| paddy@113 | 703 r.SetBasicAuth(client.ID.String(), "not actually the secret") |
| paddy@113 | 704 resp, success = verifyClient(w, r, false, context) |
| paddy@113 | 705 if success { |
| paddy@113 | 706 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 707 } |
| paddy@113 | 708 if resp != nil { |
| paddy@113 | 709 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 710 } |
| paddy@113 | 711 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 712 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 713 } |
| paddy@113 | 714 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 715 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 716 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 717 } |
| paddy@113 | 718 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 719 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 720 } |
| paddy@113 | 721 |
| paddy@113 | 722 // verifyClient with auth header, public clients, client secret wrong |
| paddy@113 | 723 w = httptest.NewRecorder() |
| paddy@113 | 724 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 725 if err != nil { |
| paddy@113 | 726 t.Fatal("Can't build request:", err) |
| paddy@113 | 727 } |
| paddy@113 | 728 r.SetBasicAuth(client.ID.String(), "not actually the secret") |
| paddy@113 | 729 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 730 if success { |
| paddy@113 | 731 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 732 } |
| paddy@113 | 733 if resp != nil { |
| paddy@113 | 734 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 735 } |
| paddy@113 | 736 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 737 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 738 } |
| paddy@113 | 739 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 740 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 741 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 742 } |
| paddy@113 | 743 if w.Header().Get("WWW-Authenticate") != "Basic" { |
| paddy@113 | 744 t.Errorf(`Expected header WWW-Authenticate to be set to "Basic", got "%s"`, w.Header().Get("WWW-Authenticate")) |
| paddy@113 | 745 } |
| paddy@113 | 746 |
| paddy@113 | 747 // verifyClient with no auth header, public clients, invalid client_id post form value |
| paddy@113 | 748 w = httptest.NewRecorder() |
| paddy@113 | 749 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 750 if err != nil { |
| paddy@113 | 751 t.Fatal("Can't build request:", err) |
| paddy@113 | 752 } |
| paddy@113 | 753 r.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| paddy@113 | 754 params := url.Values{} |
| paddy@113 | 755 params.Set("client_id", "not an actual id") |
| paddy@113 | 756 body := bytes.NewBufferString(params.Encode()) |
| paddy@113 | 757 r.Body = ioutil.NopCloser(body) |
| paddy@113 | 758 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 759 if success { |
| paddy@113 | 760 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 761 } |
| paddy@113 | 762 if resp != nil { |
| paddy@113 | 763 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 764 } |
| paddy@113 | 765 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 766 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 767 } |
| paddy@113 | 768 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 769 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 770 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 771 } |
| paddy@113 | 772 |
| paddy@113 | 773 // verifyClient with no auth header, public clients, client_id valid but not in clientStore |
| paddy@113 | 774 w = httptest.NewRecorder() |
| paddy@113 | 775 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 776 if err != nil { |
| paddy@113 | 777 t.Fatal("Can't build request:", err) |
| paddy@113 | 778 } |
| paddy@113 | 779 r.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| paddy@113 | 780 params = url.Values{} |
| paddy@113 | 781 params.Set("client_id", uuid.NewID().String()) |
| paddy@113 | 782 body = bytes.NewBufferString(params.Encode()) |
| paddy@113 | 783 r.Body = ioutil.NopCloser(body) |
| paddy@113 | 784 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 785 if success { |
| paddy@113 | 786 t.Error("Expected verification to fail, but succeeded with client ID:", resp) |
| paddy@113 | 787 } |
| paddy@113 | 788 if resp != nil { |
| paddy@113 | 789 t.Error("Expected nil client ID, got", resp) |
| paddy@113 | 790 } |
| paddy@113 | 791 if w.Code != http.StatusUnauthorized { |
| paddy@113 | 792 t.Errorf("Expected status code of %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@113 | 793 } |
| paddy@113 | 794 expectedBody = `{"error":"invalid_client"}` |
| paddy@113 | 795 if expectedBody != strings.TrimSpace(w.Body.String()) { |
| paddy@113 | 796 t.Errorf("Expected body of `%s`, got `%s`", expectedBody, strings.TrimSpace(w.Body.String())) |
| paddy@113 | 797 } |
| paddy@113 | 798 |
| paddy@113 | 799 // verifyClient with auth header, public clients, valid client_id and secret |
| paddy@113 | 800 w = httptest.NewRecorder() |
| paddy@113 | 801 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 802 if err != nil { |
| paddy@113 | 803 t.Fatal("Can't build request:", err) |
| paddy@113 | 804 } |
| paddy@113 | 805 r.SetBasicAuth(client.ID.String(), client.Secret) |
| paddy@113 | 806 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 807 if !success { |
| paddy@113 | 808 t.Error("Expected verification to succeed, but it failed") |
| paddy@113 | 809 } |
| paddy@113 | 810 if !client.ID.Equal(resp) { |
| paddy@113 | 811 t.Errorf("Expected client ID to be %s, got %s", client.ID, resp) |
| paddy@113 | 812 } |
| paddy@113 | 813 if w.Code != http.StatusOK { |
| paddy@113 | 814 t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code) |
| paddy@113 | 815 } |
| paddy@113 | 816 if w.Body.String() != "" { |
| paddy@113 | 817 t.Errorf(`Expected empty body, got "%s"`, w.Body.String()) |
| paddy@113 | 818 } |
| paddy@113 | 819 |
| paddy@113 | 820 // verifyClient with auth header, no public clients, valid client_id and secret |
| paddy@113 | 821 w = httptest.NewRecorder() |
| paddy@113 | 822 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 823 if err != nil { |
| paddy@113 | 824 t.Fatal("Can't build request:", err) |
| paddy@113 | 825 } |
| paddy@113 | 826 r.SetBasicAuth(client.ID.String(), client.Secret) |
| paddy@113 | 827 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 828 if !success { |
| paddy@113 | 829 t.Error("Expected verification to succeed, but it failed") |
| paddy@113 | 830 } |
| paddy@113 | 831 if !client.ID.Equal(resp) { |
| paddy@113 | 832 t.Errorf("Expected client ID to be %s, got %s", client.ID, resp) |
| paddy@113 | 833 } |
| paddy@113 | 834 if w.Code != http.StatusOK { |
| paddy@113 | 835 t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code) |
| paddy@113 | 836 } |
| paddy@113 | 837 if w.Body.String() != "" { |
| paddy@113 | 838 t.Errorf(`Expected empty body, got "%s"`, w.Body.String()) |
| paddy@113 | 839 } |
| paddy@113 | 840 |
| paddy@113 | 841 // verifyClient with no auth header, public clients, valid client_id and secret |
| paddy@113 | 842 w = httptest.NewRecorder() |
| paddy@113 | 843 r, err = http.NewRequest("POST", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@113 | 844 if err != nil { |
| paddy@113 | 845 t.Fatal("Can't build request:", err) |
| paddy@113 | 846 } |
| paddy@113 | 847 r.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| paddy@113 | 848 params = url.Values{} |
| paddy@113 | 849 params.Set("client_id", publicClient.ID.String()) |
| paddy@113 | 850 body = bytes.NewBufferString(params.Encode()) |
| paddy@113 | 851 r.Body = ioutil.NopCloser(body) |
| paddy@113 | 852 resp, success = verifyClient(w, r, true, context) |
| paddy@113 | 853 if !success { |
| paddy@113 | 854 t.Error("Expected verification to succeed, but it failed") |
| paddy@113 | 855 } |
| paddy@113 | 856 if !publicClient.ID.Equal(resp) { |
| paddy@113 | 857 t.Errorf("Expected client ID to be %s, got %s", publicClient.ID, resp) |
| paddy@113 | 858 } |
| paddy@113 | 859 if w.Code != http.StatusOK { |
| paddy@113 | 860 t.Errorf("Expected status code of %d, got %d", http.StatusOK, w.Code) |
| paddy@113 | 861 } |
| paddy@113 | 862 if w.Body.String() != "" { |
| paddy@113 | 863 t.Errorf(`Expected empty body, got "%s"`, w.Body.String()) |
| paddy@113 | 864 } |
| paddy@113 | 865 } |