auth
2014-12-07
Parent:1dc4e152e3b0
auth/grant.go
Document RenderJSONToken. Document the RenderJSONToken to satisfy golint.
| 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 } |