storage: add a password resource
This commit is contained in:
		| @@ -16,12 +16,12 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	// stubbed out for testing |  | ||||||
| 	now = time.Now |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| 	// ErrNotFound is the error returned by storages if a resource cannot be found. | 	// ErrNotFound is the error returned by storages if a resource cannot be found. | ||||||
| var ErrNotFound = errors.New("not found") | 	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. | // Kubernetes only allows lower case letters for names. | ||||||
| // | // | ||||||
| @@ -51,6 +51,7 @@ type Storage interface { | |||||||
| 	CreateClient(c Client) error | 	CreateClient(c Client) error | ||||||
| 	CreateAuthCode(c AuthCode) error | 	CreateAuthCode(c AuthCode) error | ||||||
| 	CreateRefresh(r RefreshToken) error | 	CreateRefresh(r RefreshToken) error | ||||||
|  | 	CreatePassword(p Password) error | ||||||
|  |  | ||||||
| 	// TODO(ericchiang): return (T, bool, error) so we can indicate not found | 	// TODO(ericchiang): return (T, bool, error) so we can indicate not found | ||||||
| 	// requests that way instead of using ErrNotFound. | 	// requests that way instead of using ErrNotFound. | ||||||
| @@ -59,6 +60,7 @@ type Storage interface { | |||||||
| 	GetClient(id string) (Client, error) | 	GetClient(id string) (Client, error) | ||||||
| 	GetKeys() (Keys, error) | 	GetKeys() (Keys, error) | ||||||
| 	GetRefresh(id string) (RefreshToken, error) | 	GetRefresh(id string) (RefreshToken, error) | ||||||
|  | 	GetPassword(email string) (Password, error) | ||||||
|  |  | ||||||
| 	ListClients() ([]Client, error) | 	ListClients() ([]Client, error) | ||||||
| 	ListRefreshTokens() ([]RefreshToken, error) | 	ListRefreshTokens() ([]RefreshToken, error) | ||||||
| @@ -68,6 +70,7 @@ type Storage interface { | |||||||
| 	DeleteAuthCode(code string) error | 	DeleteAuthCode(code string) error | ||||||
| 	DeleteClient(id string) error | 	DeleteClient(id string) error | ||||||
| 	DeleteRefresh(id string) error | 	DeleteRefresh(id string) error | ||||||
|  | 	DeletePassword(email string) error | ||||||
|  |  | ||||||
| 	// Update functions are assumed to be a performed within a single object transaction. | 	// 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 | 	UpdateClient(id string, updater func(old Client) (Client, error)) error | ||||||
| 	UpdateKeys(updater func(old Keys) (Keys, error)) error | 	UpdateKeys(updater func(old Keys) (Keys, error)) error | ||||||
| 	UpdateAuthRequest(id string, updater func(a AuthRequest) (AuthRequest, 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 | 	// TODO(ericchiang): Add a GarbageCollect(now time.Time) method so conformance tests | ||||||
| 	// can test implementations. | 	// can test implementations. | ||||||
| @@ -217,6 +221,28 @@ type RefreshToken struct { | |||||||
| 	Nonce string | 	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 | // VerificationKey is a rotated signing key which can still be used to verify | ||||||
| // signatures. | // signatures. | ||||||
| type VerificationKey struct { | type VerificationKey struct { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user