From f2c6689d2f775b1aed907d553c42d87c8464e6c7 Mon Sep 17 00:00:00 2001 From: Jake Van Vorhis <83739412+jakedoublev@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:02:46 -0700 Subject: [PATCH] feat(core): support kas grants to namespaces (#292) Closes #269 --- .github/workflows/ci.yaml | 4 +- cmd/kas-grants.go | 101 ++++++++++++++----- cmd/kas-registry.go | 2 +- cmd/policy-attributeNamespaces.go | 2 +- cmd/policy-attributeValues.go | 2 +- cmd/policy-attributes.go | 2 +- cmd/policy-resourceMappings.go | 2 +- cmd/policy-subjectConditionSets.go | 2 +- cmd/policy-subject_mappings.go | 2 +- docs/man/policy/kas-grants/assign.md | 9 +- docs/man/policy/kas-grants/unassign.md | 5 + docs/man/policy/kas-registry/_index.md | 2 +- go.sum | 2 - pkg/cli/confirm.go | 5 +- pkg/handlers/kas-grants.go | 49 ++++++++-- tests/kas-grants.bats | 129 +++++++++++++++++++++++++ 16 files changed, 275 insertions(+), 45 deletions(-) create mode 100755 tests/kas-grants.bats diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 62856a2e..0e5b2917 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -66,6 +66,8 @@ jobs: working-directory: platform - run: go run ./service provision keycloak working-directory: platform + - run: go run ./service provision fixtures + working-directory: platform - uses: JarvusInnovations/background-action@2428e7b970a846423095c79d43f759abf979a635 name: start server in background with: @@ -85,4 +87,4 @@ jobs: - name: Setup Bats and bats libs uses: bats-core/bats-action@2.0.0 - run: tests/encrypt-decrypt.bats - + - run: tests/kas-grants.bats diff --git a/cmd/kas-grants.go b/cmd/kas-grants.go index ff5cdbc3..a391599f 100644 --- a/cmd/kas-grants.go +++ b/cmd/kas-grants.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "github.com/opentdf/otdfctl/pkg/cli" @@ -8,23 +9,33 @@ import ( "github.com/spf13/cobra" ) +var forceFlagValue = false + func policy_assignKasGrant(cmd *cobra.Command, args []string) { h := NewHandler(cmd) defer h.Close() flagHelper := cli.NewFlagHelper(cmd) - + nsID := flagHelper.GetOptionalString("namespace-id") attrID := flagHelper.GetOptionalString("attribute-id") valID := flagHelper.GetOptionalString("value-id") kasID := flagHelper.GetRequiredString("kas-id") - if attrID == "" && valID == "" { - cli.ExitWithError("Must specify and Attribute Definition ID or Value ID to assign a KAS Grant.", nil) + + count := 0 + for _, v := range []string{nsID, attrID, valID} { + if v != "" { + count++ + } + } + if count != 1 { + cli.ExitWithError("Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to assign", errors.New("invalid flag values")) } + var ( - id string - header string - res interface{} - err error + id string + res interface{} + err error + rowID []string ) kas, err := h.GetKasRegistryEntry(kasID) @@ -32,23 +43,28 @@ func policy_assignKasGrant(cmd *cobra.Command, args []string) { cli.ExitWithError("Failed to get registered KAS", err) } - if attrID != "" { - res, err = h.UpdateKasGrantForAttribute(attrID, kasID) + ctx := cmd.Context() + if nsID != "" { + res, err = h.AssignKasGrantToNamespace(ctx, nsID, kasID) + if err != nil { + cli.ExitWithError("Failed to assign KAS Grant for Namespace", err) + } + rowID = []string{"Namespace ID", nsID} + } else if attrID != "" { + res, err = h.AssignKasGrantToAttribute(ctx, attrID, kasID) if err != nil { cli.ExitWithError("Failed to assign KAS Grant for Attribute Definition", err) } - id = attrID - header = "Attribute ID" + rowID = []string{"Attribute ID", attrID} } else { - res, err = h.UpdateKasGrantForValue(valID, kasID) + res, err = h.AssignKasGrantToValue(ctx, valID, kasID) if err != nil { cli.ExitWithError("Failed to assign KAS Grant for Attribute Value", err) } - id = attrID - header = "Value ID" + rowID = []string{"Value ID", valID} } - t := cli.NewTabular([]string{header, id}, []string{"KAS ID", kasID}, []string{"Granted KAS URI", kas.GetUri()}) + t := cli.NewTabular(rowID, []string{"KAS ID", kasID}, []string{"Granted KAS URI", kas.GetUri()}) HandleSuccess(cmd, id, t, res) } @@ -57,12 +73,20 @@ func policy_unassignKasGrant(cmd *cobra.Command, args []string) { defer h.Close() flagHelper := cli.NewFlagHelper(cmd) + nsID := flagHelper.GetOptionalString("namespace-id") attrID := flagHelper.GetOptionalString("attribute-id") valID := flagHelper.GetOptionalString("value-id") kasID := flagHelper.GetRequiredString("kas-id") + force := flagHelper.GetOptionalBool("force") - if attrID == "" && valID == "" { - cli.ExitWithError("Must specify an Attribute Definition ID or Value ID to unassign.", nil) + count := 0 + for _, v := range []string{nsID, attrID, valID} { + if v != "" { + count++ + } + } + if count != 1 { + cli.ExitWithError("Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to unassign", errors.New("invalid flag values")) } var ( res interface{} @@ -78,14 +102,29 @@ func policy_unassignKasGrant(cmd *cobra.Command, args []string) { } kasURI := kas.GetUri() - if attrID != "" { + ctx := cmd.Context() + if nsID != "" { + ns, err := h.GetNamespace(nsID) + if err != nil || ns == nil { + cli.ExitWithError("Failed to get namespace definition", err) + } + confirm = fmt.Sprintf("the grant to namespace FQN (%s) of KAS URI", ns.GetFqn()) + cli.ConfirmAction(cli.ActionDelete, confirm, kasURI, force) + res, err = h.DeleteKasGrantFromNamespace(ctx, nsID, kasID) + if err != nil { + cli.ExitWithError("Failed to update KAS grant for namespace", err) + } + + rowID = []string{"Namespace ID", nsID} + rowFQN = []string{"Namespace FQN", ns.GetFqn()} + } else if attrID != "" { attr, err := h.GetAttribute(attrID) if err != nil || attr == nil { cli.ExitWithError("Failed to get attribute definition", err) } confirm = fmt.Sprintf("the grant to attribute FQN (%s) of KAS URI", attr.GetFqn()) - cli.ConfirmAction(cli.ActionDelete, confirm, kasURI) - res, err = h.DeleteKasGrantFromAttribute(attrID, kasID) + cli.ConfirmAction(cli.ActionDelete, confirm, kasURI, force) + res, err = h.DeleteKasGrantFromAttribute(ctx, attrID, kasID) if err != nil { cli.ExitWithError("Failed to update KAS grant for attribute", err) } @@ -98,8 +137,8 @@ func policy_unassignKasGrant(cmd *cobra.Command, args []string) { cli.ExitWithError("Failed to get attribute value", err) } confirm = fmt.Sprintf("the grant to attribute value FQN (%s) of KAS URI", val.GetFqn()) - cli.ConfirmAction(cli.ActionDelete, confirm, kasURI) - _, err = h.DeleteKasGrantFromValue(valID, kasID) + cli.ConfirmAction(cli.ActionDelete, confirm, kasURI, force) + _, err = h.DeleteKasGrantFromValue(ctx, valID, kasID) if err != nil { cli.ExitWithError("Failed to update KAS grant for attribute value", err) } @@ -118,6 +157,12 @@ func init() { assignCmd := man.Docs.GetCommand("policy/kas-grants/assign", man.WithRun(policy_assignKasGrant), ) + assignCmd.Flags().StringP( + assignCmd.GetDocFlag("namespace-id").Name, + assignCmd.GetDocFlag("namespace-id").Shorthand, + assignCmd.GetDocFlag("namespace-id").Default, + assignCmd.GetDocFlag("namespace-id").Description, + ) assignCmd.Flags().StringP( assignCmd.GetDocFlag("attribute-id").Name, assignCmd.GetDocFlag("attribute-id").Shorthand, @@ -141,6 +186,12 @@ func init() { unassignCmd := man.Docs.GetCommand("policy/kas-grants/unassign", man.WithRun(policy_unassignKasGrant), ) + unassignCmd.Flags().StringP( + unassignCmd.GetDocFlag("namespace-id").Name, + unassignCmd.GetDocFlag("namespace-id").Shorthand, + unassignCmd.GetDocFlag("namespace-id").Default, + unassignCmd.GetDocFlag("namespace-id").Description, + ) unassignCmd.Flags().StringP( unassignCmd.GetDocFlag("attribute-id").Name, unassignCmd.GetDocFlag("attribute-id").Shorthand, @@ -159,6 +210,12 @@ func init() { unassignCmd.GetDocFlag("kas-id").Default, unassignCmd.GetDocFlag("kas-id").Description, ) + unassignCmd.Flags().BoolVar( + &forceFlagValue, + unassignCmd.GetDocFlag("force").Name, + false, + unassignCmd.GetDocFlag("force").Description, + ) cmd := man.Docs.GetCommand("policy/kas-grants", man.WithSubcommands(assignCmd, unassignCmd), diff --git a/cmd/kas-registry.go b/cmd/kas-registry.go index 6a0377c4..b6ecf85b 100644 --- a/cmd/kas-registry.go +++ b/cmd/kas-registry.go @@ -183,7 +183,7 @@ func policy_deleteKeyAccessRegistry(cmd *cobra.Command, args []string) { cli.ExitWithError(errMsg, err) } - cli.ConfirmAction(cli.ActionDelete, "KAS Registry Entry: ", id) + cli.ConfirmAction(cli.ActionDelete, "KAS Registry Entry: ", id, false) if _, err := h.DeleteKasRegistryEntry(id); err != nil { errMsg := fmt.Sprintf("Failed to delete KAS registry entry (%s)", id) diff --git a/cmd/policy-attributeNamespaces.go b/cmd/policy-attributeNamespaces.go index 239c7d2c..0e44a2db 100644 --- a/cmd/policy-attributeNamespaces.go +++ b/cmd/policy-attributeNamespaces.go @@ -113,7 +113,7 @@ func policy_deactivateAttributeNamespace(cmd *cobra.Command, args []string) { cli.ExitWithError(errMsg, err) } - cli.ConfirmAction(cli.ActionDeactivate, "namespace", ns.Name) + cli.ConfirmAction(cli.ActionDeactivate, "namespace", ns.Name, false) d, err := h.DeactivateNamespace(id) if err != nil { diff --git a/cmd/policy-attributeValues.go b/cmd/policy-attributeValues.go index 12dfb149..a6373e4f 100644 --- a/cmd/policy-attributeValues.go +++ b/cmd/policy-attributeValues.go @@ -118,7 +118,7 @@ func policy_deactivateAttributeValue(cmd *cobra.Command, args []string) { cli.ExitWithError(fmt.Sprintf("Failed to get attribute value (%s)", id), err) } - cli.ConfirmAction(cli.ActionDeactivate, "attribute value", value.Value) + cli.ConfirmAction(cli.ActionDeactivate, "attribute value", value.Value, false) deactivated, err := h.DeactivateAttributeValue(id) if err != nil { diff --git a/cmd/policy-attributes.go b/cmd/policy-attributes.go index 4a3684db..8e161b86 100644 --- a/cmd/policy-attributes.go +++ b/cmd/policy-attributes.go @@ -140,7 +140,7 @@ func policy_deactivateAttribute(cmd *cobra.Command, args []string) { cli.ExitWithError(errMsg, err) } - cli.ConfirmAction(cli.ActionDeactivate, "attribute", attr.Name) + cli.ConfirmAction(cli.ActionDeactivate, "attribute", attr.Name, false) attr, err = h.DeactivateAttribute(id) if err != nil { diff --git a/cmd/policy-resourceMappings.go b/cmd/policy-resourceMappings.go index ffbb0db8..912dfe23 100644 --- a/cmd/policy-resourceMappings.go +++ b/cmd/policy-resourceMappings.go @@ -139,7 +139,7 @@ func policy_deleteResourceMapping(cmd *cobra.Command, args []string) { flagHelper := cli.NewFlagHelper(cmd) id := flagHelper.GetRequiredString("id") - cli.ConfirmAction(cli.ActionDelete, "resource-mapping", id) + cli.ConfirmAction(cli.ActionDelete, "resource-mapping", id, false) resourceMapping, err := h.DeleteResourceMapping(id) if err != nil { diff --git a/cmd/policy-subjectConditionSets.go b/cmd/policy-subjectConditionSets.go index 80bb49c9..c25125a0 100644 --- a/cmd/policy-subjectConditionSets.go +++ b/cmd/policy-subjectConditionSets.go @@ -253,7 +253,7 @@ func policy_deleteSubjectConditionSet(cmd *cobra.Command, args []string) { cli.ExitWithError(fmt.Sprintf("Subject Condition Set with id %s not found", id), err) } - cli.ConfirmAction(cli.ActionDelete, "Subject Condition Set", id) + cli.ConfirmAction(cli.ActionDelete, "Subject Condition Set", id, false) if err := h.DeleteSubjectConditionSet(id); err != nil { cli.ExitWithError(fmt.Sprintf("Subject Condition Set with id %s not found", id), err) diff --git a/cmd/policy-subject_mappings.go b/cmd/policy-subject_mappings.go index f720ca1c..5c51ecdd 100644 --- a/cmd/policy-subject_mappings.go +++ b/cmd/policy-subject_mappings.go @@ -192,7 +192,7 @@ func policy_deleteSubjectMapping(cmd *cobra.Command, args []string) { cli.ExitWithError(errMsg, err) } - cli.ConfirmAction(cli.ActionDelete, "subject mapping", sm.Id) + cli.ConfirmAction(cli.ActionDelete, "subject mapping", sm.Id, false) deleted, err := h.DeleteSubjectMapping(id) if err != nil { diff --git a/docs/man/policy/kas-grants/assign.md b/docs/man/policy/kas-grants/assign.md index d13c6111..318ad36d 100644 --- a/docs/man/policy/kas-grants/assign.md +++ b/docs/man/policy/kas-grants/assign.md @@ -12,13 +12,16 @@ command: - upsert description: Assign a grant of a KAS to an Attribute Definition or Value flags: + - name: namespace-id + shorthand: n + description: The ID of the Namespace being assigned a KAS Grant - name: attribute-id shorthand: a - description: The ID of the attribute definition being assigned a KAS Grant + description: The ID of the Attribute Definition being assigned a KAS Grant required: true - name: value-id shorthand: v - description: The ID of the attribute value being assigned a KAS Grant + description: The ID of the Value being assigned a KAS Grant required: true - name: kas-id shorthand: k @@ -33,6 +36,6 @@ command: default: false --- -Assign a registered Key Access Server (KAS) to an attribute definition or value. +Assign a registered Key Access Server (KAS) to an attribute namespace, definition, or value. For more information, see `kas-registry` and `kas-grants` manuals. \ No newline at end of file diff --git a/docs/man/policy/kas-grants/unassign.md b/docs/man/policy/kas-grants/unassign.md index 21d42dd4..3af55453 100644 --- a/docs/man/policy/kas-grants/unassign.md +++ b/docs/man/policy/kas-grants/unassign.md @@ -8,6 +8,9 @@ command: - remove description: Remove a grant assignment of a KAS to an Attribute Definition or Value flags: + - name: namespace-id + shorthand: n + description: The ID of the Namespace being unassigned a KAS Grant - name: attribute-id shorthand: a description: The ID of the Attribute Definition being unassigned the KAS grant @@ -20,6 +23,8 @@ command: shorthand: k description: The Key Access Server (KAS) ID being unassigned a grant required: true + - name: force + description: Force the unassignment with no confirmation --- Unassign a registered Key Access Server (KAS) to an attribute definition or value. diff --git a/docs/man/policy/kas-registry/_index.md b/docs/man/policy/kas-registry/_index.md index 3482fd6f..03b23ef0 100644 --- a/docs/man/policy/kas-registry/_index.md +++ b/docs/man/policy/kas-registry/_index.md @@ -10,7 +10,7 @@ command: The Key Access Server (KAS) registry is a record of KASs safeguarding access and maintaining public keys. The registry contains critical information like each server's uri, its public key (which can be either local or at a remote uri), and any metadata about the server. Key Access Servers grant keys -for specified Attributes and their Values via Attribute Key Access Grants and Attribute Value Key +for specified Namespaces, Attributes, and their Values via Attribute Key Access Grants and Attribute Value Key Access Grants. For more information about grants and how KASs are utilized once registered, see the manual for the diff --git a/go.sum b/go.sum index 7302b60d..0c9be642 100644 --- a/go.sum +++ b/go.sum @@ -222,8 +222,6 @@ github.com/opentdf/platform/lib/ocrypto v0.1.5 h1:Gv5dAmZEVQeD9w1Fg9fix8gdZIsPDH github.com/opentdf/platform/lib/ocrypto v0.1.5/go.mod h1:ne+l8Q922OdzA0xesK3XJmfECBnn5vLSGYU3/3OhiHM= github.com/opentdf/platform/protocol/go v0.2.14 h1:0wqKDVTpuPICyH37ecKxR2+tZNsgXV8TfdzlbQ3ovrA= github.com/opentdf/platform/protocol/go v0.2.14/go.mod h1:WqDcnFQJb0v8ivRQPidbehcL8ils5ZSZYXkuv0nyvsI= -github.com/opentdf/platform/sdk v0.3.9 h1:sNXGjt5kWnmMCx43GcBc5+sE1YqPNyqxrMSHF3/SRk8= -github.com/opentdf/platform/sdk v0.3.9/go.mod h1:XqFivuo4tcqxGwJF9ORnLB3S5bjrgJwiaj6BAJUXJXg= github.com/opentdf/platform/sdk v0.3.10 h1:WoPtM6IcwwDIEqCcLq2jb6pd15bFXmEDaju9MKd6JtM= github.com/opentdf/platform/sdk v0.3.10/go.mod h1:XqFivuo4tcqxGwJF9ORnLB3S5bjrgJwiaj6BAJUXJXg= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= diff --git a/pkg/cli/confirm.go b/pkg/cli/confirm.go index da325864..05a64fb1 100644 --- a/pkg/cli/confirm.go +++ b/pkg/cli/confirm.go @@ -23,7 +23,10 @@ const ( InputNameFQNUpdated = "deprecated fully qualified name (FQN) being altered" ) -func ConfirmAction(action, resource, id string) { +func ConfirmAction(action, resource, id string, force bool) { + if force { + return + } var confirm bool err := huh.NewConfirm(). Title(fmt.Sprintf("Are you sure you want to %s %s:\n\n\t%s", action, resource, id)). diff --git a/pkg/handlers/kas-grants.go b/pkg/handlers/kas-grants.go index a2e5e329..48360d48 100644 --- a/pkg/handlers/kas-grants.go +++ b/pkg/handlers/kas-grants.go @@ -1,15 +1,18 @@ package handlers import ( + "context" + "github.com/opentdf/platform/protocol/go/policy/attributes" + "github.com/opentdf/platform/protocol/go/policy/namespaces" ) -func (h Handler) UpdateKasGrantForAttribute(attr_id string, kas_id string) (*attributes.AttributeKeyAccessServer, error) { +func (h Handler) AssignKasGrantToAttribute(ctx context.Context, attr_id string, kas_id string) (*attributes.AttributeKeyAccessServer, error) { kas := &attributes.AttributeKeyAccessServer{ AttributeId: attr_id, KeyAccessServerId: kas_id, } - resp, err := h.sdk.Attributes.AssignKeyAccessServerToAttribute(h.ctx, &attributes.AssignKeyAccessServerToAttributeRequest{ + resp, err := h.sdk.Attributes.AssignKeyAccessServerToAttribute(ctx, &attributes.AssignKeyAccessServerToAttributeRequest{ AttributeKeyAccessServer: kas, }) if err != nil { @@ -19,12 +22,12 @@ func (h Handler) UpdateKasGrantForAttribute(attr_id string, kas_id string) (*att return resp.GetAttributeKeyAccessServer(), nil } -func (h Handler) DeleteKasGrantFromAttribute(attr_id string, kas_id string) (*attributes.AttributeKeyAccessServer, error) { +func (h Handler) DeleteKasGrantFromAttribute(ctx context.Context, attr_id string, kas_id string) (*attributes.AttributeKeyAccessServer, error) { kas := &attributes.AttributeKeyAccessServer{ AttributeId: attr_id, KeyAccessServerId: kas_id, } - resp, err := h.sdk.Attributes.RemoveKeyAccessServerFromAttribute(h.ctx, &attributes.RemoveKeyAccessServerFromAttributeRequest{ + resp, err := h.sdk.Attributes.RemoveKeyAccessServerFromAttribute(ctx, &attributes.RemoveKeyAccessServerFromAttributeRequest{ AttributeKeyAccessServer: kas, }) if err != nil { @@ -34,12 +37,12 @@ func (h Handler) DeleteKasGrantFromAttribute(attr_id string, kas_id string) (*at return resp.GetAttributeKeyAccessServer(), nil } -func (h Handler) UpdateKasGrantForValue(val_id string, kas_id string) (*attributes.ValueKeyAccessServer, error) { +func (h Handler) AssignKasGrantToValue(ctx context.Context, val_id string, kas_id string) (*attributes.ValueKeyAccessServer, error) { kas := &attributes.ValueKeyAccessServer{ ValueId: val_id, KeyAccessServerId: kas_id, } - resp, err := h.sdk.Attributes.AssignKeyAccessServerToValue(h.ctx, &attributes.AssignKeyAccessServerToValueRequest{ + resp, err := h.sdk.Attributes.AssignKeyAccessServerToValue(ctx, &attributes.AssignKeyAccessServerToValueRequest{ ValueKeyAccessServer: kas, }) if err != nil { @@ -49,12 +52,12 @@ func (h Handler) UpdateKasGrantForValue(val_id string, kas_id string) (*attribut return resp.GetValueKeyAccessServer(), nil } -func (h Handler) DeleteKasGrantFromValue(val_id string, kas_id string) (*attributes.ValueKeyAccessServer, error) { +func (h Handler) DeleteKasGrantFromValue(ctx context.Context, val_id string, kas_id string) (*attributes.ValueKeyAccessServer, error) { kas := &attributes.ValueKeyAccessServer{ ValueId: val_id, KeyAccessServerId: kas_id, } - resp, err := h.sdk.Attributes.RemoveKeyAccessServerFromValue(h.ctx, &attributes.RemoveKeyAccessServerFromValueRequest{ + resp, err := h.sdk.Attributes.RemoveKeyAccessServerFromValue(ctx, &attributes.RemoveKeyAccessServerFromValueRequest{ ValueKeyAccessServer: kas, }) if err != nil { @@ -63,3 +66,33 @@ func (h Handler) DeleteKasGrantFromValue(val_id string, kas_id string) (*attribu return resp.GetValueKeyAccessServer(), nil } + +func (h Handler) AssignKasGrantToNamespace(ctx context.Context, ns_id string, kas_id string) (*namespaces.NamespaceKeyAccessServer, error) { + kas := &namespaces.NamespaceKeyAccessServer{ + NamespaceId: ns_id, + KeyAccessServerId: kas_id, + } + resp, err := h.sdk.Namespaces.AssignKeyAccessServerToNamespace(ctx, &namespaces.AssignKeyAccessServerToNamespaceRequest{ + NamespaceKeyAccessServer: kas, + }) + if err != nil { + return nil, err + } + + return resp.GetNamespaceKeyAccessServer(), nil +} + +func (h Handler) DeleteKasGrantFromNamespace(ctx context.Context, ns_id string, kas_id string) (*namespaces.NamespaceKeyAccessServer, error) { + kas := &namespaces.NamespaceKeyAccessServer{ + NamespaceId: ns_id, + KeyAccessServerId: kas_id, + } + resp, err := h.sdk.Namespaces.RemoveKeyAccessServerFromNamespace(ctx, &namespaces.RemoveKeyAccessServerFromNamespaceRequest{ + NamespaceKeyAccessServer: kas, + }) + if err != nil { + return nil, err + } + + return resp.GetNamespaceKeyAccessServer(), nil +} diff --git a/tests/kas-grants.bats b/tests/kas-grants.bats new file mode 100755 index 00000000..2c022605 --- /dev/null +++ b/tests/kas-grants.bats @@ -0,0 +1,129 @@ +#!/usr/bin/env bats + +# Tests for KAS grants + +setup() { + echo -n '{"clientId":"opentdf","clientSecret":"secret"}' > creds.json + export WITH_CREDS='--with-client-creds-file ./creds.json' + export HOST='--host http://localhost:8080' + + if [[ "$BATS_TEST_NUMBER" -eq 1 ]]; then + export KAS_ID=$(./otdfctl $HOST $WITH_CREDS policy kas-registry create --uri 'https://e2etestkas.com' --public-key-remote 'https://e2etestkas.com/pub_key' --json | jq -r '.id') + else + export KAS_ID=$(./otdfctl $HOST $WITH_CREDS policy kas-registry list --json | jq -r '.[-1].id') + fi + + export KAS_ID_FLAG="--kas-id $KAS_ID" +} + +@test "namespace: assign grant then unassign it" { + export NS_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes namespaces list --json | jq -r '.[0].id') + export NS_ID_FLAG="--namespace-id $NS_ID" + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $NS_ID_FLAG $KAS_ID_FLAG)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Namespace ID"* ]] + [[ "$result" == *$NS_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] + + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $NS_ID_FLAG $KAS_ID_FLAG --force)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Namespace ID"* ]] + [[ "$result" == *$NS_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] +} + +@test "attribute: assign grant then unassign it" { + export ATTR_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes list --json | jq -r '.[0].id') + export ATTR_ID_FLAG="--attribute-id $ATTR_ID" + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $ATTR_ID_FLAG $KAS_ID_FLAG)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Attribute ID"* ]] + [[ "$result" == *$ATTR_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] + + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $ATTR_ID_FLAG $KAS_ID_FLAG --force)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Attribute ID"* ]] + [[ "$result" == *$ATTR_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] +} + +@test "value: assign grant then unassign it" { + export VAL_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes list --json | jq -r '.[0].values[0].id') + export VAL_ID_FLAG="--value-id $VAL_ID" + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $VAL_ID_FLAG $KAS_ID_FLAG)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Value ID"* ]] + [[ "$result" == *$VAL_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] + + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $VAL_ID_FLAG $KAS_ID_FLAG --force)" + [[ "$result" == *"SUCCESS"* ]] + [[ "$result" == *"Value ID"* ]] + [[ "$result" == *$VAL_ID* ]] + [[ "$result" == *"KAS ID"* ]] + [[ "$result" == *$KAS_ID* ]] +} + +@test "assign rejects more than one type of grant at once" { + export NS_ID_FLAG='--namespace-id hello' + export ATTR_ID_FLAG='--attribute-id world' + export VAL_ID_FLAG='--value-id goodnight' + + # simulates try/catch to avoid failed tests on expected errors + result='' + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $ATTR_ID_FLAG $VAL_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to assign"* ]] + + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $NS_ID_FLAG $VAL_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to assign"* ]] + + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants assign $ATTR_ID_FLAG $NS_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to assign"* ]] +} + +@test "unassign rejects more than one type of grant at once" { + export NS_ID_FLAG='--namespace-id hello' + export ATTR_ID_FLAG='--attribute-id world' + export VAL_ID_FLAG='--value-id goodnight' + + # simulates try/catch to avoid failed tests on expected errors + result='' + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $ATTR_ID_FLAG $VAL_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to unassign"* ]] + + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $NS_ID_FLAG $VAL_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to unassign"* ]] + + { + result="$(./otdfctl $HOST $WITH_CREDS policy kas-grants unassign $ATTR_ID_FLAG $NS_ID_FLAG $KAS_ID_FLAG)" + } || { + true + } + [[ "$result" == *"Must specify exactly one Attribute Namespace ID, Definition ID, or Value ID to unassign"* ]] +} \ No newline at end of file