Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1 example #34

Merged
merged 4 commits into from Oct 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yaml
Expand Up @@ -2,10 +2,10 @@ name: "build"
on:
push:
branches:
- "!dependabot/*"
- "*"
- "master"
pull_request:
branches:
- "!dependabot/*"
- "*"
jobs:
lint:
Expand Down Expand Up @@ -62,6 +62,6 @@ jobs:
- uses: "actions/checkout@v2"
- uses: "bufbuild/buf-setup-action@v0.5.0"
with:
version: "0.56.0"
version: "1.0.0-rc6"
- name: "Generate & Diff Protos"
run: "./buf.gen.yaml && git diff && bash -c '[ $(git status --porcelain | tee /dev/fd/2 | wc -c) -eq 0 ]'"
123 changes: 0 additions & 123 deletions examples/v0/example.go

This file was deleted.

71 changes: 0 additions & 71 deletions examples/v0/yourtenant.yaml

This file was deleted.

160 changes: 160 additions & 0 deletions examples/v1/example.go
@@ -0,0 +1,160 @@
package main

import (
"context"
"log"

"github.com/authzed/grpcutil"

v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/authzed/authzed-go/v1"
)

const (
documentNS = "yourtenant/document"
userNS = "yourtenant/user"

schema = `
definition yourtenant/user {}

definition yourtenant/document {
relation viewer: yourtenant/user
relation contributor: yourtenant/user
relation owner: yourtenant/user

permission read = viewer + contributor + owner
permission write = contributor + owner
permission delete = owner
}
`
)

func main() {
// Create an Authzed client.
client, err := authzed.NewClient(
"grpc.authzed.com:443",
grpcutil.WithInsecureBearerToken("t_your_token_here"),
grpcutil.WithSystemCerts(grpcutil.VerifyCA),
)
if err != nil {
log.Fatalf("unable to initialize client: %s", err)
}

// Uncomment this block to run against a local SpiceDB.
// client, err = authzed.NewClient(
// "localhost:50051",
// grpcutil.WithInsecureBearerToken("testtesttesttest"),
// grpc.WithInsecure(),
// )
// if err != nil {
// log.Fatalf("unable to initialize client: %s", err)
// }

// Write the schema to the permissions system
_, err = client.WriteSchema(context.Background(), &v1.WriteSchemaRequest{
Schema: schema,
})
if err != nil {
log.Fatalf("unable to write schema: %s", err)
}

// Create some objects that will be protected by Authzed.
aDoc := object(documentNS, "doc1")
anOwner := subject(userNS, "theowner")
anEditor := subject(userNS, "userwhocanedit")
aViewer := subject(userNS, "viewonlyuser")

// Create some relationships that represent roles granted between users and objects.
resp, err := client.WriteRelationships(context.Background(), &v1.WriteRelationshipsRequest{
Updates: []*v1.RelationshipUpdate{
createRelationship(relationship(aDoc, "owner", anOwner)),
createRelationship(relationship(aDoc, "contributor", anEditor)),
createRelationship(relationship(aDoc, "viewer", aViewer)),
},
})
if err != nil {
log.Fatalf("unable to write tuples: %s", err)
}

// Save the ZedToken from the Write for future requests in order to enforce
// that responses are at least as fresh as our last write.
//
// We recommend saving this from any call to WriteRelationships and storing it
// alongside the object referenced in the write or check (in this case aDoc)"
//
// For more info see:
// https://github.com/authzed/spicedb/blob/main/docs/zedtokens-and-zookies.md
whenPermsChanged := resp.WrittenAt

// Run some permission checks on the written data.
aNobody := subject(userNS, "randomnobody")
expected := []struct {
resource *v1.ObjectReference
permission string
subject *v1.SubjectReference
hasAccess bool
}{
{aDoc, "read", anOwner, true},
{aDoc, "write", anOwner, true},
{aDoc, "delete", anOwner, true},
{aDoc, "read", anEditor, true},
{aDoc, "write", anEditor, true},
{aDoc, "delete", anEditor, false},
{aDoc, "read", aViewer, true},
{aDoc, "write", aViewer, false},
{aDoc, "delete", aViewer, false},
{aDoc, "read", aNobody, false},
{aDoc, "write", aNobody, false},
{aDoc, "delete", aNobody, false},
}

for _, test := range expected {
testResp, err := client.CheckPermission(context.Background(), &v1.CheckPermissionRequest{
// Guarantee checks occur on data fresher than the write.
Consistency: &v1.Consistency{
Requirement: &v1.Consistency_AtLeastAsFresh{
AtLeastAsFresh: whenPermsChanged,
},
},
Resource: test.resource,
Permission: test.permission,
Subject: test.subject,
})
if err != nil {
log.Fatalf("unable to run check request: %s", err)
}

hasAccess := testResp.Permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_HAS_PERMISSION
if hasAccess != test.hasAccess {
log.Fatalf("check returned the wrong result: %#v", test)
}
}
}

func object(namespace, objectID string) *v1.ObjectReference {
return &v1.ObjectReference{
ObjectType: namespace,
ObjectId: objectID,
}
}

func subject(namespace, objectID string) *v1.SubjectReference {
return &v1.SubjectReference{
Object: object(namespace, objectID),
}
}

func relationship(resource *v1.ObjectReference, relation string, subject *v1.SubjectReference) *v1.Relationship {
return &v1.Relationship{
Resource: resource,
Relation: relation,
Subject: subject,
}
}

func createRelationship(relationship *v1.Relationship) *v1.RelationshipUpdate {
return &v1.RelationshipUpdate{
Operation: v1.RelationshipUpdate_OPERATION_CREATE,
Relationship: relationship,
}
}