micro/auth/store/store.go
ben-toogood ffdf986aac
Refactor auth: add token and store implementations (#1230)
* Refactor auth: add token and memory implementations

* Fix typo

* Remove memory auth (implemented already by the store implementation), revert default to noop

* Add grpc header

* Global Config

* config/global => util/config

* Rename package to remove confict

* Tweak

* Improve Error Handling
2020-02-24 15:07:27 +00:00

129 lines
2.6 KiB
Go

package store
import (
"bytes"
"encoding/gob"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/store"
)
// NewAuth returns an instance of store auth
func NewAuth(opts ...auth.Option) auth.Auth {
options := auth.Options{}
for _, o := range opts {
o(&options)
}
return &Auth{
store: store.DefaultStore,
opts: options,
}
}
type Auth struct {
store store.Store
opts auth.Options
}
// Init the auth package
func (a *Auth) Init(opts ...auth.Option) error {
for _, o := range opts {
o(&a.opts)
}
return nil
}
// Options returns the options set
func (a *Auth) Options() auth.Options {
return a.opts
}
// Generate a new auth Account
func (a *Auth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
// generate the token
token, err := uuid.NewUUID()
if err != nil {
return nil, err
}
// parse the options
options := auth.NewGenerateOptions(opts...)
// construct the account
sa := auth.Account{
Id: id,
Token: token.String(),
Created: time.Now(),
Metadata: options.Metadata,
Roles: options.Roles,
}
// encode the data to bytes
buf := &bytes.Buffer{}
e := gob.NewEncoder(buf)
if err := e.Encode(sa); err != nil {
return nil, err
}
// write to the store
err = a.store.Write(&store.Record{
Key: token.String(),
Value: buf.Bytes(),
})
if err != nil {
return nil, err
}
// return the result
return &sa, nil
}
// Revoke an authorization Account
func (a *Auth) Revoke(token string) error {
records, err := a.store.Read(token, store.ReadSuffix())
if err != nil {
return err
}
if len(records) == 0 {
return errors.BadRequest("go.micro.auth", "token not found")
}
for _, r := range records {
if err := a.store.Delete(r.Key); err != nil {
return errors.InternalServerError("go.micro.auth", "error deleting from store")
}
}
return nil
}
// Validate an account token
func (a *Auth) Validate(token string) (*auth.Account, error) {
// lookup the record by token
records, err := a.store.Read(token, store.ReadSuffix())
if err == store.ErrNotFound || len(records) == 0 {
return nil, errors.Unauthorized("go.micro.auth", "invalid token")
} else if err != nil {
return nil, errors.InternalServerError("go.micro.auth", "error reading store")
}
// decode the result
b := bytes.NewBuffer(records[0].Value)
decoder := gob.NewDecoder(b)
var sa auth.Account
err = decoder.Decode(&sa)
// return the result
return &sa, err
}
// String returns the implementation
func (a *Auth) String() string {
return "store"
}