auth

Paddy 2014-12-13 Parent:d5561856f45e Child:9c50b2e2e03b

93:a22b35677cd5 Go to Latest

auth/authcode.go

Implement RevokeToken helper for Context. Add a RevokeToken wrapper to Context that checks for the a tokenStore set on the Context and calls the underlying tokenStore.revokeToken if a tokenStore is set.

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@87 21 // ErrNoAuthorizationCodeStore is returned when a Context tries to act on a authorizationCodeStore without setting one first.
paddy@87 22 ErrNoAuthorizationCodeStore = errors.New("no authorizationCodeStore was specified for the Context")
paddy@87 23 // ErrAuthorizationCodeNotFound is returned when an AuthorizationCode is requested but not found in the authorizationCodeStore.
paddy@87 24 ErrAuthorizationCodeNotFound = errors.New("authorization code not found in authorizationCodeStore")
paddy@87 25 // ErrAuthorizationCodeAlreadyExists is returned when an AuthorizationCode is added to a authorizationCodeStore, but another AuthorizationCode with the
paddy@87 26 // same Code already exists in the authorizationCodeStore.
paddy@87 27 ErrAuthorizationCodeAlreadyExists = errors.New("authorization code already exists in authorizationCodeStore")
paddy@29 28 )
paddy@29 29
paddy@87 30 // AuthorizationCode 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@87 32 type AuthorizationCode 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@87 43 type authorizationCodeStore interface {
paddy@87 44 getAuthorizationCode(code string) (AuthorizationCode, error)
paddy@87 45 saveAuthorizationCode(authCode AuthorizationCode) error
paddy@87 46 deleteAuthorizationCode(code string) error
paddy@26 47 }
paddy@29 48
paddy@87 49 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
paddy@87 50 m.authCodeLock.RLock()
paddy@87 51 defer m.authCodeLock.RUnlock()
paddy@87 52 authCode, ok := m.authCodes[code]
paddy@29 53 if !ok {
paddy@87 54 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
paddy@29 55 }
paddy@87 56 return authCode, nil
paddy@29 57 }
paddy@29 58
paddy@87 59 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
paddy@87 60 m.authCodeLock.Lock()
paddy@87 61 defer m.authCodeLock.Unlock()
paddy@87 62 _, ok := m.authCodes[authCode.Code]
paddy@29 63 if ok {
paddy@87 64 return ErrAuthorizationCodeAlreadyExists
paddy@29 65 }
paddy@87 66 m.authCodes[authCode.Code] = authCode
paddy@29 67 return nil
paddy@29 68 }
paddy@29 69
paddy@87 70 func (m *memstore) deleteAuthorizationCode(code string) error {
paddy@87 71 m.authCodeLock.Lock()
paddy@87 72 defer m.authCodeLock.Unlock()
paddy@87 73 _, ok := m.authCodes[code]
paddy@29 74 if !ok {
paddy@87 75 return ErrAuthorizationCodeNotFound
paddy@29 76 }
paddy@87 77 delete(m.authCodes, 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@87 93 authCode, err := context.GetAuthorizationCode(code)
paddy@84 94 if err != nil {
paddy@87 95 if err == ErrAuthorizationCodeNotFound {
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@87 105 if authCode.RedirectURI != redirectURI {
paddy@84 106 w.WriteHeader(http.StatusBadRequest)
paddy@84 107 renderJSONError(enc, "invalid_grant")
paddy@84 108 return
paddy@84 109 }
paddy@87 110 if !authCode.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@87 115 return authCode.Scope, authCode.ProfileID, true
paddy@84 116 }
paddy@90 117
paddy@90 118 func authCodeGrantInvalidate(r *http.Request, context Context) error {
paddy@90 119 // TODO(paddy): implement marking the authcode as used.
paddy@90 120 return nil
paddy@90 121 }