auth

Paddy 2014-12-14 Parent:0b45e6b9cb94 Child:3a1fe5ee17f5

104:bc77a315f823 Browse Files

Add request helpers. Fix a typo in the requestErrConflict constant. Create a response type that is used to build responses before sending them down the wire. Create vars for a few common types of error responses that never change. Create a negotiate middleware function that will respond with a 406 error if the client requests an encoding that we can't support. Create an encode helper that determines the requested encoding and uses it to send the data down the wire. Move our wrap middleware from the oauth2.go file to the request.go file, where it's more likely to be looked for.

oauth2.go request.go

     1.1 --- a/oauth2.go	Sun Dec 14 16:56:12 2014 -0500
     1.2 +++ b/oauth2.go	Sun Dec 14 17:00:31 2014 -0500
     1.3 @@ -126,12 +126,6 @@
     1.4  	return true
     1.5  }
     1.6  
     1.7 -func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
     1.8 -	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
     1.9 -		f(w, r, context)
    1.10 -	})
    1.11 -}
    1.12 -
    1.13  // RegisterOAuth2 adds handlers to the passed router to handle the OAuth2 endpoints.
    1.14  func RegisterOAuth2(r *mux.Router, context Context) {
    1.15  	r.Handle("/authorize", wrap(context, GetAuthorizationCodeHandler))
     2.1 --- a/request.go	Sun Dec 14 16:56:12 2014 -0500
     2.2 +++ b/request.go	Sun Dec 14 17:00:31 2014 -0500
     2.3 @@ -1,5 +1,13 @@
     2.4  package auth
     2.5  
     2.6 +import (
     2.7 +	"encoding/json"
     2.8 +	"log"
     2.9 +	"net/http"
    2.10 +
    2.11 +	"bitbucket.org/ww/goautoneg"
    2.12 +)
    2.13 +
    2.14  const (
    2.15  	requestErrAccessDenied  = "access_denied"
    2.16  	requestErrInsufficient  = "insufficient"
    2.17 @@ -8,13 +16,60 @@
    2.18  	requestErrInvalidFormat = "invalid_format"
    2.19  	requestErrMissing       = "missing"
    2.20  	requestErrNotFound      = "not_found"
    2.21 -	requestErrConflig       = "conflict"
    2.22 +	requestErrConflict      = "conflict"
    2.23  	requestErrActOfGod      = "act_of_god"
    2.24  )
    2.25  
    2.26 +var (
    2.27 +	actOfGodResponse      = response{Errors: []requestError{requestError{Slug: requestErrActOfGod}}}
    2.28 +	invalidFormatResponse = response{Errors: []requestError{requestError{Slug: requestErrInvalidFormat, Field: "/"}}}
    2.29 +
    2.30 +	encoders = []string{"application/json"}
    2.31 +)
    2.32 +
    2.33 +type response struct {
    2.34 +	Errors   []requestError `json:"errors,omitempty"`
    2.35 +	Logins   []Login        `json:"logins,omitempty"`
    2.36 +	Profiles []Profile      `json:"profiles,omitempty"`
    2.37 +}
    2.38 +
    2.39  type requestError struct {
    2.40  	Slug   string `json:"error,omitempty"`
    2.41  	Field  string `json:"field,omitempty"`
    2.42  	Param  string `json:"param,omitempty"`
    2.43  	Header string `json:"header,omitempty"`
    2.44  }
    2.45 +
    2.46 +func negotiate(h http.Handler) http.Handler {
    2.47 +	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    2.48 +		contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
    2.49 +		if contentType == "" {
    2.50 +			w.WriteHeader(http.StatusNotAcceptable)
    2.51 +			log.Println("Unsupported Accept header:", r.Header.Get("Accept"))
    2.52 +			w.Write([]byte("Unsupported content type requested: " + r.Header.Get("Accept")))
    2.53 +			return
    2.54 +		}
    2.55 +		h.ServeHTTP(w, r)
    2.56 +	})
    2.57 +}
    2.58 +
    2.59 +func encode(w http.ResponseWriter, r *http.Request, status int, resp response) {
    2.60 +	contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
    2.61 +	w.Header().Set("content-type", contentType)
    2.62 +	w.WriteHeader(status)
    2.63 +	var err error
    2.64 +	switch contentType {
    2.65 +	case "application/json":
    2.66 +		enc := json.NewEncoder(w)
    2.67 +		err = enc.Encode(resp)
    2.68 +	}
    2.69 +	if err != nil {
    2.70 +		log.Println(err)
    2.71 +	}
    2.72 +}
    2.73 +
    2.74 +func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
    2.75 +	return negotiate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    2.76 +		f(w, r, context)
    2.77 +	}))
    2.78 +}