From 02b4ba4266022eb04a24933d4c12f15f4c335177 Mon Sep 17 00:00:00 2001 From: Victor Login Date: Mon, 12 Jun 2023 18:34:12 +0200 Subject: [PATCH] spicedb: improve auth module Signed-off-by: Victor Login --- .run/auth_spicedb.run.xml | 14 ----- internal/pkg/auth/auth.go | 21 +++++-- internal/pkg/auth/auth_test.go | 100 ++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 21 deletions(-) delete mode 100644 .run/auth_spicedb.run.xml diff --git a/.run/auth_spicedb.run.xml b/.run/auth_spicedb.run.xml deleted file mode 100644 index 425cf1fea67..00000000000 --- a/.run/auth_spicedb.run.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/internal/pkg/auth/auth.go b/internal/pkg/auth/auth.go index 7f3e73b41a7..e4abd6bfe3b 100644 --- a/internal/pkg/auth/auth.go +++ b/internal/pkg/auth/auth.go @@ -15,28 +15,39 @@ import ( "gopkg.in/yaml.v3" ) -// Migrations run the migrations for the authzed service. -func Migrations(ctx context.Context, fs embed.FS) error { +type Auth struct { + client *authzed.Client +} + +func New() (*Auth, error) { + var err error + auth := &Auth{} + viper.SetDefault("SPICE_DB_API", "shortlink.spicedb:50051") viper.SetDefault("SPICE_DB_COMMON_KEY", "secret-shortlink-preshared-key") - client, err := authzed.NewClient( + auth.client, err = authzed.NewClient( viper.GetString("SPICE_DB_API"), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(insecureMetadataCreds{"authorization": "Bearer " + viper.GetString("SPICE_DB_COMMON_KEY")}), grpc.WithBlock(), ) if err != nil { - return err + return nil, err } + return auth, nil +} + +// Migrations run the migrations for the authzed service. +func (a *Auth) Migrations(ctx context.Context, fs embed.FS) error { permissionsData, err := GetPermissions(fs) if err != nil { return err } for i := range permissionsData { - _, err = client.WriteSchema(ctx, permissionsData[i]) + _, err = a.client.WriteSchema(ctx, permissionsData[i]) if err != nil { return fmt.Errorf("Failed to write schema: %w", err) } diff --git a/internal/pkg/auth/auth_test.go b/internal/pkg/auth/auth_test.go index 20a262e3408..4f32152a362 100644 --- a/internal/pkg/auth/auth_test.go +++ b/internal/pkg/auth/auth_test.go @@ -10,6 +10,7 @@ import ( "testing" "testing/fstest" + pb "github.com/authzed/authzed-go/proto/authzed/api/v1" "github.com/ory/dockertest/v3" "github.com/stretchr/testify/require" ) @@ -48,6 +49,7 @@ schema: func TestSpiceDB(t *testing.T) { ctx := context.Background() + var client *Auth // uses a sensible default on windows (tcp/http) and linux/osx (socket) pool, err := dockertest.NewPool("") @@ -76,8 +78,8 @@ func TestSpiceDB(t *testing.T) { errSetenv = os.Setenv("SPICE_DB_API", fmt.Sprintf("localhost:%s", resource.GetPort("50051/tcp"))) require.NoError(t, errSetenv, "Cannot set ENV") - errMigrations := Migrations(ctx, permissions) - require.NoError(t, errMigrations, "Cannot migrate") + client, err = New() + require.NoError(t, err, "Cannot create client") return nil }); errRetry != nil { @@ -89,7 +91,101 @@ func TestSpiceDB(t *testing.T) { require.NoError(t, errRetry, "Could not connect to docker") } + // test migrations + t.Run("Migrations", func(t *testing.T) { + errMigrations := client.Migrations(ctx, permissions) + require.NoError(t, errMigrations, "Cannot migrate") + }) + + // mock data + emilia := &pb.SubjectReference{Object: &pb.ObjectReference{ + ObjectType: "user", + ObjectId: "emilia", + }} + + beatrice := &pb.SubjectReference{Object: &pb.ObjectReference{ + ObjectType: "user", + ObjectId: "beatrice", + }} + + firstItem := &pb.ObjectReference{ + ObjectType: "link", + ObjectId: "1", + } + + // test write + t.Run("Write", func(t *testing.T) { + request := &pb.WriteRelationshipsRequest{ + Updates: []*pb.RelationshipUpdate{ + { + // Emilia is a Writer on Post 1 + Operation: pb.RelationshipUpdate_OPERATION_CREATE, + Relationship: &pb.Relationship{ + Resource: firstItem, + Relation: "writer", + Subject: emilia, + }, + }, + { + // Beatrice is a Reader on Post 1 + Operation: pb.RelationshipUpdate_OPERATION_CREATE, + Relationship: &pb.Relationship{ + Resource: firstItem, + Relation: "reader", + Subject: beatrice, + }, + }, + }, + } + + _, errWrite := client.client.WriteRelationships(context.Background(), request) + require.NoError(t, errWrite) + }) + + // check permissions + t.Run("CheckPermissions", func(t *testing.T) { + resp, err := client.client.CheckPermission(ctx, &pb.CheckPermissionRequest{ + Resource: firstItem, + Permission: "view", + Subject: emilia, + }) + require.NoError(t, err, "Cannot check permission") + require.Equal(t, pb.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION, resp.Permissionship, "Emilia should have view permission") + + resp, err = client.client.CheckPermission(ctx, &pb.CheckPermissionRequest{ + Resource: firstItem, + Permission: "edit", + Subject: emilia, + }) + require.NoError(t, err, "Cannot check permission") + require.Equal(t, pb.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION, resp.Permissionship, "Emilia should have write permission") + + resp, err = client.client.CheckPermission(ctx, &pb.CheckPermissionRequest{ + Resource: firstItem, + Permission: "view", + Subject: beatrice, + }) + require.NoError(t, err, "Cannot check permission") + require.Equal(t, pb.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION, resp.Permissionship, "Beatrice should have view permission") + + resp, err = client.client.CheckPermission(ctx, &pb.CheckPermissionRequest{ + Resource: firstItem, + Permission: "edit", + Subject: beatrice, + }) + require.NoError(t, err, "Cannot check permission") + require.Equal(t, pb.CheckPermissionResponse_PERMISSIONSHIP_NO_PERMISSION, resp.Permissionship, "Beatrice should have write permission") + }) + t.Cleanup(func() { + // delete all data + _, errDelete := client.client.DeleteRelationships(ctx, &pb.DeleteRelationshipsRequest{ + RelationshipFilter: &pb.RelationshipFilter{ + ResourceType: "link", + }, + }) + require.NoError(t, errDelete, "Cannot delete relationships") + // When you're done, kill and remove the container if errPurge := pool.Purge(resource); errPurge != nil { t.Fatalf("Could not purge resource: %s", errPurge)