auth

Paddy 2015-01-24 Parent:6c755b23ec80 Child:163ce22fa4c9

131:f474ce964dcf Browse Files

Implement handlers for retrieving clients. Create a GetClientHandler and ListClientsHandler for retrieving details about a client. Currently, we're not returning the client secret for these clients. We're also not doing any auth. We may want to restrict auth to the owner of the clients, and return secrets only when auth'd, and maybe even only when a special header is included. Alternatively, we could only return the secret when retrieving a single client. Still unsure how I want to handle that.

client.go client_test.go

     1.1 --- a/client.go	Sat Jan 24 09:48:12 2015 -0500
     1.2 +++ b/client.go	Sat Jan 24 10:34:33 2015 -0500
     1.3 @@ -56,10 +56,12 @@
     1.4  )
     1.5  
     1.6  const (
     1.7 -	clientTypePublic       = "public"
     1.8 -	clientTypeConfidential = "confidential"
     1.9 -	minClientNameLen       = 2
    1.10 -	maxClientNameLen       = 24
    1.11 +	clientTypePublic          = "public"
    1.12 +	clientTypeConfidential    = "confidential"
    1.13 +	minClientNameLen          = 2
    1.14 +	maxClientNameLen          = 24
    1.15 +	defaultClientResponseSize = 20
    1.16 +	maxClientResponseSize     = 50
    1.17  
    1.18  	normalizeFlags = purell.FlagsUsuallySafeNonGreedy | purell.FlagSortQuery
    1.19  )
    1.20 @@ -386,8 +388,8 @@
    1.21  
    1.22  func RegisterClientHandlers(r *mux.Router, context Context) {
    1.23  	r.Handle("/clients", wrap(context, CreateClientHandler)).Methods("POST")
    1.24 -	// BUG(paddy): We need to implement a handler to retrieve info on a client.
    1.25 -	// BUG(paddy): We need to implement a handler to list clients.
    1.26 +	r.Handle("/clients", wrap(context, ListClientsHandler)).Methods("GET")
    1.27 +	r.Handle("/clients/{id}", wrap(context, GetClientHandler)).Methods("GET")
    1.28  	// BUG(paddy): We need to implement a handler to update a client.
    1.29  	// BUG(paddy): We need to implement a handler to delete a client. Also, what should that do with the grants and tokens belonging to that client?
    1.30  	// BUG(paddy): We need to implement a handler to add an endpoint to a client.
    1.31 @@ -492,6 +494,95 @@
    1.32  	encode(w, r, http.StatusCreated, resp)
    1.33  }
    1.34  
    1.35 +func GetClientHandler(w http.ResponseWriter, r *http.Request, c Context) {
    1.36 +	errors := []requestError{}
    1.37 +	vars := mux.Vars(r)
    1.38 +	if vars["id"] == "" {
    1.39 +		errors = append(errors, requestError{Slug: requestErrMissing, Param: "id"})
    1.40 +		encode(w, r, http.StatusBadRequest, response{Errors: errors})
    1.41 +		return
    1.42 +	}
    1.43 +	id, err := uuid.Parse(vars["id"])
    1.44 +	if err != nil {
    1.45 +		errors = append(errors, requestError{Slug: requestErrInvalidFormat, Param: "id"})
    1.46 +		encode(w, r, http.StatusBadRequest, response{Errors: errors})
    1.47 +		return
    1.48 +	}
    1.49 +	client, err := c.GetClient(id)
    1.50 +	if err != nil {
    1.51 +		if err == ErrClientNotFound {
    1.52 +			errors = append(errors, requestError{Slug: requestErrNotFound, Param: "id"})
    1.53 +			encode(w, r, http.StatusBadRequest, response{Errors: errors})
    1.54 +			return
    1.55 +		}
    1.56 +		errors = append(errors, requestError{Slug: requestErrActOfGod})
    1.57 +		encode(w, r, http.StatusInternalServerError, response{Errors: errors})
    1.58 +		return
    1.59 +	}
    1.60 +	client.Secret = ""
    1.61 +	// BUG(paddy): How should auth be handled for retrieving clients?
    1.62 +	resp := response{
    1.63 +		Clients: []Client{client},
    1.64 +		Errors:  errors,
    1.65 +	}
    1.66 +	encode(w, r, http.StatusOK, resp)
    1.67 +}
    1.68 +
    1.69 +func ListClientsHandler(w http.ResponseWriter, r *http.Request, c Context) {
    1.70 +	errors := []requestError{}
    1.71 +	var err error
    1.72 +	// BUG(paddy): If ids are provided in query params, retrieve only those clients
    1.73 +	// BUG(paddy): We should have auth when listing clients
    1.74 +	num := defaultClientResponseSize
    1.75 +	offset := 0
    1.76 +	ownerIDStr := r.URL.Query().Get("owner_id")
    1.77 +	numStr := r.URL.Query().Get("num")
    1.78 +	offsetStr := r.URL.Query().Get("offset")
    1.79 +	if numStr != "" {
    1.80 +		num, err = strconv.Atoi(numStr)
    1.81 +		if err != nil {
    1.82 +			errors = append(errors, requestError{Slug: requestErrInvalidFormat, Param: "num"})
    1.83 +		}
    1.84 +		if num > maxClientResponseSize {
    1.85 +			errors = append(errors, requestError{Slug: requestErrOverflow, Param: "num"})
    1.86 +		}
    1.87 +	}
    1.88 +	if offsetStr != "" {
    1.89 +		offset, err = strconv.Atoi(offsetStr)
    1.90 +		if err != nil {
    1.91 +			errors = append(errors, requestError{Slug: requestErrInvalidFormat, Param: "offset"})
    1.92 +		}
    1.93 +	}
    1.94 +	if ownerIDStr == "" {
    1.95 +		errors = append(errors, requestError{Slug: requestErrMissing, Param: "owner_id"})
    1.96 +	}
    1.97 +	if len(errors) > 0 {
    1.98 +		encode(w, r, http.StatusBadRequest, response{Errors: errors})
    1.99 +		return
   1.100 +	}
   1.101 +	ownerID, err := uuid.Parse(ownerIDStr)
   1.102 +	if err != nil {
   1.103 +		errors = append(errors, requestError{Slug: requestErrInvalidFormat, Param: "owner_id"})
   1.104 +		encode(w, r, http.StatusInternalServerError, response{Errors: errors})
   1.105 +		return
   1.106 +	}
   1.107 +	clients, err := c.ListClientsByOwner(ownerID, num, offset)
   1.108 +	if err != nil {
   1.109 +		errors = append(errors, requestError{Slug: requestErrActOfGod})
   1.110 +		encode(w, r, http.StatusInternalServerError, response{Errors: errors})
   1.111 +		return
   1.112 +	}
   1.113 +	for pos, client := range clients {
   1.114 +		client.Secret = ""
   1.115 +		clients[pos] = client
   1.116 +	}
   1.117 +	resp := response{
   1.118 +		Clients: clients,
   1.119 +		Errors:  errors,
   1.120 +	}
   1.121 +	encode(w, r, http.StatusOK, resp)
   1.122 +}
   1.123 +
   1.124  func clientCredentialsValidate(w http.ResponseWriter, r *http.Request, context Context) (scope string, profileID uuid.ID, valid bool) {
   1.125  	scope = r.PostFormValue("scope")
   1.126  	valid = true
     2.1 --- a/client_test.go	Sat Jan 24 09:48:12 2015 -0500
     2.2 +++ b/client_test.go	Sat Jan 24 10:34:33 2015 -0500
     2.3 @@ -782,3 +782,5 @@
     2.4  }
     2.5  
     2.6  // BUG(paddy): We need to test the clientCredentialsValidate function.
     2.7 +// BUG(paddy): We need to test the GetClientHandler.
     2.8 +// BUG(paddy): We need to test the ListClientsHandler.