mirror of
https://github.com/kevin-DL/services.git
synced 2026-01-22 15:25:19 +00:00
Add tenancy to seen and otp services
This commit is contained in:
@@ -23,7 +23,7 @@ func (e *Otp) Generate(ctx context.Context, req *pb.GenerateRequest, rsp *pb.Gen
|
|||||||
// check if a key exists for the user
|
// check if a key exists for the user
|
||||||
var secret string
|
var secret string
|
||||||
|
|
||||||
if err := cache.Get(req.Id, &secret); err != nil {
|
if err := cache.Context(ctx).Get(req.Id, &secret); err != nil {
|
||||||
// generate a key
|
// generate a key
|
||||||
key, err := totp.Generate(totp.GenerateOpts{
|
key, err := totp.Generate(totp.GenerateOpts{
|
||||||
Issuer: "Micro",
|
Issuer: "Micro",
|
||||||
@@ -38,7 +38,7 @@ func (e *Otp) Generate(ctx context.Context, req *pb.GenerateRequest, rsp *pb.Gen
|
|||||||
|
|
||||||
secret = key.Secret()
|
secret = key.Secret()
|
||||||
|
|
||||||
if err := cache.Put(req.Id, secret, time.Now().Add(time.Minute*5)); err != nil {
|
if err := cache.Context(ctx).Put(req.Id, secret, time.Now().Add(time.Minute*5)); err != nil {
|
||||||
logger.Error("Failed to store secret: %v", err)
|
logger.Error("Failed to store secret: %v", err)
|
||||||
return errors.InternalServerError("otp.generate", "failed to generate code")
|
return errors.InternalServerError("otp.generate", "failed to generate code")
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func (e *Otp) Validate(ctx context.Context, req *pb.ValidateRequest, rsp *pb.Val
|
|||||||
|
|
||||||
var secret string
|
var secret string
|
||||||
|
|
||||||
if err := cache.Get(req.Id, &secret); err != nil {
|
if err := cache.Context(ctx).Get(req.Id, &secret); err != nil {
|
||||||
logger.Error("Failed to get secret from store: %v", err)
|
logger.Error("Failed to get secret from store: %v", err)
|
||||||
return errors.InternalServerError("otp.generate", "failed to validate code")
|
return errors.InternalServerError("otp.generate", "failed to validate code")
|
||||||
}
|
}
|
||||||
|
|||||||
38
pkg/cache/cache.go
vendored
38
pkg/cache/cache.go
vendored
@@ -2,20 +2,26 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/micro/micro/v3/service/store"
|
"github.com/micro/micro/v3/service/store"
|
||||||
|
"github.com/micro/services/pkg/tenant"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cache interface {
|
type Cache interface {
|
||||||
|
// Context returns a tenant scoped Cache
|
||||||
|
Context(ctx context.Context) Cache
|
||||||
Get(key string, val interface{}) error
|
Get(key string, val interface{}) error
|
||||||
Put(key string, val interface{}, expires time.Time) error
|
Put(key string, val interface{}, expires time.Time) error
|
||||||
Delete(key string) error
|
Delete(key string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type cache struct {
|
type cache struct {
|
||||||
Store store.Store
|
Store store.Store
|
||||||
|
Prefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -23,7 +29,25 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func New(st store.Store) Cache {
|
func New(st store.Store) Cache {
|
||||||
return &cache{st}
|
return &cache{Store: st}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) Key(k string) string {
|
||||||
|
if len(c.Prefix) > 0 {
|
||||||
|
return fmt.Sprintf("%s/%s", c.Prefix, k)
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache) Context(ctx context.Context) Cache {
|
||||||
|
t, ok := tenant.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return &cache{
|
||||||
|
Store: c.Store,
|
||||||
|
Prefix: t,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cache) Get(key string, val interface{}) error {
|
func (c *cache) Get(key string, val interface{}) error {
|
||||||
@@ -31,7 +55,7 @@ func (c *cache) Get(key string, val interface{}) error {
|
|||||||
c.Store = store.DefaultStore
|
c.Store = store.DefaultStore
|
||||||
}
|
}
|
||||||
|
|
||||||
recs, err := c.Store.Read(key, store.ReadLimit(1))
|
recs, err := c.Store.Read(c.Key(key), store.ReadLimit(1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -57,7 +81,7 @@ func (c *cache) Put(key string, val interface{}, expires time.Time) error {
|
|||||||
expiry = time.Duration(0)
|
expiry = time.Duration(0)
|
||||||
}
|
}
|
||||||
return c.Store.Write(&store.Record{
|
return c.Store.Write(&store.Record{
|
||||||
Key: key,
|
Key: c.Key(key),
|
||||||
Value: b,
|
Value: b,
|
||||||
Expiry: expiry,
|
Expiry: expiry,
|
||||||
})
|
})
|
||||||
@@ -67,7 +91,11 @@ func (c *cache) Delete(key string) error {
|
|||||||
if c.Store == nil {
|
if c.Store == nil {
|
||||||
c.Store = store.DefaultStore
|
c.Store = store.DefaultStore
|
||||||
}
|
}
|
||||||
return c.Store.Delete(key)
|
return c.Store.Delete(c.Key(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Context(ctx context.Context) Cache {
|
||||||
|
return DefaultCache.Context(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(key string, val interface{}) error {
|
func Get(key string, val interface{}) error {
|
||||||
|
|||||||
27
pkg/tenant/tenant.go
Normal file
27
pkg/tenant/tenant.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Package tenant provides multi-tenancy helpers
|
||||||
|
package tenant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/micro/micro/v3/service/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FromContext returns a tenant from the context
|
||||||
|
func FromContext(ctx context.Context) (string, bool) {
|
||||||
|
acc, ok := auth.AccountFromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return FromAccount(acc), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromAccount returns a tenant from
|
||||||
|
func FromAccount(acc *auth.Account) string {
|
||||||
|
owner := acc.Metadata["apikey_owner"]
|
||||||
|
if len(owner) == 0 {
|
||||||
|
owner = acc.ID
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/%s", acc.Issuer, owner)
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/micro/micro/v3/service/errors"
|
"github.com/micro/micro/v3/service/errors"
|
||||||
"github.com/micro/micro/v3/service/logger"
|
"github.com/micro/micro/v3/service/logger"
|
||||||
"github.com/micro/micro/v3/service/store"
|
"github.com/micro/micro/v3/service/store"
|
||||||
|
"github.com/micro/services/pkg/tenant"
|
||||||
pb "github.com/micro/services/seen/proto"
|
pb "github.com/micro/services/seen/proto"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
@@ -34,8 +35,15 @@ type Record struct {
|
|||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Record) Key() string {
|
func (r *Record) Key(ctx context.Context) string {
|
||||||
return fmt.Sprintf("%s:%s:%s", r.UserID, r.ResourceType, r.ResourceID)
|
key := fmt.Sprintf("%s:%s:%s", r.UserID, r.ResourceType, r.ResourceID)
|
||||||
|
|
||||||
|
t, ok := tenant.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s/%s", t, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Record) Marshal() []byte {
|
func (r *Record) Marshal() []byte {
|
||||||
@@ -76,7 +84,7 @@ func (s *Seen) Set(ctx context.Context, req *pb.SetRequest, rsp *pb.SetResponse)
|
|||||||
ResourceType: req.ResourceType,
|
ResourceType: req.ResourceType,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := store.Read(instance.Key(), store.ReadLimit(1))
|
_, err := store.Read(instance.Key(ctx), store.ReadLimit(1))
|
||||||
if err == store.ErrNotFound {
|
if err == store.ErrNotFound {
|
||||||
instance.ID = uuid.New().String()
|
instance.ID = uuid.New().String()
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -88,7 +96,7 @@ func (s *Seen) Set(ctx context.Context, req *pb.SetRequest, rsp *pb.SetResponse)
|
|||||||
instance.Timestamp = req.Timestamp.AsTime()
|
instance.Timestamp = req.Timestamp.AsTime()
|
||||||
|
|
||||||
if err := store.Write(&store.Record{
|
if err := store.Write(&store.Record{
|
||||||
Key: instance.Key(),
|
Key: instance.Key(ctx),
|
||||||
Value: instance.Marshal(),
|
Value: instance.Marshal(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Errorf("Error with store: %v", err)
|
logger.Errorf("Error with store: %v", err)
|
||||||
@@ -123,7 +131,7 @@ func (s *Seen) Unset(ctx context.Context, req *pb.UnsetRequest, rsp *pb.UnsetRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete the object from the store
|
// delete the object from the store
|
||||||
if err := store.Delete(instance.Key()); err != nil {
|
if err := store.Delete(instance.Key(ctx)); err != nil {
|
||||||
logger.Errorf("Error with store: %v", err)
|
logger.Errorf("Error with store: %v", err)
|
||||||
return ErrStore
|
return ErrStore
|
||||||
}
|
}
|
||||||
@@ -150,8 +158,10 @@ func (s *Seen) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadRespon
|
|||||||
return ErrMissingResourceType
|
return ErrMissingResourceType
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a key prefix
|
rec := &Record{
|
||||||
key := fmt.Sprintf("%s:%s:", req.UserId, req.ResourceType)
|
UserID: req.UserId,
|
||||||
|
ResourceType: req.ResourceType,
|
||||||
|
}
|
||||||
|
|
||||||
var recs []*store.Record
|
var recs []*store.Record
|
||||||
var err error
|
var err error
|
||||||
@@ -159,9 +169,14 @@ func (s *Seen) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadRespon
|
|||||||
// get the records for the resource type
|
// get the records for the resource type
|
||||||
if len(req.ResourceIds) == 1 {
|
if len(req.ResourceIds) == 1 {
|
||||||
// read the key itself
|
// read the key itself
|
||||||
key = key + req.ResourceIds[0]
|
rec.ResourceId = req.ResourceIds[0]
|
||||||
|
// gen key
|
||||||
|
key = rec.Key(ctx)
|
||||||
|
// get the record
|
||||||
recs, err = store.Read(key, store.ReadLimit(1))
|
recs, err = store.Read(key, store.ReadLimit(1))
|
||||||
} else {
|
} else {
|
||||||
|
// create a key prefix
|
||||||
|
key := rec.Key(ctx)
|
||||||
// otherwise read the prefix
|
// otherwise read the prefix
|
||||||
recs, err = store.Read(key, store.ReadPrefix())
|
recs, err = store.Read(key, store.ReadPrefix())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user