Skip to content

Commit

Permalink
PR: Rename and split to permission package
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzadlone committed Feb 25, 2024
1 parent 78a9b65 commit 0e573d5
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 120 deletions.
14 changes: 0 additions & 14 deletions client/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,20 +185,6 @@ type Collection interface {
GetIndexes(ctx context.Context) ([]IndexDescription, error)
}

// IsPermissioned returns true if the collection has a policy, otherwise returns false.
//
// This tells us if access control is enabled for this collection or not.
func IsPermissioned(c Collection) (string, string, bool) {
policy := c.Definition().Description.Policy
if policy.HasValue() &&
policy.Value().ID != "" &&
policy.Value().ResourceName != "" {
return policy.Value().ID, policy.Value().ResourceName, true
}

return "", "", false
}

// DocIDResult wraps the result of an attempt at a DocID retrieval operation.
type DocIDResult struct {
// If a DocID was successfully retrieved, this will be that DocID.
Expand Down
2 changes: 1 addition & 1 deletion db/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,7 @@ func (c *collection) create(ctx context.Context, txn datastore.Txn, doc *client.
return err
}

return c.tryRegisterDocWithACP(ctx, doc)
return c.registerDocCreation(ctx, doc.ID().String())
}

// Update an existing document with the new values.
Expand Down
54 changes: 22 additions & 32 deletions db/collection_acp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,29 @@ package db
import (
"context"

"github.com/sourcenetwork/defradb/client"
"github.com/sourcenetwork/defradb/acp"
"github.com/sourcenetwork/defradb/db/permission"
)

// tryRegisterDocWithACP handles the registeration of the document with acp module,
// according to our registration logic based on weather (1) the request is permissioned,
// (2) the collection is permissioned (has a policy), (3) acp module exists.
//
// Note: we only register the document with ACP if all (1) (2) and (3) are true.
// In all other cases, nothing is registered with ACP.
//
// Moreover 8 states, upon document creation:
// - (SignatureRequest, PermissionedCollection, ModuleExists) => Register with ACP
// - (SignatureRequest, PermissionedCollection, !ModuleExists) => Normal/Public - Don't Register with ACP
// - (SignatureRequest, !PermissionedCollection, ModuleExists) => Normal/Public - Don't Register with ACP
// - (SignatureRequest, !PermissionedCollection, !ModuleExists) => Normal/Public - Don't Register with ACP
// - (!SignatureRequest, PermissionedCollection, ModuleExists) => Normal/Public - Don't Register with ACP
// - (!SignatureRequest, !PermissionedCollection, ModuleExists) => Normal/Public - Don't Register with ACP
// - (!SignatureRequest, PermissionedCollection, !ModuleExists) => Normal/Public - Don't Register with ACP
// - (!SignatureRequest, !PermissionedCollection, !ModuleExists) => Normal/Public - Don't Register with ACP
func (c *collection) tryRegisterDocWithACP(ctx context.Context, doc *client.Document) error {
// Check if acp module exists.
if c.db.ACPModule().HasValue() {
// Check if collection has policy.
if policyID, resourceName, hasPolicy := client.IsPermissioned(c); hasPolicy {
return c.db.ACPModule().Value().RegisterDocCreation(
ctx,
"cosmos1zzg43wdrhmmk89z3pmejwete2kkd4a3vn7w969", // TODO-ACP: Replace with signature identity
policyID,
resourceName,
doc.ID().String(),
)
}
}
func (c *collection) registerDocCreation(ctx context.Context, docID string) error {
return permission.RegisterDocCreationOnCollection(
ctx,
c.db.ACPModule(),
c,
docID,
)
}

return nil
func (c *collection) checkDocPermissionedAccess(
ctx context.Context,
dpiPermission acp.DPIPermission,
docID string,
) (bool, error) {
return permission.CheckDocPermissionedAccessOnCollection(
ctx,
c.db.ACPModule(),
c,
dpiPermission,
docID,
)
}
74 changes: 1 addition & 73 deletions db/fetcher/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,78 +576,6 @@ func (df *DocumentFetcher) FetchNext(ctx context.Context) (EncodedDocument, Exec
return encdoc, resultExecInfo, err
}

// runDocumentReadPermissionCheck handles the checking (while fetching) if the document has read access
// or not, according to our access logic based on weather (1) the request is permissioned,
// (2) the collection is permissioned (has a policy), (3) acp module exists.
//
// Note: we only need to make a call to the acp module if (2) and (3) are true, where if (1) is true
// we then check passes only if the document has proper access, otherwise if (1) is false then
// the check passes only if the document is public (is not registered with acp module at all).
//
// Moreover 8 states, upon checking access:
// (SignatureRequest, PermissionedCollection, ModuleExists) => Must pass ACP check, unless public (not registered)
// (!SignatureRequest, PermissionedCollection, ModuleExists) => Only public (No access if registered with ACP)
// (SignatureRequest, PermissionedCollection, !ModuleExists) => No check needed
// (SignatureRequest, !PermissionedCollection, ModuleExists) => No check needed
// (SignatureRequest, !PermissionedCollection, !ModuleExists) => No check needed
// (!SignatureRequest, !PermissionedCollection, ModuleExists) => No check needed
// (!SignatureRequest, PermissionedCollection, !ModuleExists) => No check needed
// (!SignatureRequest, !PermissionedCollection, !ModuleExists) => No check needed
func (df *DocumentFetcher) runDocumentReadPermissionCheck(ctx context.Context) error {
// If no acp module, then we have unrestricted access.
if !df.acp.HasValue() {
df.passedPermissionCheck = true
return nil
}

// Even if acp module exists, but there is no policy on the collection (unpermissioned collection)
// then we still have unrestricted access.
policyID, resourceName, hasPolicy := client.IsPermissioned(df.col)
if !hasPolicy {
df.passedPermissionCheck = true
return nil
}

// TODO-ACP: Implement signatures
hasSignature := true

// Now that we know acp module exists and the collection is permissioned, handle based on signature.
if hasSignature {
hasAccess, err := df.acp.Value().CheckDocAccess(
ctx,
acp.ReadPermission,
"cosmos1zzg43wdrhmmk89z3pmejwete2kkd4a3vn7w969", // TODO-ACP: Replace with signature identity
policyID,
resourceName,
df.kv.Key.DocID,
)
if err != nil {
df.passedPermissionCheck = false
return err
}
df.passedPermissionCheck = hasAccess
return nil
}

// If does not have signature, we need to make sure we don't operate on registered documents.
// In this case actor only has access to the public (unregistered) documents.
isRegistered, err := df.acp.Value().IsDocRegistered(
ctx,
policyID,
resourceName,
df.kv.Key.DocID,
)
if err != nil {
df.passedPermissionCheck = false
return err
}

// Check passes if document is NOT registered. If it is registered then the
// document must not be accessed.
df.passedPermissionCheck = !isRegistered
return nil
}

func (df *DocumentFetcher) fetchNext(ctx context.Context) (EncodedDocument, ExecInfo, error) {
if df.kvEnd {
return nil, ExecInfo{}, nil
Expand Down Expand Up @@ -687,7 +615,7 @@ func (df *DocumentFetcher) fetchNext(ctx context.Context) (EncodedDocument, Exec

// Check if can access document with current permissions/signature.
if !df.passedPermissionCheck {
if err := df.runDocumentReadPermissionCheck(ctx); err != nil {
if err := df.runDocReadPermissionCheck(ctx); err != nil {
return nil, ExecInfo{}, err
}
}
Expand Down
39 changes: 39 additions & 0 deletions db/fetcher/fetcher_acp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2024 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package fetcher

import (
"context"

"github.com/sourcenetwork/defradb/acp"
"github.com/sourcenetwork/defradb/db/permission"
)

// runDocReadPermissionCheck handles the checking (while fetching) if the document has read access
// or not, according to our access logic based on weather (1) the request is permissioned,
// (2) the collection is permissioned (has a policy), (3) acp module exists.
func (df *DocumentFetcher) runDocReadPermissionCheck(ctx context.Context) error {
hasPermission, err := permission.CheckDocPermissionedAccessOnCollection(
ctx,
df.acp,
df.col,
acp.ReadPermission,
df.kv.Key.DocID,
)

if err != nil {
df.passedPermissionCheck = false
return err
}

df.passedPermissionCheck = hasPermission
return nil
}

0 comments on commit 0e573d5

Please sign in to comment.