auth
115:fa8ee6a4507c Browse Files
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.
authcode_test.go client.go client_test.go context.go oauth2_test.go
1.1 --- a/authcode_test.go Sat Jan 10 04:16:07 2015 -0500 1.2 +++ b/authcode_test.go Wed Jan 14 00:23:30 2015 -0500 1.3 @@ -139,7 +139,7 @@ 1.4 if err != nil { 1.5 t.Fatal("Can't store client:", err) 1.6 } 1.7 - err = testContext.AddEndpoint(client.ID, endpoint) 1.8 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint}) 1.9 if err != nil { 1.10 t.Fatal("Can't store endpoint:", err) 1.11 }
2.1 --- a/client.go Sat Jan 10 04:16:07 2015 -0500 2.2 +++ b/client.go Wed Jan 14 00:23:30 2015 -0500 2.3 @@ -8,6 +8,7 @@ 2.4 "github.com/gorilla/mux" 2.5 "net/http" 2.6 "net/url" 2.7 + "strconv" 2.8 "time" 2.9 2.10 "code.secondbit.org/uuid.hg" 2.11 @@ -38,6 +39,11 @@ 2.12 ErrClientWebsiteNotURL = errors.New("client website must be a valid absolute URL") 2.13 ) 2.14 2.15 +const ( 2.16 + clientTypePublic = "public" 2.17 + clientTypeConfidential = "confidential" 2.18 +) 2.19 + 2.20 // Client represents a client that grants access 2.21 // to the auth server, exchanging grants for tokens, 2.22 // and tokens for access. 2.23 @@ -190,7 +196,7 @@ 2.24 deleteClient(id uuid.ID) error 2.25 listClientsByOwner(ownerID uuid.ID, num, offset int) ([]Client, error) 2.26 2.27 - addEndpoint(client uuid.ID, endpoint Endpoint) error 2.28 + addEndpoints(client uuid.ID, endpoint []Endpoint) error 2.29 removeEndpoint(client, endpoint uuid.ID) error 2.30 checkEndpoint(client uuid.ID, endpoint string) (bool, error) 2.31 listEndpoints(client uuid.ID, num, offset int) ([]Endpoint, error) 2.32 @@ -271,10 +277,10 @@ 2.33 return clients, nil 2.34 } 2.35 2.36 -func (m *memstore) addEndpoint(client uuid.ID, endpoint Endpoint) error { 2.37 +func (m *memstore) addEndpoints(client uuid.ID, endpoints []Endpoint) error { 2.38 m.endpointLock.Lock() 2.39 defer m.endpointLock.Unlock() 2.40 - m.endpoints[client.String()] = append(m.endpoints[client.String()], endpoint) 2.41 + m.endpoints[client.String()] = append(m.endpoints[client.String()], endpoints...) 2.42 return nil 2.43 } 2.44 2.45 @@ -330,14 +336,17 @@ 2.46 } 2.47 2.48 func CreateClientHandler(w http.ResponseWriter, r *http.Request, c Context) { 2.49 + errors := []requestError{} 2.50 username, password, ok := r.BasicAuth() 2.51 if !ok { 2.52 - // TODO(paddy): return error 2.53 + errors = append(errors, requestError{Slug: requestErrAccessDenied}) 2.54 + encode(w, r, http.StatusUnauthorized, response{Errors: errors}) 2.55 return 2.56 } 2.57 profile, err := authenticate(username, password, c) 2.58 if err != nil { 2.59 - // TODO(paddy): return error 2.60 + errors = append(errors, requestError{Slug: requestErrAccessDenied}) 2.61 + encode(w, r, http.StatusUnauthorized, response{Errors: errors}) 2.62 return 2.63 } 2.64 var req newClientReq 2.65 @@ -347,31 +356,43 @@ 2.66 encode(w, r, http.StatusBadRequest, invalidFormatResponse) 2.67 return 2.68 } 2.69 - secret := make([]byte, 32) 2.70 - _, err = rand.Read(secret) 2.71 - if err != nil { 2.72 - // TODO(paddy): return error 2.73 + if req.Type != clientTypePublic && req.Type != clientTypeConfidential { 2.74 + errors = append(errors, requestError{Slug: requestErrInvalidValue, Field: "/type"}) 2.75 + encode(w, r, http.StatusBadRequest, response{Errors: errors}) 2.76 return 2.77 } 2.78 client := Client{ 2.79 ID: uuid.NewID(), 2.80 - Secret: hex.EncodeToString(secret), 2.81 OwnerID: profile.ID, 2.82 Name: req.Name, 2.83 Logo: req.Logo, 2.84 Website: req.Website, 2.85 Type: req.Type, 2.86 } 2.87 + if client.Type == clientTypePublic { 2.88 + secret := make([]byte, 32) 2.89 + _, err = rand.Read(secret) 2.90 + if err != nil { 2.91 + encode(w, r, http.StatusInternalServerError, actOfGodResponse) 2.92 + return 2.93 + } 2.94 + client.Secret = hex.EncodeToString(secret) 2.95 + } 2.96 err = c.SaveClient(client) 2.97 if err != nil { 2.98 - // TODO(paddy): return error 2.99 + if err == ErrClientAlreadyExists { 2.100 + errors = append(errors, requestError{Slug: requestErrConflict, Field: "/id"}) 2.101 + encode(w, r, http.StatusBadRequest, response{Errors: errors}) 2.102 + return 2.103 + } 2.104 + encode(w, r, http.StatusInternalServerError, actOfGodResponse) 2.105 return 2.106 } 2.107 endpoints := []Endpoint{} 2.108 - for _, u := range req.Endpoints { 2.109 + for pos, u := range req.Endpoints { 2.110 uri, err := url.Parse(u) 2.111 if err != nil { 2.112 - // TODO(paddy): add error to response 2.113 + errors = append(errors, requestError{Slug: requestErrInvalidFormat, Field: "/endpoints/" + strconv.Itoa(pos)}) 2.114 continue 2.115 } 2.116 endpoint := Endpoint{ 2.117 @@ -380,13 +401,14 @@ 2.118 URI: *uri, 2.119 Added: time.Now(), 2.120 } 2.121 - err = c.AddEndpoint(client.ID, endpoint) 2.122 - if err != nil { 2.123 - // TODO(paddy): return error 2.124 - return 2.125 - } 2.126 endpoints = append(endpoints, endpoint) 2.127 } 2.128 + err = c.AddEndpoints(client.ID, endpoints) 2.129 + if err != nil { 2.130 + errors = append(errors, requestError{Slug: requestErrActOfGod}) 2.131 + encode(w, r, http.StatusInternalServerError, response{Errors: errors, Clients: []Client{client}}) 2.132 + return 2.133 + } 2.134 resp := response{ 2.135 Clients: []Client{client}, 2.136 Endpoints: endpoints,
3.1 --- a/client_test.go Sat Jan 10 04:16:07 2015 -0500 3.2 +++ b/client_test.go Wed Jan 14 00:23:30 2015 -0500 3.3 @@ -155,7 +155,7 @@ 3.4 if err != nil { 3.5 t.Fatalf("Error saving client to %T: %s", store, err) 3.6 } 3.7 - err = store.addEndpoint(client.ID, endpoint1) 3.8 + err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) 3.9 if err != nil { 3.10 t.Fatalf("Error adding endpoint to client in %T: %s", store, err) 3.11 } 3.12 @@ -170,7 +170,7 @@ 3.13 if !success { 3.14 t.Fatalf("Expected field %s to be %v, but %T returned %v", field, expectation, store, result) 3.15 } 3.16 - err = store.addEndpoint(client.ID, endpoint2) 3.17 + err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) 3.18 if err != nil { 3.19 t.Fatalf("Error adding endpoint to client in %T: %s", store, err) 3.20 } 3.21 @@ -331,11 +331,11 @@ 3.22 if err != nil { 3.23 t.Fatalf("Error saving client in %T: %s", store, err) 3.24 } 3.25 - err = store.addEndpoint(client.ID, endpoint1) 3.26 + err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) 3.27 if err != nil { 3.28 t.Fatalf("Error saving endpoint in %T: %s", store, err) 3.29 } 3.30 - err = store.addEndpoint(client.ID, endpoint2) 3.31 + err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) 3.32 if err != nil { 3.33 t.Fatalf("Error saving endpoint in %T: %s", store, err) 3.34 } 3.35 @@ -393,11 +393,11 @@ 3.36 if err != nil { 3.37 t.Fatalf("Error saving client in %T: %s", store, err) 3.38 } 3.39 - err = store.addEndpoint(client.ID, endpoint1) 3.40 + err = store.addEndpoints(client.ID, []Endpoint{endpoint1}) 3.41 if err != nil { 3.42 t.Fatalf("Error saving endpoint in %T: %s", store, err) 3.43 } 3.44 - err = store.addEndpoint(client.ID, endpoint2) 3.45 + err = store.addEndpoints(client.ID, []Endpoint{endpoint2}) 3.46 if err != nil { 3.47 t.Fatalf("Error saving endpoint in %T: %s", store, err) 3.48 }
4.1 --- a/context.go Sat Jan 10 04:16:07 2015 -0500 4.2 +++ b/context.go Wed Jan 14 00:23:30 2015 -0500 4.3 @@ -107,13 +107,13 @@ 4.4 return c.clients.listClientsByOwner(ownerID, num, offset) 4.5 } 4.6 4.7 -// AddEndpoint stores the specified Endpoint in the clientStore associated with the Context, 4.8 -// and associates the newly-stored Endpoint with the Client specified by the passed ID. 4.9 -func (c Context) AddEndpoint(client uuid.ID, endpoint Endpoint) error { 4.10 +// AddEndpoints stores the specified Endpoints in the clientStore associated with the Context, 4.11 +// and associates the newly-stored Endpoints with the Client specified by the passed ID. 4.12 +func (c Context) AddEndpoints(client uuid.ID, endpoints []Endpoint) error { 4.13 if c.clients == nil { 4.14 return ErrNoClientStore 4.15 } 4.16 - return c.clients.addEndpoint(client, endpoint) 4.17 + return c.clients.addEndpoints(client, endpoints) 4.18 } 4.19 4.20 // RemoveEndpoint deletes the Endpoint with the specified ID from the clientStore associated
5.1 --- a/oauth2_test.go Sat Jan 10 04:16:07 2015 -0500 5.2 +++ b/oauth2_test.go Wed Jan 14 00:23:30 2015 -0500 5.3 @@ -60,7 +60,7 @@ 5.4 if err != nil { 5.5 t.Fatal("Can't store client:", err) 5.6 } 5.7 - err = testContext.AddEndpoint(client.ID, endpoint) 5.8 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint}) 5.9 if err != nil { 5.10 t.Fatal("Can't store endpoint:", err) 5.11 } 5.12 @@ -287,7 +287,7 @@ 5.13 URI: *uri, 5.14 Added: time.Now(), 5.15 } 5.16 - err = testContext.AddEndpoint(client.ID, endpoint) 5.17 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint}) 5.18 if err != nil { 5.19 t.Fatal("Can't store endpoint:", err) 5.20 } 5.21 @@ -307,7 +307,7 @@ 5.22 URI: *uri, 5.23 Added: time.Now(), 5.24 } 5.25 - err = testContext.AddEndpoint(client.ID, endpoint2) 5.26 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint2}) 5.27 if err != nil { 5.28 t.Fatal("Can't store endpoint:", err) 5.29 } 5.30 @@ -367,7 +367,7 @@ 5.31 if err != nil { 5.32 t.Fatal("Can't store client:", err) 5.33 } 5.34 - err = testContext.AddEndpoint(client.ID, endpoint) 5.35 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint}) 5.36 if err != nil { 5.37 t.Fatal("Can't store endpoint:", err) 5.38 } 5.39 @@ -474,7 +474,7 @@ 5.40 if err != nil { 5.41 t.Fatal("Can't store client:", err) 5.42 } 5.43 - err = testContext.AddEndpoint(client.ID, endpoint) 5.44 + err = testContext.AddEndpoints(client.ID, []Endpoint{endpoint}) 5.45 if err != nil { 5.46 t.Fatal("Can't store endpoint:", err) 5.47 }