auth

Paddy 2015-05-12 Parent:04c8edf89e3b Child:581c60f8dd23

167:0ff23f3a4ede Go to Latest

auth/request.go

Implement an endpoint for token information. Implement an endpoint that allows us to look up information on a token. We strip the refresh token before the response is sent to avoid leaking the response token.

History
paddy@99 1 package auth
paddy@99 2
paddy@104 3 import (
paddy@104 4 "encoding/json"
paddy@104 5 "log"
paddy@104 6 "net/http"
paddy@104 7
paddy@104 8 "bitbucket.org/ww/goautoneg"
paddy@104 9 )
paddy@104 10
paddy@99 11 const (
paddy@99 12 requestErrAccessDenied = "access_denied"
paddy@99 13 requestErrInsufficient = "insufficient"
paddy@99 14 requestErrOverflow = "overflow"
paddy@99 15 requestErrInvalidValue = "invalid_value"
paddy@99 16 requestErrInvalidFormat = "invalid_format"
paddy@99 17 requestErrMissing = "missing"
paddy@99 18 requestErrNotFound = "not_found"
paddy@104 19 requestErrConflict = "conflict"
paddy@99 20 requestErrActOfGod = "act_of_god"
paddy@99 21 )
paddy@99 22
paddy@104 23 var (
paddy@104 24 actOfGodResponse = response{Errors: []requestError{requestError{Slug: requestErrActOfGod}}}
paddy@104 25 invalidFormatResponse = response{Errors: []requestError{requestError{Slug: requestErrInvalidFormat, Field: "/"}}}
paddy@104 26
paddy@104 27 encoders = []string{"application/json"}
paddy@104 28 )
paddy@104 29
paddy@104 30 type response struct {
paddy@108 31 Errors []requestError `json:"errors,omitempty"`
paddy@108 32 Logins []Login `json:"logins,omitempty"`
paddy@108 33 Profiles []Profile `json:"profiles,omitempty"`
paddy@108 34 Clients []Client `json:"clients,omitempty"`
paddy@108 35 Endpoints []Endpoint `json:"endpoints,omitempty"`
paddy@159 36 Sessions []Session `json:"sessions,omitempty"`
paddy@167 37 Tokens []Token `json:"tokens,omitempty"`
paddy@104 38 }
paddy@104 39
paddy@99 40 type requestError struct {
paddy@99 41 Slug string `json:"error,omitempty"`
paddy@99 42 Field string `json:"field,omitempty"`
paddy@99 43 Param string `json:"param,omitempty"`
paddy@99 44 Header string `json:"header,omitempty"`
paddy@99 45 }
paddy@104 46
paddy@104 47 func negotiate(h http.Handler) http.Handler {
paddy@104 48 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@110 49 if r.Header.Get("Accept") != "" {
paddy@110 50 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@110 51 if contentType == "" {
paddy@110 52 w.WriteHeader(http.StatusNotAcceptable)
paddy@110 53 w.Write([]byte("Unsupported content type requested: " + r.Header.Get("Accept")))
paddy@110 54 return
paddy@110 55 }
paddy@104 56 }
paddy@104 57 h.ServeHTTP(w, r)
paddy@104 58 })
paddy@104 59 }
paddy@104 60
paddy@104 61 func encode(w http.ResponseWriter, r *http.Request, status int, resp response) {
paddy@104 62 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@104 63 w.Header().Set("content-type", contentType)
paddy@104 64 w.WriteHeader(status)
paddy@104 65 var err error
paddy@104 66 switch contentType {
paddy@104 67 case "application/json":
paddy@104 68 enc := json.NewEncoder(w)
paddy@104 69 err = enc.Encode(resp)
paddy@110 70 default:
paddy@110 71 enc := json.NewEncoder(w)
paddy@110 72 err = enc.Encode(resp)
paddy@104 73 }
paddy@104 74 if err != nil {
paddy@104 75 log.Println(err)
paddy@104 76 }
paddy@104 77 }
paddy@104 78
paddy@133 79 func decode(r *http.Request, target interface{}) error {
paddy@133 80 defer r.Body.Close()
paddy@133 81 switch r.Header.Get("Content-Type") {
paddy@133 82 case "application/json":
paddy@133 83 dec := json.NewDecoder(r.Body)
paddy@133 84 return dec.Decode(target)
paddy@133 85 default:
paddy@133 86 dec := json.NewDecoder(r.Body)
paddy@133 87 return dec.Decode(target)
paddy@133 88 }
paddy@133 89 }
paddy@133 90
paddy@104 91 func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
paddy@104 92 return negotiate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@165 93 w.Header().Set("Access-Control-Allow-Origin", "*")
paddy@165 94 w.Header().Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
paddy@165 95 w.Header().Set("Access-Control-Allow-Credentials", "true")
paddy@165 96 if r.Method == "OPTIONS" {
paddy@165 97 w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
paddy@165 98 w.Header().Set("Allow", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
paddy@165 99 w.WriteHeader(http.StatusOK)
paddy@165 100 return
paddy@165 101 }
paddy@104 102 f(w, r, context)
paddy@104 103 }))
paddy@104 104 }