Skip to content

Commit

Permalink
feat: add authz store
Browse files Browse the repository at this point in the history
  • Loading branch information
katallaxie authored Aug 1, 2024
1 parent e4d1c13 commit 2235982
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 10 deletions.
90 changes: 80 additions & 10 deletions authz/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,35 @@ import (
"context"

"github.com/openfga/go-sdk/client"
"github.com/zeiss/pkg/cast"
"github.com/zeiss/pkg/conv"
)

// User is the user that is making the request.
type User string

// Object is the object that is being accessed.
type Object string

// Relation is the relation between the user and the object.
type Relation string

// Store is an interface that provides methods for transactional operations on the authz database.
type Store[Tx any] interface {
// Allowed checks if the user is allowed to perform the operation on the object.
Allowed(context.Context, User, Object, Relation) (bool, error)
// WriteTx starts a read write transaction.
WriteTx(context.Context, func(context.Context, Tx) error) error
}

// StoreTx is an interface that provides methods for transactional operations on the authz database.
type StoreTx interface {
// WriteTuple writes a tuple to the authz database.
WriteTuple(context.Context, User, Object, Relation) error
// DeleteTuple deletes a tuple from the authz database.
DeleteTuple(context.Context, User, Object, Relation) error
}

// AuthzError is an error that occurred while executing a query.
type AuthzError struct {
// Op is the operation that caused the error.
Expand Down Expand Up @@ -40,16 +61,39 @@ type storeImpl[W any] struct {
}

// StoreTxFactory is a function that creates a new instance of authz store.
type StoreTxFactory[Tx any] func(*client.OpenFgaClient) (Tx, error)
type StoreTxFactory[Tx any] func(*client.OpenFgaClient, StoreTx) (Tx, error)

// NewStore returns a new instance of authz store.
func NewStore[Tx any](client *client.OpenFgaClient, tx StoreTxFactory[Tx]) (Store[Tx], error) {
return &storeImpl[Tx]{tx, client}, nil
}

// Allowed checks if the user is allowed to perform the operation on the object.
func (t *storeImpl[W]) Allowed(ctx context.Context, user User, object Object, relation Relation) (bool, error) {
opts := client.ClientCheckOptions{}

body := client.ClientCheckRequest{
User: conv.String(user),
Relation: conv.String(relation),
Object: conv.String(object),
}

data, err := t.client.Check(ctx).Options(opts).Body(body).Execute()
if err != nil {
return false, err
}

ok := cast.Value(data.Allowed)
if ok {
return true, nil
}

return false, nil
}

// ReadWriteTx starts a read only transaction.
func (s *storeImpl[Tx]) WriteTx(ctx context.Context, fn func(context.Context, Tx) error) error {
t, err := s.tx(s.client)
t, err := s.tx(s.client, s)
if err != nil {
return err
}
Expand All @@ -61,16 +105,42 @@ func (s *storeImpl[Tx]) WriteTx(ctx context.Context, fn func(context.Context, Tx
return nil
}

type defaultStoreTxImpl struct {
client *client.OpenFgaClient
// WriteTuple writes a tuple to the authz database.
func (s *storeImpl[Tx]) WriteTuple(ctx context.Context, user User, object Object, relation Relation) error {
body := client.ClientWriteRequest{
Writes: []client.ClientTupleKey{
{
User: conv.String(user),
Relation: conv.String(relation),
Object: conv.String(object),
},
},
}

_, err := s.client.Write(ctx).Body(body).Execute()
if err != nil {
return err
}

return nil
}

// DefaultStoreTx is a default authz store transaction.
type DefaultStoreTx interface{}
// DeleteTuple deletes a tuple from the authz database.
func (s *storeImpl[Tx]) DeleteTuple(ctx context.Context, user User, object Object, relation Relation) error {
body := client.ClientWriteRequest{
Deletes: []client.ClientTupleKeyWithoutCondition{
{
User: conv.String(user),
Relation: conv.String(relation),
Object: conv.String(object),
},
},
}

// NewDefaultStoreTx returns a new instance of default authz store transaction.
func NewDefaultStoreTx() StoreTxFactory[DefaultStoreTx] {
return func(fga *client.OpenFgaClient) (DefaultStoreTx, error) {
return &defaultStoreTxImpl{client: fga}, nil
_, err := s.client.Write(ctx).Body(body).Execute()
if err != nil {
return err
}

return nil
}
6 changes: 6 additions & 0 deletions conv/string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package conv

// String is a type that represents a string.
func String[T ~string](val T) string {
return string(val)
}

0 comments on commit 2235982

Please sign in to comment.