auth

Paddy 2014-12-07 Parent:4cb65cf90217

85:1dc4e152e3b0 Go to Latest

auth/grant.go

Break client verification out, break token returns out. Break client verification out into a helper function to avoid rewriting it for pretty much every grant. Break token returns out into a new function as part of the GrantType, so that implicit grants can redirect with the token value. Split returning the token as JSON into its own exported function, which can be used in multiple grants. Return more relevant information to the template when a user is deciding whether or not to authorize a grant.

History
paddy@26 1 package auth
paddy@26 2
paddy@26 3 import (
paddy@84 4 "encoding/json"
paddy@29 5 "errors"
paddy@84 6 "net/http"
paddy@26 7 "time"
paddy@26 8
paddy@45 9 "code.secondbit.org/uuid"
paddy@26 10 )
paddy@26 11
paddy@84 12 func init() {
paddy@84 13 RegisterGrantType("authorization_code", GrantType{
paddy@84 14 Validate: authCodeGrantValidate,
paddy@84 15 IssuesRefresh: true,
paddy@85 16 ReturnToken: RenderJSONToken,
paddy@84 17 })
paddy@84 18 }
paddy@84 19
paddy@29 20 var (
paddy@57 21 // ErrNoGrantStore is returned when a Context tries to act on a grantStore without setting one first.
paddy@57 22 ErrNoGrantStore = errors.New("no grantStore was specified for the Context")
paddy@57 23 // ErrGrantNotFound is returned when a Grant is requested but not found in the grantStore.
paddy@57 24 ErrGrantNotFound = errors.New("grant not found in grantStore")
paddy@57 25 // ErrGrantAlreadyExists is returned when a Grant is added to a grantStore, but another Grant with the
paddy@57 26 // same Code already exists in the grantStore.
paddy@57 27 ErrGrantAlreadyExists = errors.New("grant already exists in grantStore")
paddy@29 28 )
paddy@29 29
paddy@57 30 // Grant represents an authorization grant made by a user to a Client, to
paddy@57 31 // access user data within a defined Scope for a limited amount of time.
paddy@26 32 type Grant struct {
paddy@26 33 Code string
paddy@26 34 Created time.Time
paddy@26 35 ExpiresIn int32
paddy@26 36 ClientID uuid.ID
paddy@26 37 Scope string
paddy@26 38 RedirectURI string
paddy@26 39 State string
paddy@69 40 ProfileID uuid.ID
paddy@26 41 }
paddy@26 42
paddy@57 43 type grantStore interface {
paddy@57 44 getGrant(code string) (Grant, error)
paddy@57 45 saveGrant(grant Grant) error
paddy@57 46 deleteGrant(code string) error
paddy@26 47 }
paddy@29 48
paddy@57 49 func (m *memstore) getGrant(code string) (Grant, error) {
paddy@29 50 m.grantLock.RLock()
paddy@29 51 defer m.grantLock.RUnlock()
paddy@29 52 grant, ok := m.grants[code]
paddy@29 53 if !ok {
paddy@29 54 return Grant{}, ErrGrantNotFound
paddy@29 55 }
paddy@29 56 return grant, nil
paddy@29 57 }
paddy@29 58
paddy@57 59 func (m *memstore) saveGrant(grant Grant) error {
paddy@29 60 m.grantLock.Lock()
paddy@29 61 defer m.grantLock.Unlock()
paddy@29 62 _, ok := m.grants[grant.Code]
paddy@29 63 if ok {
paddy@29 64 return ErrGrantAlreadyExists
paddy@29 65 }
paddy@29 66 m.grants[grant.Code] = grant
paddy@29 67 return nil
paddy@29 68 }
paddy@29 69
paddy@57 70 func (m *memstore) deleteGrant(code string) error {
paddy@29 71 m.grantLock.Lock()
paddy@29 72 defer m.grantLock.Unlock()
paddy@29 73 _, ok := m.grants[code]
paddy@29 74 if !ok {
paddy@29 75 return ErrGrantNotFound
paddy@29 76 }
paddy@29 77 delete(m.grants, code)
paddy@29 78 return nil
paddy@29 79 }
paddy@84 80
paddy@84 81 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scope string, profileID uuid.ID, valid bool) {
paddy@84 82 enc := json.NewEncoder(w)
paddy@84 83 code := r.PostFormValue("code")
paddy@84 84 if code == "" {
paddy@84 85 w.WriteHeader(http.StatusBadRequest)
paddy@84 86 renderJSONError(enc, "invalid_request")
paddy@84 87 return
paddy@84 88 }
paddy@85 89 clientID, success := verifyClient(w, r, true, context)
paddy@85 90 if !success {
paddy@84 91 return
paddy@84 92 }
paddy@84 93 grant, err := context.GetGrant(code)
paddy@84 94 if err != nil {
paddy@84 95 if err == ErrGrantNotFound {
paddy@84 96 w.WriteHeader(http.StatusBadRequest)
paddy@84 97 renderJSONError(enc, "invalid_grant")
paddy@84 98 return
paddy@84 99 }
paddy@84 100 w.WriteHeader(http.StatusInternalServerError)
paddy@84 101 renderJSONError(enc, "server_error")
paddy@84 102 return
paddy@84 103 }
paddy@85 104 redirectURI := r.PostFormValue("redirect_uri")
paddy@84 105 if grant.RedirectURI != redirectURI {
paddy@84 106 w.WriteHeader(http.StatusBadRequest)
paddy@84 107 renderJSONError(enc, "invalid_grant")
paddy@84 108 return
paddy@84 109 }
paddy@84 110 if !grant.ClientID.Equal(clientID) {
paddy@84 111 w.WriteHeader(http.StatusBadRequest)
paddy@84 112 renderJSONError(enc, "invalid_grant")
paddy@84 113 return
paddy@84 114 }
paddy@84 115 return grant.Scope, grant.ProfileID, true
paddy@84 116 }