auth

Paddy 2014-12-14 Parent:9c50b2e2e03b Child:c03b5eb3179e

98:09c47387e455 Go to Latest

auth/authcode.go

Move login concerns to session, add login handler. Move all our helpers for authenticating, building a login redirect, and reading a cookie to session.go. Rewrite our passphrase scheme code so that a scheme is just a struct with three functions for checking a passphrase against a profile object, generating a passphrase, and calculating the number of iterations to use when generating a passphrase. Define an implementation of our passphrase scheme (scheme #1) using PBKDF2 and SHA256. Add a CreateSessionHandler function that logs the user in using their login and passphrase. Add a RegisterSessionHandlers function that adds the session-related handlers (right now, just our CreateSessionHandler) to the specified router.

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@94 15 Invalidate: authCodeGrantInvalidate,
paddy@84 16 IssuesRefresh: true,
paddy@85 17 ReturnToken: RenderJSONToken,
paddy@84 18 })
paddy@84 19 }
paddy@84 20
paddy@29 21 var (
paddy@87 22 // ErrNoAuthorizationCodeStore is returned when a Context tries to act on a authorizationCodeStore without setting one first.
paddy@87 23 ErrNoAuthorizationCodeStore = errors.New("no authorizationCodeStore was specified for the Context")
paddy@87 24 // ErrAuthorizationCodeNotFound is returned when an AuthorizationCode is requested but not found in the authorizationCodeStore.
paddy@87 25 ErrAuthorizationCodeNotFound = errors.New("authorization code not found in authorizationCodeStore")
paddy@87 26 // ErrAuthorizationCodeAlreadyExists is returned when an AuthorizationCode is added to a authorizationCodeStore, but another AuthorizationCode with the
paddy@87 27 // same Code already exists in the authorizationCodeStore.
paddy@87 28 ErrAuthorizationCodeAlreadyExists = errors.New("authorization code already exists in authorizationCodeStore")
paddy@29 29 )
paddy@29 30
paddy@87 31 // AuthorizationCode represents an authorization grant made by a user to a Client, to
paddy@57 32 // access user data within a defined Scope for a limited amount of time.
paddy@87 33 type AuthorizationCode struct {
paddy@26 34 Code string
paddy@26 35 Created time.Time
paddy@26 36 ExpiresIn int32
paddy@26 37 ClientID uuid.ID
paddy@26 38 Scope string
paddy@26 39 RedirectURI string
paddy@26 40 State string
paddy@69 41 ProfileID uuid.ID
paddy@94 42 Used bool
paddy@26 43 }
paddy@26 44
paddy@87 45 type authorizationCodeStore interface {
paddy@87 46 getAuthorizationCode(code string) (AuthorizationCode, error)
paddy@87 47 saveAuthorizationCode(authCode AuthorizationCode) error
paddy@87 48 deleteAuthorizationCode(code string) error
paddy@94 49 useAuthorizationCode(code string) error
paddy@26 50 }
paddy@29 51
paddy@87 52 func (m *memstore) getAuthorizationCode(code string) (AuthorizationCode, error) {
paddy@87 53 m.authCodeLock.RLock()
paddy@87 54 defer m.authCodeLock.RUnlock()
paddy@87 55 authCode, ok := m.authCodes[code]
paddy@29 56 if !ok {
paddy@87 57 return AuthorizationCode{}, ErrAuthorizationCodeNotFound
paddy@29 58 }
paddy@87 59 return authCode, nil
paddy@29 60 }
paddy@29 61
paddy@87 62 func (m *memstore) saveAuthorizationCode(authCode AuthorizationCode) error {
paddy@87 63 m.authCodeLock.Lock()
paddy@87 64 defer m.authCodeLock.Unlock()
paddy@87 65 _, ok := m.authCodes[authCode.Code]
paddy@29 66 if ok {
paddy@87 67 return ErrAuthorizationCodeAlreadyExists
paddy@29 68 }
paddy@87 69 m.authCodes[authCode.Code] = authCode
paddy@29 70 return nil
paddy@29 71 }
paddy@29 72
paddy@87 73 func (m *memstore) deleteAuthorizationCode(code string) error {
paddy@87 74 m.authCodeLock.Lock()
paddy@87 75 defer m.authCodeLock.Unlock()
paddy@87 76 _, ok := m.authCodes[code]
paddy@29 77 if !ok {
paddy@87 78 return ErrAuthorizationCodeNotFound
paddy@29 79 }
paddy@87 80 delete(m.authCodes, code)
paddy@29 81 return nil
paddy@29 82 }
paddy@84 83
paddy@94 84 func (m *memstore) useAuthorizationCode(code string) error {
paddy@94 85 m.authCodeLock.Lock()
paddy@94 86 defer m.authCodeLock.Unlock()
paddy@94 87 a, ok := m.authCodes[code]
paddy@94 88 if !ok {
paddy@94 89 return ErrAuthorizationCodeNotFound
paddy@94 90 }
paddy@94 91 a.Used = true
paddy@94 92 m.authCodes[code] = a
paddy@94 93 return nil
paddy@94 94 }
paddy@94 95
paddy@84 96 func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scope string, profileID uuid.ID, valid bool) {
paddy@84 97 enc := json.NewEncoder(w)
paddy@84 98 code := r.PostFormValue("code")
paddy@84 99 if code == "" {
paddy@84 100 w.WriteHeader(http.StatusBadRequest)
paddy@84 101 renderJSONError(enc, "invalid_request")
paddy@84 102 return
paddy@84 103 }
paddy@85 104 clientID, success := verifyClient(w, r, true, context)
paddy@85 105 if !success {
paddy@84 106 return
paddy@84 107 }
paddy@87 108 authCode, err := context.GetAuthorizationCode(code)
paddy@84 109 if err != nil {
paddy@87 110 if err == ErrAuthorizationCodeNotFound {
paddy@84 111 w.WriteHeader(http.StatusBadRequest)
paddy@84 112 renderJSONError(enc, "invalid_grant")
paddy@84 113 return
paddy@84 114 }
paddy@84 115 w.WriteHeader(http.StatusInternalServerError)
paddy@84 116 renderJSONError(enc, "server_error")
paddy@84 117 return
paddy@84 118 }
paddy@85 119 redirectURI := r.PostFormValue("redirect_uri")
paddy@87 120 if authCode.RedirectURI != redirectURI {
paddy@84 121 w.WriteHeader(http.StatusBadRequest)
paddy@84 122 renderJSONError(enc, "invalid_grant")
paddy@84 123 return
paddy@84 124 }
paddy@87 125 if !authCode.ClientID.Equal(clientID) {
paddy@84 126 w.WriteHeader(http.StatusBadRequest)
paddy@84 127 renderJSONError(enc, "invalid_grant")
paddy@84 128 return
paddy@84 129 }
paddy@87 130 return authCode.Scope, authCode.ProfileID, true
paddy@84 131 }
paddy@90 132
paddy@90 133 func authCodeGrantInvalidate(r *http.Request, context Context) error {
paddy@94 134 code := r.PostFormValue("code")
paddy@94 135 if code == "" {
paddy@94 136 return ErrAuthorizationCodeNotFound
paddy@94 137 }
paddy@94 138 return context.UseAuthorizationCode(code)
paddy@90 139 }