auth

Paddy 2015-04-11 Parent:cf6c1f05eb21 Child:04c8edf89e3b

162:6f473576c6ae Go to Latest

auth/request.go

Clean up sessions and tokens after Profile is deleted. Add a terminateSessionsByProfile method to our sessionStore to mark Sessions associated with a Profile as inactive. Implement memstore and postgres implementations of the terminateSessionsByProfile method. Add a TerminateSessionsByProfile wrapper method to Context. Add a revokeTokensByProfileID method to our tokenStore to mark Tokens associated with a Profile as revoked. Implement memstore and postgres implementation of the revokeTokensByProfileID method. Add a RevokeTokensByProfileID wrapper method to Context. Call our RevokeTokensByProfileID and TerminateSessionsByProfile methods after a Profile is deleted, to clean up the Tokens and Sessions associated with it.

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@104 37 }
paddy@104 38
paddy@99 39 type requestError struct {
paddy@99 40 Slug string `json:"error,omitempty"`
paddy@99 41 Field string `json:"field,omitempty"`
paddy@99 42 Param string `json:"param,omitempty"`
paddy@99 43 Header string `json:"header,omitempty"`
paddy@99 44 }
paddy@104 45
paddy@104 46 func negotiate(h http.Handler) http.Handler {
paddy@104 47 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@110 48 if r.Header.Get("Accept") != "" {
paddy@110 49 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@110 50 if contentType == "" {
paddy@110 51 w.WriteHeader(http.StatusNotAcceptable)
paddy@110 52 w.Write([]byte("Unsupported content type requested: " + r.Header.Get("Accept")))
paddy@110 53 return
paddy@110 54 }
paddy@104 55 }
paddy@104 56 h.ServeHTTP(w, r)
paddy@104 57 })
paddy@104 58 }
paddy@104 59
paddy@104 60 func encode(w http.ResponseWriter, r *http.Request, status int, resp response) {
paddy@104 61 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@104 62 w.Header().Set("content-type", contentType)
paddy@104 63 w.WriteHeader(status)
paddy@104 64 var err error
paddy@104 65 switch contentType {
paddy@104 66 case "application/json":
paddy@104 67 enc := json.NewEncoder(w)
paddy@104 68 err = enc.Encode(resp)
paddy@110 69 default:
paddy@110 70 enc := json.NewEncoder(w)
paddy@110 71 err = enc.Encode(resp)
paddy@104 72 }
paddy@104 73 if err != nil {
paddy@104 74 log.Println(err)
paddy@104 75 }
paddy@104 76 }
paddy@104 77
paddy@133 78 func decode(r *http.Request, target interface{}) error {
paddy@133 79 defer r.Body.Close()
paddy@133 80 switch r.Header.Get("Content-Type") {
paddy@133 81 case "application/json":
paddy@133 82 dec := json.NewDecoder(r.Body)
paddy@133 83 return dec.Decode(target)
paddy@133 84 default:
paddy@133 85 dec := json.NewDecoder(r.Body)
paddy@133 86 return dec.Decode(target)
paddy@133 87 }
paddy@133 88 }
paddy@133 89
paddy@104 90 func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
paddy@104 91 return negotiate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@104 92 f(w, r, context)
paddy@104 93 }))
paddy@104 94 }