diff --git a/storage/storage.go b/storage/storage.go index 4a92485b..78c162f9 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -16,12 +16,12 @@ import ( ) var ( - // stubbed out for testing - now = time.Now -) + // ErrNotFound is the error returned by storages if a resource cannot be found. + ErrNotFound = errors.New("not found") -// ErrNotFound is the error returned by storages if a resource cannot be found. -var ErrNotFound = errors.New("not found") + // ErrAlreadyExists is the error returned by storages if a resource ID is taken during a create. + ErrAlreadyExists = errors.New("ID already exists") +) // Kubernetes only allows lower case letters for names. // @@ -51,6 +51,7 @@ type Storage interface { CreateClient(c Client) error CreateAuthCode(c AuthCode) error CreateRefresh(r RefreshToken) error + CreatePassword(p Password) error // TODO(ericchiang): return (T, bool, error) so we can indicate not found // requests that way instead of using ErrNotFound. @@ -59,6 +60,7 @@ type Storage interface { GetClient(id string) (Client, error) GetKeys() (Keys, error) GetRefresh(id string) (RefreshToken, error) + GetPassword(email string) (Password, error) ListClients() ([]Client, error) ListRefreshTokens() ([]RefreshToken, error) @@ -68,6 +70,7 @@ type Storage interface { DeleteAuthCode(code string) error DeleteClient(id string) error DeleteRefresh(id string) error + DeletePassword(email string) error // Update functions are assumed to be a performed within a single object transaction. // @@ -75,6 +78,7 @@ type Storage interface { UpdateClient(id string, updater func(old Client) (Client, error)) error UpdateKeys(updater func(old Keys) (Keys, error)) error UpdateAuthRequest(id string, updater func(a AuthRequest) (AuthRequest, error)) error + UpdatePassword(email string, updater func(p Password) (Password, error)) error // TODO(ericchiang): Add a GarbageCollect(now time.Time) method so conformance tests // can test implementations. @@ -217,6 +221,28 @@ type RefreshToken struct { Nonce string } +// Password is an email to password mapping managed by the storage. +type Password struct { + // Email and identifying name of the password. Emails are assumed to be valid and + // determining that an end-user controls the address is left to an outside application. + // + // Emails are case insensitive and should be standardized by the storage. + // + // Storages that don't support an extended character set for IDs, such as '.' and '@' + // (cough cough, kubernetes), must map this value appropriately. + Email string `yaml:"email"` + + // Bcrypt encoded hash of the password. This package recommends a cost value of at + // least 14. + Hash []byte `yaml:"hash"` + + // Optional username to display. NOT used during login. + Username string `yaml:"username"` + + // Randomly generated user ID. This is NOT the primary ID of the Password object. + UserID string `yaml:"userID"` +} + // VerificationKey is a rotated signing key which can still be used to verify // signatures. type VerificationKey struct {