From 35771f211035b32fd458331444d4f1a8fb654e89 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Mon, 28 Oct 2024 14:28:50 -0700 Subject: [PATCH 01/11] mark interactive mode experimental --- docs/man/interactive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/man/interactive.md b/docs/man/interactive.md index 9c6bc598..656738d4 100644 --- a/docs/man/interactive.md +++ b/docs/man/interactive.md @@ -1,5 +1,5 @@ --- -title: Interactive Mode +title: Interactive Mode (experimental) command: name: interactive From df0a9ec97e560133d92b970912f7f614f2e1abe2 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 29 Oct 2024 15:49:19 -0700 Subject: [PATCH 02/11] match subject mappings --- cmd/policy-subjectMappings.go | 86 +++++++++++++++++++++++ docs/man/policy/subject-mappings/match.md | 26 +++++++ go.mod | 1 + go.sum | 2 + pkg/handlers/selectors.go | 41 +++++++++++ pkg/handlers/subjectmappings.go | 13 ++++ 6 files changed, 169 insertions(+) create mode 100644 docs/man/policy/subject-mappings/match.md diff --git a/cmd/policy-subjectMappings.go b/cmd/policy-subjectMappings.go index 8bf068bd..2bc8b3e6 100644 --- a/cmd/policy-subjectMappings.go +++ b/cmd/policy-subjectMappings.go @@ -7,6 +7,7 @@ import ( "github.com/evertras/bubble-table/table" "github.com/opentdf/otdfctl/pkg/cli" + "github.com/opentdf/otdfctl/pkg/handlers" "github.com/opentdf/otdfctl/pkg/man" "github.com/opentdf/platform/protocol/go/policy" "github.com/opentdf/platform/protocol/go/policy/subjectmapping" @@ -253,6 +254,73 @@ func policy_updateSubjectMapping(cmd *cobra.Command, args []string) { HandleSuccess(cmd, id, t, updated) } +func policy_matchSubjectMappings(cmd *cobra.Command, args []string) { + c := cli.New(cmd, args) + h := NewHandler(c) + defer h.Close() + + subject := c.Flags.GetOptionalString("subject") + selectors = c.Flags.GetStringSlice("selector", selectors, cli.FlagsStringSliceOptions{Min: 0}) + + if len(selectors) > 0 && subject != "" { + cli.ExitWithError("Must provide either '--subject' or '--selector' flag values, not both", nil) + } + + if subject != "" { + flattened, err := handlers.FlattenSubjectContext(subject) + if err != nil { + cli.ExitWithError("Could not process '--subject' value", err) + } + for _, item := range flattened { + selectors = append(selectors, item.Key) + } + } + + matched, err := h.MatchSubjectMappings(selectors) + if err != nil { + cli.ExitWithError(fmt.Sprintf("Failed to match subject mappings with selectors %v", selectors), err) + } + + t := cli.NewTable( + cli.NewUUIDColumn(), + table.NewFlexColumn("subject_attrval_id", "Subject AttrVal: Id", cli.FlexColumnWidthFour), + table.NewFlexColumn("subject_attrval_value", "Subject AttrVal: Value", cli.FlexColumnWidthThree), + table.NewFlexColumn("actions", "Actions", cli.FlexColumnWidthTwo), + table.NewFlexColumn("subject_condition_set_id", "Subject Condition Set: Id", cli.FlexColumnWidthFour), + table.NewFlexColumn("subject_condition_set", "Subject Condition Set", cli.FlexColumnWidthThree), + table.NewFlexColumn("labels", "Labels", cli.FlexColumnWidthOne), + table.NewFlexColumn("created_at", "Created At", cli.FlexColumnWidthOne), + table.NewFlexColumn("updated_at", "Updated At", cli.FlexColumnWidthOne), + ) + rows := []table.Row{} + for _, sm := range matched { + var actionsJSON []byte + if actionsJSON, err = json.Marshal(sm.GetActions()); err != nil { + cli.ExitWithError("Error marshalling subject mapping actions", err) + } + + var subjectSetsJSON []byte + if subjectSetsJSON, err = json.Marshal(sm.GetSubjectConditionSet().GetSubjectSets()); err != nil { + cli.ExitWithError("Error marshalling subject condition set", err) + } + metadata := cli.ConstructMetadata(sm.GetMetadata()) + + rows = append(rows, table.NewRow(table.RowData{ + "id": sm.GetId(), + "subject_attrval_id": sm.GetAttributeValue().GetId(), + "subject_attrval_value": sm.GetAttributeValue().GetValue(), + "actions": string(actionsJSON), + "subject_condition_set_id": sm.GetSubjectConditionSet().GetId(), + "subject_condition_set": string(subjectSetsJSON), + "labels": metadata["Labels"], + "created_at": metadata["Created At"], + "updated_at": metadata["Updated At"], + })) + } + t = t.WithRows(rows) + HandleSuccess(cmd, "", t, matched) +} + func getSubjectMappingMappingActionEnumFromChoice(readable string) policy.Action_StandardAction { switch readable { case actionStandardDecrypt: @@ -378,6 +446,23 @@ func init() { deleteDoc.GetDocFlag("force").Description, ) + matchDoc := man.Docs.GetCommand("policy/subject-mappings/match", + man.WithRun(policy_matchSubjectMappings), + ) + matchDoc.Flags().StringP( + matchDoc.GetDocFlag("subject").Name, + matchDoc.GetDocFlag("subject").Shorthand, + matchDoc.GetDocFlag("subject").Default, + matchDoc.GetDocFlag("subject").Description, + ) + matchDoc.Flags().StringSliceVarP( + &selectors, + matchDoc.GetDocFlag("selector").Name, + matchDoc.GetDocFlag("selector").Shorthand, + []string{}, + matchDoc.GetDocFlag("selector").Description, + ) + doc := man.Docs.GetCommand("policy/subject-mappings", man.WithSubcommands( createDoc, @@ -385,6 +470,7 @@ func init() { listDoc, updateDoc, deleteDoc, + matchDoc, ), ) policy_subjectMappingCmd := &doc.Command diff --git a/docs/man/policy/subject-mappings/match.md b/docs/man/policy/subject-mappings/match.md new file mode 100644 index 00000000..86d16c8d --- /dev/null +++ b/docs/man/policy/subject-mappings/match.md @@ -0,0 +1,26 @@ +--- +title: Match a subject or set of selectors to relevant subject mappings +command: + name: match + flags: + - name: subject + shorthand: s + description: A Subject Entity Representation string (JSON or JWT, auto-detected) + default: '' + - name: selector + shorthand: x + description: "Individual selectors (i.e. '.department' or '.realm_access.roles[]') that may be found in SubjectConditionSets" +--- + +Given that Subject Mappings contain Subject Condition Sets (see either relevant command for more information), this tool can consume an Entity Representation +or a set of provided selectors to query the platform Policy for any relevant Subject Mappings. + +Given an Entity Representation of a Subject via `--subject` (an OIDC Access Token JWT, or a JSON object such as from an Entity Resolution Service response), +this command will parse all possible valid selectors and check those for presence in any Subject Condition Set referenced on a Subject Mapping to an Attribute Value. + +Given a set of selectors (`--selector`), this command will look for any Subject Mappings with Subject Condition Sets containing those same selectors. + +> [!NOTE] +> The values of the selectors and any IN/NOT_IN/IN_CONTAINS logic of Subject Condition Sets is irrelevant to this command. Evaluation of any matched conditions +> is handled by the Authorization Service to determine entitlements. This command is specifically for management of policy - to facilitate lookup of current +> conditions driven by known selectors as a precondition for administration of entitlement given the logical *operators* of the matched conditions and their relations. diff --git a/go.mod b/go.mod index e857b4a8..e38d56c4 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.6.0 github.com/itchyny/gojq v0.12.16 + github.com/opentdf/platform/lib/flattening v0.1.1 github.com/opentdf/platform/protocol/go v0.2.18 github.com/opentdf/platform/sdk v0.3.15 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index f0421114..108a00dd 100644 --- a/go.sum +++ b/go.sum @@ -218,6 +218,8 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentdf/platform/lib/fixtures v0.2.7 h1:2LxWmLBBISONVJnVDH8yMsV72VHQyirua0DwDBBoq+g= github.com/opentdf/platform/lib/fixtures v0.2.7/go.mod h1:8yCSe+oUzW9jbM573r9qgE68rjwDMNzktObiGVsO/W8= +github.com/opentdf/platform/lib/flattening v0.1.1 h1:la1f6PcRsc+yLH8+9UEr0ux6IRKu+6+oMaMVt05+8HU= +github.com/opentdf/platform/lib/flattening v0.1.1/go.mod h1:eyG7pe5UZlV+GI5/CymQD3xTAJxNhnP9M4QnBzaad1M= github.com/opentdf/platform/lib/ocrypto v0.1.6 h1:rd4ctCZOE/c3qDJORtkSK9tw6dEXb+jbJXRRk4LcxII= github.com/opentdf/platform/lib/ocrypto v0.1.6/go.mod h1:ne+l8Q922OdzA0xesK3XJmfECBnn5vLSGYU3/3OhiHM= github.com/opentdf/platform/protocol/go v0.2.18 h1:s+TVZkOPGCzy7WyObtJWJNaFeOGDUTuSmAsq3omvugY= diff --git a/pkg/handlers/selectors.go b/pkg/handlers/selectors.go index 26a5d42e..4bd3f6df 100644 --- a/pkg/handlers/selectors.go +++ b/pkg/handlers/selectors.go @@ -1,12 +1,15 @@ package handlers import ( + "encoding/json" + "errors" "fmt" "log" "reflect" "github.com/golang-jwt/jwt" "github.com/itchyny/gojq" + flat "github.com/opentdf/platform/lib/flattening" "github.com/opentdf/platform/protocol/go/policy" ) @@ -150,3 +153,41 @@ func TestSubjectContext(subject interface{}, selectors []string) ([]*policy.Subj } return found, nil } + +func ParseSubjectString(subject string) (map[string]interface{}, error) { + var value map[string]interface{} + //nolint:errcheck // if fails to unmarshal, may be a JWT, so swallow the error + json.Unmarshal([]byte(subject), &value) + + if value == nil { + token, _, err := new(jwt.Parser).ParseUnverified(subject, jwt.MapClaims{}) + if err != nil { + return nil, fmt.Errorf("failed to flatten subject [%v]: %w", subject, err) + } + + if claims, ok := token.Claims.(jwt.MapClaims); ok { + value = claims + } else { + return nil, errors.New("failed to get claims from subject JWT token") + } + } + + if value == nil { + return nil, errors.New("invalid subject context type. Must be of type: [json, jwt]") + } + return value, nil +} + +func FlattenSubjectContext(subject string) ([]flat.Item, error) { + value, err := ParseSubjectString(subject) + if err != nil { + return nil, fmt.Errorf("failed to parse subject string into JSON or JWT [%s]: %w", subject, err) + } + + flattened, err := flat.Flatten(value) + if err != nil { + return nil, fmt.Errorf("failed to flatten subject [%v]: %w", subject, err) + } + + return flattened.Items, nil +} diff --git a/pkg/handlers/subjectmappings.go b/pkg/handlers/subjectmappings.go index c5106a0f..82b98098 100644 --- a/pkg/handlers/subjectmappings.go +++ b/pkg/handlers/subjectmappings.go @@ -65,6 +65,19 @@ func (h Handler) DeleteSubjectMapping(id string) (*policy.SubjectMapping, error) return resp.GetSubjectMapping(), err } +func (h Handler) MatchSubjectMappings(selectors []string) ([]*policy.SubjectMapping, error) { + subjectProperties := make([]*policy.SubjectProperty, len(selectors)) + for i, selector := range selectors { + subjectProperties[i] = &policy.SubjectProperty{ + ExternalSelectorValue: selector, + } + } + resp, err := h.sdk.SubjectMapping.MatchSubjectMappings(h.ctx, &subjectmapping.MatchSubjectMappingsRequest{ + SubjectProperties: subjectProperties, + }) + return resp.GetSubjectMappings(), err +} + func GetSubjectMappingOperatorFromChoice(readable string) policy.SubjectMappingOperatorEnum { switch readable { case SubjectMappingOperatorIn: From db2758d2c2acaef3c212bc31b716d0c69b5353f6 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 29 Oct 2024 16:17:42 -0700 Subject: [PATCH 03/11] spellcheck --- .github/spellcheck.ignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/spellcheck.ignore b/.github/spellcheck.ignore index d1dab22c..d5ba52ee 100644 --- a/.github/spellcheck.ignore +++ b/.github/spellcheck.ignore @@ -35,6 +35,7 @@ SCS SCSs SDK ShinyThing +SubjectConditionSets TDF TDF'd TDFd From 79804127831591493f461f0b88c78631ade075c5 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Wed, 30 Oct 2024 07:42:34 -0700 Subject: [PATCH 04/11] fix manual --- docs/man/policy/subject-mappings/match.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/man/policy/subject-mappings/match.md b/docs/man/policy/subject-mappings/match.md index 86d16c8d..43d2091b 100644 --- a/docs/man/policy/subject-mappings/match.md +++ b/docs/man/policy/subject-mappings/match.md @@ -21,6 +21,7 @@ this command will parse all possible valid selectors and check those for presenc Given a set of selectors (`--selector`), this command will look for any Subject Mappings with Subject Condition Sets containing those same selectors. > [!NOTE] -> The values of the selectors and any IN/NOT_IN/IN_CONTAINS logic of Subject Condition Sets is irrelevant to this command. Evaluation of any matched conditions -> is handled by the Authorization Service to determine entitlements. This command is specifically for management of policy - to facilitate lookup of current -> conditions driven by known selectors as a precondition for administration of entitlement given the logical *operators* of the matched conditions and their relations. +> The values of the selectors and any `IN`/`NOT_IN`/`IN_CONTAINS` logic of Subject Condition Sets is irrelevant to this command. +> Evaluation of any matched conditions is handled by the Authorization Service to determine entitlements. This command +> is specifically for management of policy - to facilitate lookup of current conditions driven by known selectors as a +> precondition for administration of entitlement given the logical *operators* of the matched conditions and their relations. From 272b43c8ce5effa3f510e6ede0750bea1d565c23 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 12 Nov 2024 07:54:05 -0800 Subject: [PATCH 05/11] dependency merge conflict --- go.mod | 2 ++ go.sum | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/go.mod b/go.mod index c155a341..b56593de 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gowebpki/jcs v1.0.1 // indirect @@ -80,6 +81,7 @@ require ( github.com/muesli/termenv v0.15.2 // indirect github.com/muhlemmer/gu v0.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/opentdf/platform/lib/flattening v0.1.1 // indirect github.com/opentdf/platform/lib/ocrypto v0.1.6 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go.sum b/go.sum index d6f5fa8a..19b61b1a 100644 --- a/go.sum +++ b/go.sum @@ -118,6 +118,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -215,6 +217,8 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentdf/platform/lib/fixtures v0.2.7 h1:2LxWmLBBISONVJnVDH8yMsV72VHQyirua0DwDBBoq+g= github.com/opentdf/platform/lib/fixtures v0.2.7/go.mod h1:8yCSe+oUzW9jbM573r9qgE68rjwDMNzktObiGVsO/W8= +github.com/opentdf/platform/lib/flattening v0.1.1 h1:la1f6PcRsc+yLH8+9UEr0ux6IRKu+6+oMaMVt05+8HU= +github.com/opentdf/platform/lib/flattening v0.1.1/go.mod h1:eyG7pe5UZlV+GI5/CymQD3xTAJxNhnP9M4QnBzaad1M= github.com/opentdf/platform/lib/ocrypto v0.1.6 h1:rd4ctCZOE/c3qDJORtkSK9tw6dEXb+jbJXRRk4LcxII= github.com/opentdf/platform/lib/ocrypto v0.1.6/go.mod h1:ne+l8Q922OdzA0xesK3XJmfECBnn5vLSGYU3/3OhiHM= github.com/opentdf/platform/protocol/go v0.2.20 h1:FPU1ZcXvPm/QeE2nqgbD/HMTOCICQSD0DoncQbAZ1ws= From b004fc42711b0576a704701bc13081fb49e8376c Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 12 Nov 2024 07:56:21 -0800 Subject: [PATCH 06/11] fix table - metadata not returned from this API --- cmd/policy-subjectMappings.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/policy-subjectMappings.go b/cmd/policy-subjectMappings.go index 2bc8b3e6..a5f6d76a 100644 --- a/cmd/policy-subjectMappings.go +++ b/cmd/policy-subjectMappings.go @@ -288,9 +288,6 @@ func policy_matchSubjectMappings(cmd *cobra.Command, args []string) { table.NewFlexColumn("actions", "Actions", cli.FlexColumnWidthTwo), table.NewFlexColumn("subject_condition_set_id", "Subject Condition Set: Id", cli.FlexColumnWidthFour), table.NewFlexColumn("subject_condition_set", "Subject Condition Set", cli.FlexColumnWidthThree), - table.NewFlexColumn("labels", "Labels", cli.FlexColumnWidthOne), - table.NewFlexColumn("created_at", "Created At", cli.FlexColumnWidthOne), - table.NewFlexColumn("updated_at", "Updated At", cli.FlexColumnWidthOne), ) rows := []table.Row{} for _, sm := range matched { From 82f331e0909b438fcf1002ddd22ae8f75d69b5e4 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 12 Nov 2024 08:23:31 -0800 Subject: [PATCH 07/11] fix existing CLI doc example --- docs/man/auth/client-credentials.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/man/auth/client-credentials.md b/docs/man/auth/client-credentials.md index 97f97e20..a452cee6 100644 --- a/docs/man/auth/client-credentials.md +++ b/docs/man/auth/client-credentials.md @@ -26,11 +26,11 @@ in the OS keyring for future use. Authenticate with client credentials (secret provided interactively) ```shell -opentdf auth client-credentials --client-id +otdfctl auth client-credentials --client-id ``` Authenticate with client credentials (secret provided as argument) ```shell -opentdf auth client-credentials --client-id --client-secret +otdfctl auth client-credentials --client-id --client-secret ``` From dfe928ea369b4e0b3483de16ce6c34b6e9b453da Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 12 Nov 2024 08:35:04 -0800 Subject: [PATCH 08/11] add docs --- docs/man/policy/subject-mappings/match.md | 26 +++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/man/policy/subject-mappings/match.md b/docs/man/policy/subject-mappings/match.md index 43d2091b..4791b19a 100644 --- a/docs/man/policy/subject-mappings/match.md +++ b/docs/man/policy/subject-mappings/match.md @@ -12,16 +12,30 @@ command: description: "Individual selectors (i.e. '.department' or '.realm_access.roles[]') that may be found in SubjectConditionSets" --- -Given that Subject Mappings contain Subject Condition Sets (see either relevant command for more information), this tool can consume an Entity Representation -or a set of provided selectors to query the platform Policy for any relevant Subject Mappings. +This tool queries platform policies for relevant Subject Mappings using either an Entity Representation or specific selectors. -Given an Entity Representation of a Subject via `--subject` (an OIDC Access Token JWT, or a JSON object such as from an Entity Resolution Service response), -this command will parse all possible valid selectors and check those for presence in any Subject Condition Set referenced on a Subject Mapping to an Attribute Value. +If an Entity Representation is provided via `--subject` (such as an OIDC JWT or JSON response from an Entity Resolution Service), the tool +parses all valid selectors and checks for matching Subject Condition Sets in Subject Mappings to Attribute Values. -Given a set of selectors (`--selector`), this command will look for any Subject Mappings with Subject Condition Sets containing those same selectors. +If selectors are provided directly with `--selector`, the tool searches for Subject Mappings with Subject Condition Sets that contain those selectors. + +## Examples + +Various ways to invoke the `match` command to query Subject Mappings to Attribute Values with relevant Subject Condition Sets. + +```shell +# matches either org name or department selectors +otdfctl policy subject-mappings match --selector '.org.name' --selector '.department' + +# parses subject entity representation as JSON and matches any selector (with this subject only '.emailAddress') +otdfctl policy subject-mappings match --subject '{"emailAddress":"user@email.com"}' + +# parses entity representation as JWT into all possicle claim selectors and matches any of them +otdfctl policy subject-mappings match --subject 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' +``` > [!NOTE] > The values of the selectors and any `IN`/`NOT_IN`/`IN_CONTAINS` logic of Subject Condition Sets is irrelevant to this command. > Evaluation of any matched conditions is handled by the Authorization Service to determine entitlements. This command > is specifically for management of policy - to facilitate lookup of current conditions driven by known selectors as a -> precondition for administration of entitlement given the logical *operators* of the matched conditions and their relations. +> precondition for administration of entitlement given the logical _operators_ of the matched conditions and their relations. From b32bf560b72bfeb63b6178d77afe87114b5c4152 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 12 Nov 2024 15:04:19 -0800 Subject: [PATCH 09/11] bats test --- e2e/subject-mapping.bats | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/e2e/subject-mapping.bats b/e2e/subject-mapping.bats index 134aa35c..d132e69e 100755 --- a/e2e/subject-mapping.bats +++ b/e2e/subject-mapping.bats @@ -44,7 +44,7 @@ teardown_file() { assert_output --partial '"Standard":1' assert_output --partial '"Standard":2' assert_output --partial ".team.name" -assert_output --regexp "Attribute Value Id.*$VAL1_ID" + assert_output --regexp "Attribute Value Id.*$VAL1_ID" # scs is required run_otdfctl_sm create --attribute-value-id "$VAL2_ID" -s TRANSMIT @@ -57,6 +57,38 @@ assert_output --regexp "Attribute Value Id.*$VAL1_ID" assert_output --partial "At least one Standard or Custom Action [--action-standard, --action-custom] is required" } +@test "Match subject mapping" { + # create with simultaneous new SCS + NEW_SCS='[{"condition_groups":[{"conditions":[{"operator":1,"subject_external_values":["sales"],"subject_external_selector_value":".department"}],"boolean_operator":2}]}]' + NEW_SM_ID=$(./otdfctl $HOST $WITH_CREDS policy subject-mappings create -a "$VAL2_ID" --action-standard DECRYPT --subject-condition-set-new "$NEW_SCS" --json | jq -r '.id') + + run ./otdfctl $HOST $WITH_CREDS policy sm match -x '.department' + assert_success + assert_output --partial "$NEW_SM_ID" + + run ./otdfctl $HOST $WITH_CREDS policy sm match --subject '{"department":"any_department"}' + assert_success + assert_output --partial "$NEW_SM_ID" + + # JWT includes 'department' in token claims + run ./otdfctl $HOST $WITH_CREDS policy sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXBhcnRtZW50Ijoibm93aGVyZV9zcGVjaWFsIn0.784uXYtfOv4tdM6JRgBMua4bBNDjUGbcr89QQKzCXfU' + assert_success + assert_output --partial "$NEW_SM_ID" + + run ./otdfctl $HOST $WITH_CREDS policy subject-mappings match --selector '.not_found' + assert_success + refute_output --partial "$NEW_SM_ID" + + run ./otdfctl $HOST $WITH_CREDS policy sm match -s '{"dept":"nope"}' + assert_success + refute_output --partial "$NEW_SM_ID" + + # JWT lacks 'department' in token claims + run ./otdfctl $HOST $WITH_CREDS policy sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhYmMiOiJub3doZXJlX3NwZWNpYWwifQ.H39TXi1gYWRhXIRkfxFJwrZz42eE4y8V5BQX-mg8JAo' + assert_success + assert_output --partial "$NEW_SM_ID" +} + @test "Get subject mapping" { new_scs=$(./otdfctl $HOST $WITH_CREDS policy scs create -s "$SCS_2" --json | jq -r '.id') created=$(./otdfctl $HOST $WITH_CREDS policy sm create -a "$VAL2_ID" -s TRANSMIT --subject-condition-set-id "$new_scs" --json | jq -r '.id') From 47791e19da6652778a0e025d5bfe2772dcc60956 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Wed, 13 Nov 2024 07:28:43 -0800 Subject: [PATCH 10/11] fix --- e2e/subject-mapping.bats | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/e2e/subject-mapping.bats b/e2e/subject-mapping.bats index d132e69e..1c04a87f 100755 --- a/e2e/subject-mapping.bats +++ b/e2e/subject-mapping.bats @@ -62,31 +62,31 @@ teardown_file() { NEW_SCS='[{"condition_groups":[{"conditions":[{"operator":1,"subject_external_values":["sales"],"subject_external_selector_value":".department"}],"boolean_operator":2}]}]' NEW_SM_ID=$(./otdfctl $HOST $WITH_CREDS policy subject-mappings create -a "$VAL2_ID" --action-standard DECRYPT --subject-condition-set-new "$NEW_SCS" --json | jq -r '.id') - run ./otdfctl $HOST $WITH_CREDS policy sm match -x '.department' + run_otdfctl_sm match -x '.department' assert_success assert_output --partial "$NEW_SM_ID" - run ./otdfctl $HOST $WITH_CREDS policy sm match --subject '{"department":"any_department"}' + run_otdfctl_sm match --subject '{"department":"any_department"}' assert_success assert_output --partial "$NEW_SM_ID" # JWT includes 'department' in token claims - run ./otdfctl $HOST $WITH_CREDS policy sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXBhcnRtZW50Ijoibm93aGVyZV9zcGVjaWFsIn0.784uXYtfOv4tdM6JRgBMua4bBNDjUGbcr89QQKzCXfU' + run_otdfctl_sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXBhcnRtZW50Ijoibm93aGVyZV9zcGVjaWFsIn0.784uXYtfOv4tdM6JRgBMua4bBNDjUGbcr89QQKzCXfU' assert_success assert_output --partial "$NEW_SM_ID" - run ./otdfctl $HOST $WITH_CREDS policy subject-mappings match --selector '.not_found' + run_otdfctl_sm match --selector '.not_found' assert_success refute_output --partial "$NEW_SM_ID" - run ./otdfctl $HOST $WITH_CREDS policy sm match -s '{"dept":"nope"}' + run_otdfctl_sm match -s '{"dept":"nope"}' assert_success refute_output --partial "$NEW_SM_ID" # JWT lacks 'department' in token claims - run ./otdfctl $HOST $WITH_CREDS policy sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhYmMiOiJub3doZXJlX3NwZWNpYWwifQ.H39TXi1gYWRhXIRkfxFJwrZz42eE4y8V5BQX-mg8JAo' + run_otdfctl_sm match -s 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhYmMiOiJub3doZXJlX3NwZWNpYWwifQ.H39TXi1gYWRhXIRkfxFJwrZz42eE4y8V5BQX-mg8JAo' assert_success - assert_output --partial "$NEW_SM_ID" + refute_output --partial "$NEW_SM_ID" } @test "Get subject mapping" { From 450a82fd515c54a5ac4c0c671ac05490262a2e41 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Wed, 13 Nov 2024 07:47:16 -0800 Subject: [PATCH 11/11] allow tests passing locally to pass in CI --- e2e/subject-mapping.bats | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/subject-mapping.bats b/e2e/subject-mapping.bats index 1c04a87f..e240846e 100755 --- a/e2e/subject-mapping.bats +++ b/e2e/subject-mapping.bats @@ -66,7 +66,8 @@ teardown_file() { assert_success assert_output --partial "$NEW_SM_ID" - run_otdfctl_sm match --subject '{"department":"any_department"}' + matched_subject='{"department":"any_department"}' + run ./otdfctl policy sm match --subject "$matched_subject" $HOST $WITH_CREDS assert_success assert_output --partial "$NEW_SM_ID" @@ -79,7 +80,8 @@ teardown_file() { assert_success refute_output --partial "$NEW_SM_ID" - run_otdfctl_sm match -s '{"dept":"nope"}' + unmatched_subject='{"dept":"nope"}' + run ./otdfctl policy sm match -s "$unmatched_subject" $HOST $WITH_CREDS assert_success refute_output --partial "$NEW_SM_ID"