auth

Paddy 2015-12-14 Parent:b7e685839a1b

182:cd5f07f9811b Go to Latest

auth/authcode.go

Update nsq import path. go-nsq has moved to nsqio/go-nsq, so we need to update the import path appropriately.

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@181 9 "code.secondbit.org/scopes.hg/types"
paddy@107 10 "code.secondbit.org/uuid.hg"
paddy@26 11 )
paddy@26 12
paddy@84 13 func init() {
paddy@84 14 RegisterGrantType("authorization_code", GrantType{
paddy@84 15 Validate: authCodeGrantValidate,
paddy@94 16 Invalidate: authCodeGrantInvalidate,
paddy@84 17 IssuesRefresh: true,
paddy@85 18 ReturnToken: RenderJSONToken,
paddy@123 19 AllowsPublic: true,
paddy@124 20 AuditString: authCodeGrantAuditString,
paddy@84 21 })
paddy@84 22 }
paddy@84 23
paddy@29 24 var (
paddy@87 25 // ErrNoAuthorizationCodeStore is returned when a Context tries to act on a authorizationCodeStore without setting one first.
paddy@87 26 ErrNoAuthorizationCodeStore = errors.New("no authorizationCodeStore was specified for the Context")
paddy@87 27 // ErrAuthorizationCodeNotFound is returned when an AuthorizationCode is requested but not found in the authorizationCodeStore.
paddy@87 28 ErrAuthorizationCodeNotFound = errors.New("authorization code not found in authorizationCodeStore")
paddy@87 29 // ErrAuthorizationCodeAlreadyExists is returned when an AuthorizationCode is added to a authorizationCodeStore, but another AuthorizationCode with the
paddy@87 30 // same Code already exists in the authorizationCodeStore.
paddy@87 31 ErrAuthorizationCodeAlreadyExists = errors.New("authorization code already exists in authorizationCodeStore")
paddy@29 32 )
paddy@29 33
paddy@87 34 // AuthorizationCode represents an authorization grant made by a user to a Client, to
paddy@57 35 // access user data within a defined Scope for a limited amount of time.
paddy@87 36 type AuthorizationCode struct {
paddy@26 37 Code string
paddy@26 38 Created time.Time
paddy@26 39 ExpiresIn int32
paddy@26 40 ClientID uuid.ID
paddy@181 41 Scopes scopeTypes.Scopes
paddy@26 42 RedirectURI string
paddy@26 43 State string
paddy@69 44 ProfileID uuid.ID
paddy@94 45 Used bool
paddy@26 46 }
paddy@26 47
paddy@87 48 type authorizationCodeStore interface {
paddy@87 49 getAuthorizationCode(code string) (AuthorizationCode, error)
paddy@87 50 saveAuthorizationCode(authCode AuthorizationCode) error
paddy@87 51 deleteAuthorizationCode(code string) error
paddy@163 52 deleteAuthorizationCodesByProfileID(profileID uuid.ID) error
paddy@164 53 deleteAuthorizationCodesByClientID(clientID uuid.ID) error
paddy@94 54 useAuthorizationCode(code string) error
paddy@26 55 }
paddy@29 56
paddy@87 57 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
paddy@87 58 m.authCodeLock.RLock()
paddy@87 59 defer m.authCodeLock.RUnlock()
paddy@87 60 authCode, ok := m.authCodes[code]
paddy@29 61 if !ok {
paddy@87 62 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
paddy@29 63 }
paddy@87 64 return authCode, nil
paddy@29 65 }
paddy@29 66
paddy@87 67 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
paddy@87 68 m.authCodeLock.Lock()
paddy@87 69 defer m.authCodeLock.Unlock()
paddy@87 70 _, ok := m.authCodes[authCode.Code]
paddy@29 71 if ok {
paddy@87 72 return ErrAuthorizationCodeAlreadyExists
paddy@29 73 }
paddy@87 74 m.authCodes[authCode.Code] = authCode
paddy@29 75 return nil
paddy@29 76 }
paddy@29 77
paddy@87 78 func (m *memstore) deleteAuthorizationCode(code string) error {
paddy@87 79 m.authCodeLock.Lock()
paddy@87 80 defer m.authCodeLock.Unlock()
paddy@87 81 _, ok := m.authCodes[code]
paddy@29 82 if !ok {
paddy@87 83 return ErrAuthorizationCodeNotFound
paddy@29 84 }
paddy@87 85 delete(m.authCodes, code)
paddy@29 86 return nil
paddy@29 87 }
paddy@84 88
paddy@163 89 func (m *memstore) deleteAuthorizationCodesByProfileID(profileID uuid.ID) error {
paddy@163 90 m.authCodeLock.Lock()
paddy@163 91 defer m.authCodeLock.Unlock()
paddy@163 92 var codes []string
paddy@163 93 for _, code := range m.authCodes {
paddy@163 94 if code.ProfileID.Equal(profileID) {
paddy@163 95 codes = append(codes, code.Code)
paddy@163 96 }
paddy@163 97 }
paddy@163 98 if len(codes) < 1 {
paddy@163 99 return ErrProfileNotFound
paddy@163 100 }
paddy@163 101 for _, code := range codes {
paddy@163 102 delete(m.authCodes, code)
paddy@163 103 }
paddy@163 104 return nil
paddy@163 105 }
paddy@163 106
paddy@164 107 func (m *memstore) deleteAuthorizationCodesByClientID(clientID uuid.ID) error {
paddy@164 108 m.authCodeLock.Lock()
paddy@164 109 defer m.authCodeLock.Unlock()
paddy@164 110 var codes []string
paddy@164 111 for _, code := range m.authCodes {
paddy@164 112 if code.ClientID.Equal(clientID) {
paddy@164 113 codes = append(codes, code.Code)
paddy@164 114 }
paddy@164 115 }
paddy@164 116 if len(codes) < 1 {
paddy@164 117 return ErrClientNotFound
paddy@164 118 }
paddy@164 119 for _, code := range codes {
paddy@164 120 delete(m.authCodes, code)
paddy@164 121 }
paddy@164 122 return nil
paddy@164 123 }
paddy@164 124
paddy@94 125 func (m *memstore) useAuthorizationCode(code string) error {
paddy@94 126 m.authCodeLock.Lock()
paddy@94 127 defer m.authCodeLock.Unlock()
paddy@94 128 a, ok := m.authCodes[code]
paddy@94 129 if !ok {
paddy@94 130 return ErrAuthorizationCodeNotFound
paddy@94 131 }
paddy@94 132 a.Used = true
paddy@94 133 m.authCodes[code] = a
paddy@94 134 return nil
paddy@94 135 }
paddy@94 136
paddy@181 137 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scopes scopeTypes.Scopes, profileID uuid.ID, valid bool) {
paddy@84 138 enc := json.NewEncoder(w)
paddy@84 139 code := r.PostFormValue("code")
paddy@84 140 if code == "" {
paddy@84 141 w.WriteHeader(http.StatusBadRequest)
paddy@84 142 renderJSONError(enc, "invalid_request")
paddy@84 143 return
paddy@84 144 }
paddy@123 145 clientID, _, ok := getClientAuth(w, r, true)
paddy@123 146 if !ok {
paddy@84 147 return
paddy@84 148 }
paddy@87 149 authCode, err := context.GetAuthorizationCode(code)
paddy@84 150 if err != nil {
paddy@87 151 if err == ErrAuthorizationCodeNotFound {
paddy@84 152 w.WriteHeader(http.StatusBadRequest)
paddy@84 153 renderJSONError(enc, "invalid_grant")
paddy@84 154 return
paddy@84 155 }
paddy@84 156 w.WriteHeader(http.StatusInternalServerError)
paddy@84 157 renderJSONError(enc, "server_error")
paddy@84 158 return
paddy@84 159 }
paddy@85 160 redirectURI := r.PostFormValue("redirect_uri")
paddy@87 161 if authCode.RedirectURI != redirectURI {
paddy@84 162 w.WriteHeader(http.StatusBadRequest)
paddy@84 163 renderJSONError(enc, "invalid_grant")
paddy@84 164 return
paddy@84 165 }
paddy@87 166 if !authCode.ClientID.Equal(clientID) {
paddy@84 167 w.WriteHeader(http.StatusBadRequest)
paddy@84 168 renderJSONError(enc, "invalid_grant")
paddy@84 169 return
paddy@84 170 }
paddy@135 171 return authCode.Scopes, authCode.ProfileID, true
paddy@84 172 }
paddy@90 173
paddy@90 174 func authCodeGrantInvalidate(r *http.Request, context Context) error {
paddy@94 175 code := r.PostFormValue("code")
paddy@94 176 if code == "" {
paddy@94 177 return ErrAuthorizationCodeNotFound
paddy@94 178 }
paddy@94 179 return context.UseAuthorizationCode(code)
paddy@90 180 }
paddy@124 181
paddy@124 182 func authCodeGrantAuditString(r *http.Request) string {
paddy@124 183 return "authcode:" + r.PostFormValue("code")
paddy@124 184 }