Now loading policies, have tests checking OPA decisions

This commit is contained in:
Fletcher Haynes 2023-02-27 23:53:54 -08:00
parent c96adc85fc
commit 39dd2e7bed
9 changed files with 208 additions and 10 deletions

73
rbac/enforcer.go Normal file
View file

@ -0,0 +1,73 @@
package rbac
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"github.com/open-policy-agent/opa/sdk"
sdktest "github.com/open-policy-agent/opa/sdk/test"
)
type ABACPolicyEnforcer struct {
S *sdk.OPA
CTX context.Context
Server *sdktest.Server
}
func NewABACPolicyEnforcer() (*ABACPolicyEnforcer, error) {
ctx := context.Background()
policy, err := ioutil.ReadFile("example_policy.rego")
if err != nil {
return nil, err
}
policyS := string(policy)
server, err := sdktest.NewServer(sdktest.MockBundle("/bundles/bundle.tar.gz", map[string]string{
"example.rego": policyS,
}))
if err != nil {
return nil, err
}
config := []byte(fmt.Sprintf(`{
"services": {
"test": {
"url": %q
}
},
"bundles": {
"test": {
"resource": "/bundles/bundle.tar.gz"
}
},
"decision_logs": {
"console": true
}
}`, server.URL()))
opa, err := sdk.New(ctx, sdk.Options{
Config: bytes.NewReader(config),
})
if err != nil {
return nil, err
}
return &ABACPolicyEnforcer{
S: opa,
CTX: ctx,
Server: server,
}, nil
}
func readPolicyFile(p string) ([]byte, error) {
policyData, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
return policyData, nil
}

37
rbac/enforcer_test.go Normal file
View file

@ -0,0 +1,37 @@
package rbac_test
import (
"testing"
"github.com/featurebasedb/featurebase/v3/rbac"
"github.com/open-policy-agent/opa/sdk"
)
func TestCreateABACPolicyEnforcer(t *testing.T) {
enf, err := rbac.NewABACPolicyEnforcer()
if err != nil {
t.Errorf("Error creating ABACPolicyEnforcer: %s", err)
}
defer enf.Server.Stop()
defer enf.S.Stop(enf.CTX)
result, err := enf.S.Decision(enf.CTX, sdk.DecisionOptions{Path: "/featurebase/authz/allow", Input: map[string]interface{}{"open": "sesame"}})
if err != nil {
t.Errorf("Error testing OPA decision: %s", err)
}
if result.Result.(bool) != false {
t.Errorf("Result was not false!")
}
result, err = enf.S.Decision(enf.CTX, sdk.DecisionOptions{Path: "/featurebase/authz/allow", Input: map[string]interface{}{"method": "SELECT", "path": "index_a", "user": "fletcher"}})
if err != nil {
t.Errorf("Error testing OPA decision: %s", err)
}
if result.Result.(bool) != true {
t.Errorf("Result was not true!")
}
}

11
rbac/errors.go Normal file
View file

@ -0,0 +1,11 @@
package rbac
import "fmt"
type RBACError struct {
err string
}
func (e RBACError) Error() string {
return fmt.Sprintf("RBACError: %s", e.err)
}

View file

@ -1,8 +1,3 @@
---
user:
name: fletcher
email: fletcher.haynes@featurebase.com
---
group:
name: employees

10
rbac/example_policy.rego Normal file
View file

@ -0,0 +1,10 @@
package featurebase.authz
default allow = false
allow {
input.method = "SELECT"
input.path = "index_a"
input.user = "fletcher"
}

1
rbac/opa.go Normal file
View file

@ -0,0 +1 @@
package rbac

View file

@ -1,6 +1,12 @@
package rbac
import "google.golang.org/genproto/googleapis/type/datetime"
import (
"fmt"
"io/ioutil"
"time"
"gopkg.in/yaml.v2"
)
type FBUserStatus int32
@ -11,9 +17,42 @@ const (
)
type FBUser struct {
Username string
Email string
Created datetime.DateTime
LastActivity datetime.DateTime
Username string `yaml:"username"`
Email string `yaml:"email"`
Created time.Time
LastActivity time.Time
Status FBUserStatus
}
func NewFBUser(username, email string) FBUser {
newUser := FBUser{
Username: username,
Email: email,
Created: time.Now(),
LastActivity: time.Now(),
Status: Active,
}
return newUser
}
func LoadUsersFromYAML(p string) ([]FBUser, error) {
usersData := make(map[string][]map[string]string)
users := make([]FBUser, 0)
data, err := ioutil.ReadFile(p)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(data, usersData)
if err != nil {
return nil, err
}
fmt.Printf("Users are: %v", usersData)
for _, user := range usersData["users"] {
newUser := FBUser{
Username: user["name"],
Email: user["email"],
}
users = append(users, newUser)
}
return users, nil
}

27
rbac/user_test.go Normal file
View file

@ -0,0 +1,27 @@
package rbac_test
import (
"testing"
"github.com/featurebasedb/featurebase/v3/rbac"
)
func TestCreateUserFromYAML(t *testing.T) {
users, err := rbac.LoadUsersFromYAML("users.yaml")
if err != nil {
t.Errorf("Error loading test users from YAML: %s", err)
}
if len(users) != 1 {
t.Errorf("Expected 1 user to be loaded from YAML. Got %d", len(users))
}
if users[0].Username != "fletcher" {
t.Errorf("Expected test user username to be fletcher. Got %s", users[0].Username)
}
if users[0].Email != "fletcher.haynes@featurebase.com" {
t.Errorf("Expected test user email to be fletcher.haynes@featurebase.com. Got %s", users[0].Email)
}
}

5
rbac/users.yaml Normal file
View file

@ -0,0 +1,5 @@
---
users:
- name: fletcher
email: fletcher.haynes@featurebase.com