diff --git a/.circleci/config.yml b/.circleci/config.yml index c5eea80cc..66ed14d96 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,9 +5,9 @@ orbs: changelog: ory/changelog@0.1.2 goreleaser: ory/goreleaser@0.1.17 slack: circleci/slack@3.4.2 - nancy: ory/nancy@0.0.10 - docs: ory/docs@0.0.4 - golangci: ory/golangci@0.0.4 + nancy: ory/nancy@0.0.12 + docs: ory/docs@0.0.8 + golangci: ory/golangci@0.0.9 jobs: test: @@ -44,12 +44,20 @@ jobs: run: go test -race -short -v $(go list ./... | grep -v cmd) - run: go-acc -v -o coverage.txt ./... - - - run: ./scripts/test-e2e.sh # Submit coverage details - run: test -z "$CIRCLE_PR_NUMBER" && goveralls -service=circle-ci -coverprofile=coverage.txt -repotoken=$COVERALLS_REPO_TOKEN || echo "forks are not allowed to push to coveralls" + validate: + docker: + - image: circleci/golang:1.15-node + environment: + GO111MODULE: 'on' + working_directory: /go/src/github.com/ory/keto + steps: + - checkout + - golangci/lint + - docs/check-format workflows: version: 2 @@ -61,7 +69,7 @@ workflows: tags: only: /.*/ - - golangci/lint: + validate: filters: tags: only: /.*/ @@ -74,7 +82,7 @@ workflows: changelog/generate: requires: - test - - golangci/lint + - validate filters: tags: only: /.*/ @@ -84,7 +92,7 @@ workflows: docs/build: requires: - test - - golangci/lint + - validate filters: tags: only: /.*/ @@ -95,12 +103,12 @@ workflows: appname: Ory_Keto requires: - test - - golangci/lint + - validate - sdk/release: requires: - test - - golangci/lint + - validate - goreleaser/release filters: tags: @@ -117,7 +125,7 @@ workflows: requires: - goreleaser/test - test - - golangci/lint + - validate filters: branches: ignore: /.*/ diff --git a/cmd/0_init_test.go b/cmd/0_init_test.go deleted file mode 100644 index 22a21ed7b..000000000 --- a/cmd/0_init_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package cmd - -import ( - "fmt" - "os" - - "github.com/akutz/gotil" -) - -var port int - -func init() { - var osArgs = make([]string, len(os.Args)) - port = gotil.RandomTCPPort() - os.Setenv("DSN", "memory") - os.Setenv("SERVE_PORT", fmt.Sprintf("%d", port)) - os.Setenv("KETO_URL", fmt.Sprintf("http://127.0.0.1:%d", port)) - copy(osArgs, os.Args) -} diff --git a/cmd/client/helper.go b/cmd/client/helper.go index 84a63f6d1..50f7958fa 100644 --- a/cmd/client/helper.go +++ b/cmd/client/helper.go @@ -31,9 +31,6 @@ import ( "github.com/ory/x/cmdx" "github.com/ory/x/flagx" - "github.com/ory/x/stringslice" - - "github.com/ory/keto/engine/ladon" ) var hc = http.DefaultClient @@ -82,12 +79,6 @@ func Delete(location string) { fmt.Printf("Resource at location %s was deleted successfully!", location) } -func CheckLadonFlavor(flavor string) { - if !stringslice.Has(ladon.EnabledFlavors, flavor) { - cmdx.Fatalf("ORY Access Control Policy flavor %s is currently not supported, please choose one of: %v", flavor, ladon.EnabledFlavors) - } -} - func EndpointURL(cmd *cobra.Command) string { e := flagx.MustGetString(cmd, "endpoint") if e == "" { diff --git a/cmd/engines.go b/cmd/engines.go deleted file mode 100644 index 05f1fe7f1..000000000 --- a/cmd/engines.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// enginesCmd represents the engines command -var enginesCmd = &cobra.Command{ - Use: "engines", - Short: "Manage access control engines", -} - -func init() { - RootCmd.AddCommand(enginesCmd) - enginesCmd.PersistentFlags().String("endpoint", "", "URL of the ORY Keto server - defaults to environment variable KETO_URL") -} diff --git a/cmd/engines_acp.go b/cmd/engines_acp.go deleted file mode 100644 index 5a9405043..000000000 --- a/cmd/engines_acp.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// enginesAcpCmd represents the acp command -var enginesAcpCmd = &cobra.Command{ - Use: "acp", - Short: "Manage access control policy flavored engines", -} - -func init() { - enginesCmd.AddCommand(enginesAcpCmd) -} diff --git a/cmd/engines_acp_ory.go b/cmd/engines_acp_ory.go deleted file mode 100644 index 1f54af461..000000000 --- a/cmd/engines_acp_ory.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// enginesAcpOryCmd represents the ory command -var enginesAcpOryCmd = &cobra.Command{ - Use: "ory", - Short: "Manage the ORY access control policy engine", -} - -func init() { - enginesAcpCmd.AddCommand(enginesAcpOryCmd) - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // enginesAcpOryCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // enginesAcpOryCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/cmd/engines_acp_ory_allowed.go b/cmd/engines_acp_ory_allowed.go deleted file mode 100644 index 9b046ebc7..000000000 --- a/cmd/engines_acp_ory_allowed.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - - "github.com/ory/keto/internal/httpclient/client/engines" - "github.com/ory/keto/internal/httpclient/models" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryAllowedCmd represents the roles command -var enginesAcpOryAllowedCmd = &cobra.Command{ - Use: "allowed ", - Short: "Check if a request should be allowed or not", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 4) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - res, err := c.Engines.DoOryAccessControlPoliciesAllow( - engines.NewDoOryAccessControlPoliciesAllowParams(). - WithFlavor(args[0]). - WithBody(&models.OryAccessControlPolicyAllowedInput{ - Subject: args[1], - Resource: args[2], - Action: args[3], - }), - ) - if err != nil { - switch d := err.(type) { - case *engines.DoOryAccessControlPoliciesAllowForbidden: - fmt.Println(cmdx.FormatResponse(&d.Payload)) - return - default: - cmdx.Must(err, "Unable to call ORY Access Control Policy allowed endpoint: %s") - } - } - fmt.Println(cmdx.FormatResponse(&res.Payload)) - }, -} - -func init() { - enginesAcpOryCmd.AddCommand(enginesAcpOryAllowedCmd) -} diff --git a/cmd/engines_acp_ory_policies.go b/cmd/engines_acp_ory_policies.go deleted file mode 100644 index 3615a1f3d..000000000 --- a/cmd/engines_acp_ory_policies.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// enginesAcpOryPoliciesCmd represents the policies command -var enginesAcpOryPoliciesCmd = &cobra.Command{ - Use: "policies", - Short: "Manage ORY Access Control Policies", -} - -func init() { - enginesAcpOryCmd.AddCommand(enginesAcpOryPoliciesCmd) -} diff --git a/cmd/engines_acp_ory_policies_delete.go b/cmd/engines_acp_ory_policies_delete.go deleted file mode 100644 index 8f612d17b..000000000 --- a/cmd/engines_acp_ory_policies_delete.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryPoliciesDeleteCmd represents the delete command -var enginesAcpOryPoliciesDeleteCmd = &cobra.Command{ - Use: "delete [, [<...>]]", - Short: "Delete an ORY Access Control Policy", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, id := range args[1:] { - _, err := c.Engines.DeleteOryAccessControlPolicy(engines.NewDeleteOryAccessControlPolicyParams().WithFlavor(args[0]).WithID(id)) - cmdx.Must(err, "Unable to delete ORY Access Control Policy: %s", err) - } - }, -} - -func init() { - enginesAcpOryPoliciesCmd.AddCommand(enginesAcpOryPoliciesDeleteCmd) -} diff --git a/cmd/engines_acp_ory_policies_get.go b/cmd/engines_acp_ory_policies_get.go deleted file mode 100644 index f9a02df75..000000000 --- a/cmd/engines_acp_ory_policies_get.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryPoliciesGetCmd represents the get command -var enginesAcpOryPoliciesGetCmd = &cobra.Command{ - Use: "get [, [<...>]]", - Short: "Get an ORY Access Control Policy", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, id := range args[1:] { - r, err := c.Engines.GetOryAccessControlPolicy(engines.NewGetOryAccessControlPolicyParams().WithFlavor(args[0]).WithID(id)) - cmdx.Must(err, "Unable to get ORY Access Control Policy: %s", err) - fmt.Println(cmdx.FormatResponse(r.Payload)) - } - }, -} - -func init() { - enginesAcpOryPoliciesCmd.AddCommand(enginesAcpOryPoliciesGetCmd) -} diff --git a/cmd/engines_acp_ory_policies_import.go b/cmd/engines_acp_ory_policies_import.go deleted file mode 100644 index 692897d9d..000000000 --- a/cmd/engines_acp_ory_policies_import.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/ory/keto/internal/httpclient/client/engines" - "github.com/ory/keto/internal/httpclient/models" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryPoliciesImportCmd represents the import command -var enginesAcpOryPoliciesImportCmd = &cobra.Command{ - Use: "import [, [, [...]]", - Short: "Import an ORY Access Control Policy", - Long: `This command imports one or more json files into the ORY Access Control Policy store. - -The json file(s) have to be formatted as arrays: - -[ - {"id": "1", "subjects": [...], ...}, - {"id": "2", "subjects": [...], ...}, -]`, - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, file := range args[1:] { - var p []models.OryAccessControlPolicy - client.ImportFile( - file, - &p, - func() { - for _, pp := range p { - _, err := c.Engines.UpsertOryAccessControlPolicy(engines.NewUpsertOryAccessControlPolicyParams().WithFlavor(args[0]).WithBody(&pp)) - cmdx.Must(err, "Unable to import ORY Access Control Policy: %s", err) - } - }, - ) - } - }, -} - -func init() { - enginesAcpOryPoliciesCmd.AddCommand(enginesAcpOryPoliciesImportCmd) -} diff --git a/cmd/engines_acp_ory_policies_list.go b/cmd/engines_acp_ory_policies_list.go deleted file mode 100644 index 3d038c710..000000000 --- a/cmd/engines_acp_ory_policies_list.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/spf13/cobra" - - "github.com/ory/x/flagx" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryPoliciesListCmd represents the list command -var enginesAcpOryPoliciesListCmd = &cobra.Command{ - Use: "list ", - Short: "List ORY Access Control Policies", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 1) - client.CheckLadonFlavor(args[0]) - - limit := int64(flagx.MustGetInt(cmd, "limit")) - offset := int64(flagx.MustGetInt(cmd, "offset")) - c := client.NewClient(cmd) - r, err := c.Engines.ListOryAccessControlPolicies( - engines.NewListOryAccessControlPoliciesParams().WithFlavor(args[0]).WithLimit(&limit).WithOffset(&offset), - ) - cmdx.Must(err, "Unable to list ORY Access Control Policies: %s", err) - fmt.Println(cmdx.FormatResponse(r.Payload)) - }, -} - -func init() { - enginesAcpOryPoliciesCmd.AddCommand(enginesAcpOryPoliciesListCmd) - enginesAcpOryPoliciesListCmd.Flags().Int("limit", 100, "Limit the items being fetched") - enginesAcpOryPoliciesListCmd.Flags().Int("offset", 0, "Set the offset for fetching items") -} diff --git a/cmd/engines_acp_ory_roles.go b/cmd/engines_acp_ory_roles.go deleted file mode 100644 index 7635e2423..000000000 --- a/cmd/engines_acp_ory_roles.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// enginesAcpOryRolesCmd represents the roles command -var enginesAcpOryRolesCmd = &cobra.Command{ - Use: "roles", - Short: "Manage ORY Access Control Roles", -} - -func init() { - enginesAcpOryCmd.AddCommand(enginesAcpOryRolesCmd) -} diff --git a/cmd/engines_acp_ory_roles_delete.go b/cmd/engines_acp_ory_roles_delete.go deleted file mode 100644 index a243e62d3..000000000 --- a/cmd/engines_acp_ory_roles_delete.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" - - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// deleteCmd represents the delete command -var deleteCmd = &cobra.Command{ - Use: "delete [, [<...>]]", - Short: "Delete an ORY Access Control Policy Role", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, id := range args[1:] { - _, err := c.Engines.DeleteOryAccessControlPolicyRole(engines.NewDeleteOryAccessControlPolicyRoleParams().WithFlavor(args[0]).WithID(id)) - cmdx.Must(err, "Unable to delete ORY Access Control Policy Role: %s", err) - } - }, -} - -func init() { - enginesAcpOryRolesCmd.AddCommand(deleteCmd) -} diff --git a/cmd/engines_acp_ory_roles_get.go b/cmd/engines_acp_ory_roles_get.go deleted file mode 100644 index 60661b6a3..000000000 --- a/cmd/engines_acp_ory_roles_get.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// getCmd represents the get command -var getCmd = &cobra.Command{ - Use: "get [, [<...>]]", - Short: "Get an ORY Access Control Policy", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, id := range args[1:] { - r, err := c.Engines.GetOryAccessControlPolicyRole(engines.NewGetOryAccessControlPolicyRoleParams().WithFlavor(args[0]).WithID(id)) - cmdx.Must(err, "Unable to get ORY Access Control Policy Role: %s", err) - fmt.Println(cmdx.FormatResponse(r.Payload)) - } - }, -} - -func init() { - enginesAcpOryRolesCmd.AddCommand(getCmd) -} diff --git a/cmd/engines_acp_ory_roles_import.go b/cmd/engines_acp_ory_roles_import.go deleted file mode 100644 index 0a2ca5f5c..000000000 --- a/cmd/engines_acp_ory_roles_import.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/ory/keto/internal/httpclient/client/engines" - "github.com/ory/keto/internal/httpclient/models" - - "github.com/spf13/cobra" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// importCmd represents the import command -var importCmd = &cobra.Command{ - Use: "import [, [, [...]]", - Short: "Import an ORY Access Control Policy", - Long: `This command imports one or more json files into the ORY Access Control Policy Role store. - -The json file(s) have to be formatted as arrays: - -[ - {"id": "1", "members": [...], ...}, - {"id": "2", "members": [...], ...}, -]`, - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 2) - client.CheckLadonFlavor(args[0]) - - c := client.NewClient(cmd) - for _, file := range args[1:] { - var p []models.OryAccessControlPolicyRole - client.ImportFile( - file, - &p, - func() { - for _, pp := range p { - _, err := c.Engines.UpsertOryAccessControlPolicyRole(engines.NewUpsertOryAccessControlPolicyRoleParams().WithFlavor(args[0]).WithBody(&pp)) - cmdx.Must(err, "Unable to import ORY Access Control Policy Role: %s", err) - } - }, - ) - } - }, -} - -func init() { - enginesAcpOryRolesCmd.AddCommand(importCmd) -} diff --git a/cmd/engines_acp_ory_roles_list.go b/cmd/engines_acp_ory_roles_list.go deleted file mode 100644 index 6d29b6528..000000000 --- a/cmd/engines_acp_ory_roles_list.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "fmt" - - "github.com/ory/keto/internal/httpclient/client/engines" - - "github.com/spf13/cobra" - - "github.com/ory/x/flagx" - - "github.com/ory/x/cmdx" - - "github.com/ory/keto/cmd/client" -) - -// enginesAcpOryRolesListCmd represents the list command -var enginesAcpOryRolesListCmd = &cobra.Command{ - Use: "list ", - Short: "List ORY Access Control Policy Roles", - Run: func(cmd *cobra.Command, args []string) { - cmdx.MinArgs(cmd, args, 1) - client.CheckLadonFlavor(args[0]) - - limit := int64(flagx.MustGetInt(cmd, "limit")) - offset := int64(flagx.MustGetInt(cmd, "offset")) - member := flagx.MustGetString(cmd, "member") - c := client.NewClient(cmd) - r, err := c.Engines.ListOryAccessControlPolicyRoles( - engines.NewListOryAccessControlPolicyRolesParams().WithFlavor(args[0]).WithLimit(&limit).WithOffset(&offset).WithMember(&member), - ) - cmdx.Must(err, "Unable to list ORY Access Control Policy Roles: %s", err) - fmt.Println(cmdx.FormatResponse(r.Payload)) - }, -} - -func init() { - enginesAcpOryRolesCmd.AddCommand(enginesAcpOryRolesListCmd) - enginesAcpOryRolesListCmd.Flags().String("member", "", "Member ID for whom roles are being fetched") - enginesAcpOryRolesListCmd.Flags().Int("limit", 100, "Limit the items being fetched") - enginesAcpOryRolesListCmd.Flags().Int("offset", 0, "Set the offset for fetching items") -} diff --git a/cmd/migrate.go b/cmd/migrate.go deleted file mode 100644 index 166320db7..000000000 --- a/cmd/migrate.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/spf13/cobra" -) - -// migrateCmd represents the migrate command -var migrateCmd = &cobra.Command{ - Use: "migrate", -} - -func init() { - RootCmd.AddCommand(migrateCmd) -} diff --git a/cmd/migrate_sql.go b/cmd/migrate_sql.go deleted file mode 100644 index 7988aab22..000000000 --- a/cmd/migrate_sql.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright © 2018 NAME HERE -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cmd - -import ( - "github.com/ory/x/sqlcon" - - "github.com/ory/keto/storage" -) - -// migrateSqlCmd represents the sql command -var migrateSqlCmd = sqlcon.MigratorSQLCmd("migrate", "sql", logger, map[string]sqlcon.SchemaCreator{ - "storage": storage.NewSQLManager(nil), -}) - -func init() { - migrateCmd.AddCommand(migrateSqlCmd) -} diff --git a/cmd/root_test.go b/cmd/root_test.go deleted file mode 100644 index 607ceff9f..000000000 --- a/cmd/root_test.go +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright © 2015-2018 Aeneas Rekkas - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * @author Aeneas Rekkas - * @Copyright 2015-2018 Aeneas Rekkas - * @license Apache-2.0 - * - */ - -package cmd - -import ( - "fmt" - "net/http" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - "github.com/ory/viper" -) - -func TestExecute(t *testing.T) { - viper.Set("dsn", "memory") - ep := fmt.Sprintf("http://127.0.0.1:%d", port) - - for _, c := range []struct { - args []string - wait func(t *testing.T) bool - expectErr bool - }{ - { - args: []string{"serve", "--disable-telemetry"}, - wait: func(t *testing.T) bool { - t.Logf("Trying to connect to port %d...", port) - _, err := http.DefaultClient.Get(fmt.Sprintf("http://127.0.0.1:%d/", port)) - return err != nil - }, - }, - {args: []string{"engines", "acp", "ory", "roles", "list", "exact"}}, - {args: []string{"engines", "acp", "ory", "roles", "import", "--endpoint", ep, "exact", "../tests/stubs/roles.json"}}, - {args: []string{"engines", "acp", "ory", "roles", "get", "--endpoint", ep, "exact", "role-1"}}, - {args: []string{"engines", "acp", "ory", "roles", "delete", "--endpoint", ep, "exact", "role-1"}}, - - {args: []string{"engines", "acp", "ory", "policies", "list", "--endpoint", ep, "exact"}}, - {args: []string{"engines", "acp", "ory", "policies", "import", "--endpoint", ep, "exact", "../tests/stubs/policies.json"}}, - {args: []string{"engines", "acp", "ory", "policies", "get", "--endpoint", ep, "exact", "policy-1"}}, - {args: []string{"engines", "acp", "ory", "policies", "delete", "--endpoint", ep, "exact", "policy-1"}}, - - {args: []string{"engines", "acp", "ory", "allowed", "--endpoint", ep, "exact", "peter-1", "resources-11", "actions-11"}}, - - {args: []string{"help", "migrate", "sql"}}, - {args: []string{"version"}}, - } { - RootCmd.SetArgs(c.args) - - t.Run(fmt.Sprintf("command=%v", c.args), func(t *testing.T) { - if c.wait != nil { - go func() { - assert.Nil(t, RootCmd.Execute()) - }() - } - - if c.wait != nil { - var count = 0 - for c.wait(t) { - t.Logf("Port not open yet, retrying attempt #%d...", count) - count++ - if count > 30 { - t.FailNow() - } - time.Sleep(time.Second) - } - } else { - err := RootCmd.Execute() - if c.expectErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - } - }) - } -} diff --git a/cmd/server/serve.go b/cmd/server/serve.go index 4d5ce4d86..21bcffdb1 100644 --- a/cmd/server/serve.go +++ b/cmd/server/serve.go @@ -42,17 +42,12 @@ import ( "github.com/ory/graceful" "github.com/ory/x/stringslice" - "github.com/ory/keto/engine/ladon" - "github.com/ory/x/cmdx" "github.com/ory/x/corsx" "github.com/ory/x/healthx" "github.com/ory/x/metricsx" "github.com/ory/x/reqlog" "github.com/ory/x/tlsx" - - // This forces go mod vendor to look for the package rego and its subpackages - _ "github.com/ory/keto/engine/ladon/rego" ) // RunServe runs the Keto API HTTP server @@ -67,7 +62,6 @@ func RunServe( ) router := httprouter.New() - d.Registry().LadonEngine().Register(router) d.Registry().HealthHandler().SetRoutes(router, true) n := negroni.New() @@ -85,7 +79,6 @@ func RunServe( WriteKey: "jk32cFATnj9GKbQdFL7fBB9qtKZdX9j7", WhitelistedPaths: stringslice.Merge( healthx.RoutesToObserve(), - ladon.RoutesToObserve(), ), BuildVersion: version, BuildTime: date, @@ -120,7 +113,10 @@ func RunServe( } else if err != nil { cmdx.Must(err, "Unable to load HTTP TLS certificate(s): %s", err) } else { - server.TLSConfig = &tls.Config{Certificates: cert} + server.TLSConfig = &tls.Config{ + Certificates: cert, + MinVersion: tls.VersionTLS10, + } } if d.Registry().Tracer().IsLoaded() { diff --git a/driver/registry.go b/driver/registry.go index 50d6a9c64..74c075020 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -1,7 +1,6 @@ package driver import ( - "github.com/open-policy-agent/opa/ast" "github.com/pkg/errors" "github.com/ory/x/dbal" @@ -10,9 +9,6 @@ import ( "github.com/ory/x/tracing" "github.com/ory/keto/driver/configuration" - "github.com/ory/keto/engine" - "github.com/ory/keto/engine/ladon" - "github.com/ory/keto/storage" "github.com/ory/keto/x" ) @@ -28,13 +24,8 @@ type Registry interface { x.RegistryLogger x.RegistryWriter - engine.Registry - storage.Registry - EngineCompiler() *ast.Compiler - StorageHandler() *storage.Handler HealthHandler() *healthx.Handler - LadonEngine() *ladon.Engine Tracer() *tracing.Tracer } diff --git a/driver/registry_base.go b/driver/registry_base.go deleted file mode 100644 index d88d4ccc8..000000000 --- a/driver/registry_base.go +++ /dev/null @@ -1,142 +0,0 @@ -package driver - -import ( - "github.com/gobuffalo/packr" - "github.com/open-policy-agent/opa/ast" - - "github.com/ory/herodot" - "github.com/ory/x/healthx" - "github.com/ory/x/logrusx" - "github.com/ory/x/tracing" - - "github.com/ory/keto/driver/configuration" - "github.com/ory/keto/engine" - "github.com/ory/keto/engine/ladon" - "github.com/ory/keto/storage" -) - -type RegistryBase struct { - l *logrusx.Logger - c configuration.Provider - writer herodot.Writer - buildVersion string - buildHash string - buildDate string - r Registry - trc *tracing.Tracer - - hh *healthx.Handler - ac *ast.Compiler - ee *engine.Engine - le *ladon.Engine - sh *storage.Handler -} - -func (m *RegistryBase) with(r Registry) *RegistryBase { - m.r = r - return m -} - -func (m *RegistryBase) WithBuildInfo(version, hash, date string) Registry { - m.buildVersion = version - m.buildHash = hash - m.buildDate = date - return m.r -} -func (m *RegistryBase) BuildVersion() string { - return m.buildVersion -} - -func (m *RegistryBase) BuildDate() string { - return m.buildDate -} - -func (m *RegistryBase) BuildHash() string { - return m.buildHash -} - -func (m *RegistryBase) WithConfig(c configuration.Provider) Registry { - m.c = c - return m.r -} - -func (m *RegistryBase) Writer() herodot.Writer { - if m.writer == nil { - h := herodot.NewJSONWriter(m.Logger()) - h.ErrorEnhancer = nil - m.writer = h - } - return m.writer -} - -func (m *RegistryBase) WithLogger(l *logrusx.Logger) Registry { - m.l = l - return m.r -} - -func (m *RegistryBase) Logger() *logrusx.Logger { - if m.l == nil { - m.l = logrusx.New("ORY Keto", m.buildVersion) - } - return m.l -} - -func (m *RegistryBase) EngineCompiler() *ast.Compiler { - if m.ac == nil { - box := packr.NewBox("../engine/ladon/rego") - compiler, err := engine.NewCompiler(box, m.Logger()) - if err != nil { - m.Logger().WithError(err).Fatalf("Unable to initialize compiler") - } - m.ac = compiler - } - return m.ac -} - -func (m *RegistryBase) Engine() *engine.Engine { - if m.ee == nil { - m.ee = engine.NewEngine(m.EngineCompiler(), m.Writer()) - } - return m.ee -} - -func (m *RegistryBase) LadonEngine() *ladon.Engine { - if m.le == nil { - m.le = ladon.NewEngine(m.r.StorageManager(), m.StorageHandler(), m.Engine(), m.Writer()) - } - return m.le -} - -func (m *RegistryBase) StorageHandler() *storage.Handler { - if m.sh == nil { - m.sh = storage.NewHandler(m.r.StorageManager(), m.Writer()) - } - return m.sh -} - -func (m *RegistryBase) HealthHandler() *healthx.Handler { - if m.hh == nil { - m.hh = healthx.NewHandler(m.Writer(), m.buildVersion, healthx.ReadyCheckers{ - "database": m.r.Ping, - }) - } - - return m.hh -} - -func (m *RegistryBase) Tracer() *tracing.Tracer { - if m.trc == nil { - m.trc = &tracing.Tracer{ - ServiceName: m.c.TracingServiceName(), - JaegerConfig: m.c.TracingJaegerConfig(), - Provider: m.c.TracingProvider(), - Logger: m.Logger(), - } - - if err := m.trc.Setup(); err != nil { - m.Logger().WithError(err).Fatalf("Unable to initialize Tracer.") - } - } - - return m.trc -} diff --git a/driver/registry_memory.go b/driver/registry_memory.go deleted file mode 100644 index 3cd40a5e1..000000000 --- a/driver/registry_memory.go +++ /dev/null @@ -1,48 +0,0 @@ -package driver - -import ( - "github.com/ory/x/dbal" - - "github.com/ory/keto/storage" -) - -type RegistryMemory struct { - *RegistryBase - - sm storage.Manager -} - -var _ Registry = new(RegistryMemory) - -func init() { - dbal.RegisterDriver(func() dbal.Driver { - return NewRegistryMemory() - }) -} - -func NewRegistryMemory() *RegistryMemory { - r := &RegistryMemory{ - RegistryBase: new(RegistryBase), - } - r.RegistryBase.with(r) - return r -} - -func (m *RegistryMemory) Init() error { - return nil -} - -func (m *RegistryMemory) CanHandle(dsn string) bool { - return dsn == "memory" -} - -func (m *RegistryMemory) Ping() error { - return nil -} - -func (m *RegistryMemory) StorageManager() storage.Manager { - if m.sm == nil { - m.sm = storage.NewMemoryManager() - } - return m.sm -} diff --git a/driver/registry_sql.go b/driver/registry_sql.go deleted file mode 100644 index a7163cd8d..000000000 --- a/driver/registry_sql.go +++ /dev/null @@ -1,84 +0,0 @@ -package driver - -import ( - "time" - - "github.com/jmoiron/sqlx" - - "github.com/ory/x/dbal" - "github.com/ory/x/sqlcon" - - "github.com/ory/keto/storage" -) - -type RegistrySQL struct { - *RegistryBase - db *sqlx.DB - sm storage.Manager - dbalOptions []sqlcon.OptionModifier -} - -var _ Registry = new(RegistrySQL) - -func init() { - dbal.RegisterDriver(func() dbal.Driver { - return NewRegistrySQL() - }) -} - -func NewRegistrySQL() *RegistrySQL { - r := &RegistrySQL{ - RegistryBase: new(RegistryBase), - } - r.RegistryBase.with(r) - return r -} - -func (m *RegistrySQL) DB() *sqlx.DB { - if m.db == nil { - if err := m.Init(); err != nil { - m.Logger().WithError(err).Fatalf("Unable to initialize database.") - } - } - - return m.db -} - -func (m *RegistrySQL) Init() error { - if m.db != nil { - return nil - } - - options := append([]sqlcon.OptionModifier{}, m.dbalOptions...) - if m.Tracer().IsLoaded() { - options = append(options, sqlcon.WithDistributedTracing(), sqlcon.WithOmitArgsFromTraceSpans()) - } - - connection, err := sqlcon.NewSQLConnection(m.c.DSN(), m.Logger(), options...) - if err != nil { - return err - } - - m.db, err = connection.GetDatabaseRetry(time.Second*5, time.Minute*5) - if err != nil { - return err - } - - return err -} - -func (m *RegistrySQL) StorageManager() storage.Manager { - if m.sm == nil { - m.sm = storage.NewSQLManager(m.DB()) - } - return m.sm -} - -func (m *RegistrySQL) CanHandle(dsn string) bool { - s := sqlcon.GetDriverName(dsn) - return s == dbal.DriverMySQL || s == dbal.DriverPostgreSQL -} - -func (m *RegistrySQL) Ping() error { - return m.DB().Ping() -} diff --git a/driver/registry_sql_test.go b/driver/registry_sql_test.go deleted file mode 100644 index 662e907ae..000000000 --- a/driver/registry_sql_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package driver - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRegistrySQL_CanHandle(t *testing.T) { - for k, tc := range []struct { - dsn string - expected bool - }{ - {dsn: "memory"}, - {dsn: "mysql://foo:bar@tcp(baz:1234)/db?foo=bar", expected: true}, - {dsn: "postgres://foo:bar@baz:1234/db?foo=bar", expected: true}, - } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - r := RegistrySQL{} - assert.Equal(t, tc.expected, r.CanHandle(tc.dsn)) - }) - } -} diff --git a/engine/compiler.go b/engine/compiler.go deleted file mode 100644 index 451743c1b..000000000 --- a/engine/compiler.go +++ /dev/null @@ -1,59 +0,0 @@ -package engine - -import ( - "path/filepath" - "strings" - - "github.com/gobuffalo/packr" - "github.com/open-policy-agent/opa/ast" - "github.com/pkg/errors" - - "github.com/ory/x/logrusx" -) - -func walk(directory packr.Box, logger *logrusx.Logger) (map[string]string, error) { - m := map[string]string{} - if err := directory.Walk(func(path string, file packr.File) error { - if filepath.Ext(path) != ".rego" { - return nil - } - - if strings.Contains(path, "_test.rego") { - return nil - } - - m[path] = directory.String(path) - logger.WithField("file", path).Debugf("Successfully loaded rego file") - - return nil - }); err != nil { - return nil, err - } - - return m, nil -} - -func NewCompiler(directory packr.Box, logger *logrusx.Logger) (*ast.Compiler, error) { - files, err := walk(directory, logger) - if err != nil { - return nil, err - } - - modules := map[string]*ast.Module{} - for file, content := range files { - parsed, err := ast.ParseModule(file, content) - if err != nil { - return nil, errors.WithStack(err) - } - modules[file] = parsed - } - - compiler := ast.NewCompiler() - compiler.Compile(modules) - - if compiler.Failed() { - return nil, errors.Errorf("unable to compile module with payload: %s", compiler.Errors) - } - - return compiler, nil -} diff --git a/engine/doc.go b/engine/doc.go deleted file mode 100644 index a720e4760..000000000 --- a/engine/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Package engine -package engine - -// AuthorizationResult is the result of an access control decision. It contains the decision outcome. -// swagger:model authorizationResult -type AuthorizationResult struct { - // Allowed is true if the request should be allowed and false otherwise. - // - // required: true - Allowed bool `json:"allowed"` -} diff --git a/engine/engine.go b/engine/engine.go deleted file mode 100644 index 6e5d56557..000000000 --- a/engine/engine.go +++ /dev/null @@ -1,84 +0,0 @@ -package engine - -import ( - "context" - "net/http" - - "github.com/julienschmidt/httprouter" - "github.com/open-policy-agent/opa/ast" - "github.com/open-policy-agent/opa/rego" - "github.com/pkg/errors" - - "github.com/ory/herodot" -) - -// swagger:ignore -type Engine struct { - compiler *ast.Compiler - h herodot.Writer -} - -func NewEngine( - compiler *ast.Compiler, - h herodot.Writer, -) *Engine { - return &Engine{ - compiler: compiler, - h: h, - } -} - -// swagger:ignore -type evaluator func(ctx context.Context, r *http.Request, ps httprouter.Params) ([]func(*rego.Rego), error) - -func (h *Engine) Evaluate(e evaluator) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ctx := r.Context() - - rs, err := e(ctx, r, ps) - if err != nil { - h.h.WriteError(w, r, err) - return - } - - allowed, err := h.eval(ctx, rs) - if err != nil { - h.h.WriteError(w, r, err) - return - } - - code := http.StatusOK - if !allowed { - code = http.StatusForbidden - } - - h.h.WriteCode(w, r, code, &AuthorizationResult{Allowed: allowed}) - } -} - -func (h *Engine) eval(ctx context.Context, options []func(*rego.Rego)) (bool, error) { - // tracer := topdown.NewBufferTracer() - r := rego.New( - append( - options, - rego.Compiler(h.compiler), - // rego.Tracer(tracer), - )..., - ) - - rs, err := r.Eval(ctx) - if err != nil { - return false, errors.WithStack(err) - } - - if len(rs) != 1 || len(rs[0].Expressions) != 1 { - return false, errors.Errorf("expected one evaluation result but got %d results instead", len(rs)) - } - - result, ok := rs[0].Expressions[0].Value.(bool) - if !ok { - return false, errors.Errorf("expected evaluation result to be of type bool but got %T instead", rs[0].Expressions[0].Value) - } - - return result, nil -} diff --git a/engine/ladon/doc.go b/engine/ladon/doc.go deleted file mode 100644 index ba57bd51f..000000000 --- a/engine/ladon/doc.go +++ /dev/null @@ -1,280 +0,0 @@ -// Package ladon -package ladon - -// swagger:parameters doOryAccessControlPoliciesAllow -type doOryAccessControlPoliciesAllow struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // in: body - Body oryAccessControlPolicyAllowedInput -} - -// Input for checking if a request is allowed or not. -// -// swagger:model oryAccessControlPolicyAllowedInput -type oryAccessControlPolicyAllowedInput struct { - // Resource is the resource that access is requested to. - Resource string `json:"resource"` - - // Action is the action that is requested on the resource. - Action string `json:"action"` - - // Subject is the subject that is requesting access. - Subject string `json:"subject"` - - // Context is the request's environmental context. - Context map[string]interface{} `json:"context"` -} - -// swagger:parameters upsertOryAccessControlPolicy -type upsertOryAccessControlPolicy struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // in: body - Body oryAccessControlPolicy -} - -// swagger:parameters listOryAccessControlPolicies -type listOryAccessControlPolicies struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact" - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The maximum amount of policies returned. - // - // in: query - Limit int `json:"limit"` - - // The offset from where to start looking. - // - // in: query - Offset int `json:"offset"` - - // The subject for whom the policies are to be listed. - // - // in: query - Subject string `json:"subject"` - - // The resource for which the policies are to be listed. - // - // in: query - Resource string `json:"resource"` - - // The action for which policies are to be listed. - // - // in: query - Action string `json:"action"` -} - -// swagger:parameters getOryAccessControlPolicy -type getOryAccessControlPolicy struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // - // in: path - // required: true - ID string `json:"id"` -} - -// swagger:parameters deleteOryAccessControlPolicy -type deleteOryAccessControlPolicy struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // - // in: path - // required: true - ID string `json:"id"` -} - -// swagger:parameters getOryAccessControlPolicyRole -type getOryAccessControlPolicyRole struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // - // in: path - // required: true - ID string `json:"id"` -} - -// swagger:parameters deleteOryAccessControlPolicyRole -type deleteOryAccessControlPolicyRole struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // in: path - // required: true - ID string `json:"id"` -} - -// swagger:parameters upsertOryAccessControlPolicyRole -type upsertOryAccessControlPolicyRole struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // in: body - Body oryAccessControlPolicyRole -} - -// swagger:model addOryAccessControlPolicyRoleMembersBody -type addOryAccessControlPolicyRoleMembersBody struct { - // The members to be added. - Members []string `json:"members"` -} - -// swagger:parameters addOryAccessControlPolicyRoleMembers -type addOryAccessControlPolicyRoleMembers struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // - // in: path - // required: true - ID string `json:"id"` - - // in: body - Body addOryAccessControlPolicyRoleMembersBody -} - -// swagger:parameters removeOryAccessControlPolicyRoleMembers -type removeOryAccessControlPolicyRoleMembers struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact". - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The ID of the ORY Access Control Policy Role. - // - // in: path - // required: true - ID string `json:"id"` - - // The member to be removed. - // - // in: path - // required: true - Member string `json:"member"` -} - -// Policies is an array of policies. -// -// swagger:response oryAccessControlPolicies -type oryAccessControlPolicies struct { - // The request body. - // - // in: body - // type: array - Body []oryAccessControlPolicy -} - -// Roles is an array of roles. -// -// swagger:response oryAccessControlPolicyRoles -type oryAccessControlPolicyRoles struct { - // The request body. - // - // in: body - // type: array - Body []oryAccessControlPolicyRole -} - -// oryAccessControlPolicyRole represents a group of users that share the same role. A role could be an administrator, a moderator, a regular -// user or some other sort of role. -// -// swagger:model oryAccessControlPolicyRole -type oryAccessControlPolicyRole struct { - // ID is the role's unique id. - ID string `json:"id"` - - // Description is the description of the role. - Description string `json:"description"` - - // Members is who belongs to the role. - Members []string `json:"members"` -} - -// oryAccessControlPolicy specifies an ORY Access Policy document. -// -// swagger:model oryAccessControlPolicy -type oryAccessControlPolicy struct { - // ID is the unique identifier of the ORY Access Policy. It is used to query, update, and remove the ORY Access Policy. - ID string `json:"id"` - - // Description is an optional, human-readable description. - Description string `json:"description"` - - // Subjects is an array representing all the subjects this ORY Access Policy applies to. - Subjects []string `json:"subjects"` - - // Resources is an array representing all the resources this ORY Access Policy applies to. - Resources []string `json:"resources"` - - // Actions is an array representing all the actions this ORY Access Policy applies to. - Actions []string `json:"actions"` - - // Effect is the effect of this ORY Access Policy. It can be "allow" or "deny". - Effect string `json:"effect"` - - // Conditions represents a keyed object of conditions under which this ORY Access Policy is active. - Conditions map[string]interface{} `json:"conditions"` -} - -// swagger:parameters listOryAccessControlPolicyRoles -type listOryAccessControlPolicyRoles struct { - // The ORY Access Control Policy flavor. Can be "regex", "glob", and "exact" - // - // in: path - // required: true - Flavor string `json:"flavor"` - - // The maximum amount of policies returned. - // - // in: query - Limit int `json:"limit"` - - // The offset from where to start looking. - // - // in: query - Offset int `json:"offset"` - - // The member for which the roles are to be listed. - // - // in: query - Member string `json:"member"` -} diff --git a/engine/ladon/handler.go b/engine/ladon/handler.go deleted file mode 100644 index 174f715f9..000000000 --- a/engine/ladon/handler.go +++ /dev/null @@ -1,504 +0,0 @@ -package ladon - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "strings" - - "github.com/julienschmidt/httprouter" - "github.com/open-policy-agent/opa/rego" - "github.com/pborman/uuid" - "github.com/pkg/errors" - - "github.com/ory/herodot" - "github.com/ory/x/stringslice" - - "github.com/ory/keto/engine" - kstorage "github.com/ory/keto/storage" -) - -// swagger:ignore -type Engine struct { - sh *kstorage.Handler - engine *engine.Engine - s kstorage.Manager - h herodot.Writer -} - -var EnabledFlavors = []string{"exact", "glob", "regex"} - -const ( - BasePath = "/engines/acp/ory/:flavor" - schema = `{ - "store": { - "ory": { - "regex": { - "policies": [], - "roles": [] - }, - "glob": { - "policies": [], - "roles": [] - }, - "exact": { - "policies": [], - "roles": [] - } - } - } -}` -) - -func RoutesToObserve() []string { - var r []string - - for _, f := range EnabledFlavors { - for _, p := range []string{"policies", "roles", "allowed"} { - r = append(r, - fmt.Sprintf(strings.Replace(BasePath, ":flavor", "%s", 1)+"/%s", f, p), - ) - } - } - - return r -} - -func policyCollection(f string) string { - return fmt.Sprintf("/store/ory/%s/policies", f) -} - -func roleCollection(f string) string { - return fmt.Sprintf("/store/ory/%s/roles", f) -} - -func NewEngine(store kstorage.Manager, sh *kstorage.Handler, e *engine.Engine, h herodot.Writer) *Engine { - return &Engine{ - s: store, - h: h, - sh: sh, - engine: e, - } -} - -func (e *Engine) Register(r *httprouter.Router) { - // swagger:route POST /engines/acp/ory/{flavor}/allowed engines doOryAccessControlPoliciesAllow - // - // Check if a request is allowed - // - // Use this endpoint to check if a request is allowed or not. If the request is allowed, a 200 response with - // `{"allowed":"true"}` will be sent. If the request is denied, a 403 response with `{"allowed":"false"}` will - // be sent instead. - // - // - // Consumes: - // - application/json - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: authorizationResult - // 403: authorizationResult - // 500: genericError - r.POST(BasePath+"/allowed", e.engine.Evaluate(e.eval)) - - // swagger:route PUT /engines/acp/ory/{flavor}/policies engines upsertOryAccessControlPolicy - // - // Upsert an ORY Access Control Policy - // - // - // Consumes: - // - application/json - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicy - // 500: genericError - r.PUT(BasePath+"/policies", e.sh.Upsert(e.policiesCreate)) - - // swagger:route GET /engines/acp/ory/{flavor}/policies engines listOryAccessControlPolicies - // - // List ORY Access Control Policies - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicies - // 500: genericError - r.GET(BasePath+"/policies", e.sh.List(e.policiesList)) - - // swagger:route GET /engines/acp/ory/{flavor}/policies/{id} engines getOryAccessControlPolicy - // - // Get an ORY Access Control Policy - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicy - // 404: genericError - // 500: genericError - r.GET(BasePath+"/policies/:id", e.sh.Get(e.policiesGet)) - - // swagger:route DELETE /engines/acp/ory/{flavor}/policies/{id} engines deleteOryAccessControlPolicy - // - // Delete an ORY Access Control Policy - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 204: emptyResponse - // 500: genericError - r.DELETE(BasePath+"/policies/:id", e.sh.Delete(e.policiesDelete)) - - // swagger:route GET /engines/acp/ory/{flavor}/roles engines listOryAccessControlPolicyRoles - // - // List ORY Access Control Policy Roles - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicyRoles - // 500: genericError - r.GET(BasePath+"/roles", e.sh.List(e.rolesList)) - - // swagger:route GET /engines/acp/ory/{flavor}/roles/{id} engines getOryAccessControlPolicyRole - // - // Get an ORY Access Control Policy Role - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicyRole - // 404: genericError - // 500: genericError - r.GET(BasePath+"/roles/:id", e.sh.Get(e.rolesGet)) - - // swagger:route PUT /engines/acp/ory/{flavor}/roles engines upsertOryAccessControlPolicyRole - // - // Upsert an ORY Access Control Policy Role - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Consumes: - // - application/json - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicyRole - // 500: genericError - r.PUT(BasePath+"/roles", e.sh.Upsert(e.rolesUpsert)) - - // swagger:route DELETE /engines/acp/ory/{flavor}/roles/{id} engines deleteOryAccessControlPolicyRole - // - // Delete an ORY Access Control Policy Role - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 204: emptyResponse - // 500: genericError - r.DELETE(BasePath+"/roles/:id", e.sh.Delete(e.rolesDelete)) - - // swagger:route PUT /engines/acp/ory/{flavor}/roles/{id}/members engines addOryAccessControlPolicyRoleMembers - // - // Add a member to an ORY Access Control Policy Role - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Consumes: - // - application/json - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: oryAccessControlPolicyRole - // 500: genericError - r.PUT(BasePath+"/roles/:id/members", e.sh.Upsert(e.rolesMembersAdd)) - - // swagger:route DELETE /engines/acp/ory/{flavor}/roles/{id}/members/{member} engines removeOryAccessControlPolicyRoleMembers - // - // Remove a member from an ORY Access Control Policy Role - // - // Roles group several subjects into one. Rules can be assigned to ORY Access Control Policy (OACP) by using the Role ID - // as subject in the OACP. - // - // - // Consumes: - // - application/json - // - // Produces: - // - application/json - // - // Schemes: http, https - // - // Responses: - // 200: emptyResponse - // 500: genericError - r.DELETE(BasePath+"/roles/:id/members/:member", e.sh.Upsert(e.rolesMembersRemove)) -} - -func (e *Engine) rolesList(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.ListRequest, error) { - p := make(kstorage.Roles, 0) - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.ListRequest{ - Collection: roleCollection(f), - Value: &p, - FilterFunc: kstorage.ListByQuery, - }, nil -} - -func (e *Engine) rolesGet(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.GetRequest, error) { - var p kstorage.Role - - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.GetRequest{ - Collection: roleCollection(f), - Key: ps.ByName("id"), - Value: &p, - }, nil -} - -func (e *Engine) rolesUpsert(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.UpsertRequest, error) { - var p kstorage.Role - if err := json.NewDecoder(r.Body).Decode(&p); err != nil { - return nil, errors.WithStack(err) - } - - if p.ID == "" { - p.ID = uuid.New() - } - - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.UpsertRequest{ - Collection: roleCollection(f), - Key: p.ID, - Value: &p, - }, nil -} - -func (e *Engine) rolesDelete(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.DeleteRequest, error) { - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.DeleteRequest{ - Collection: roleCollection(f), - Key: ps.ByName("id"), - }, nil -} - -func (e *Engine) rolesMembersAdd(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.UpsertRequest, error) { - f, err := flavor(ps) - if err != nil { - return nil, err - } - - var i kstorage.Role - if err := json.NewDecoder(r.Body).Decode(&i); err != nil { - return nil, errors.WithStack(err) - } - - var ro kstorage.Role - if err := e.s.Get(ctx, roleCollection(f), ps.ByName("id"), &ro); errors.Cause(err) == &herodot.ErrNotFound { - i.ID = ps.ByName("id") - ro = i - } else if err != nil { - return nil, err - } else { - ro.Members = stringslice.Unique(append(ro.Members, i.Members...)) - } - - return &kstorage.UpsertRequest{ - Collection: roleCollection(f), - Key: ro.ID, - Value: &ro, - }, nil - -} - -func (e *Engine) rolesMembersRemove(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.UpsertRequest, error) { - f, err := flavor(ps) - if err != nil { - return nil, err - } - - var ro kstorage.Role - if err := e.s.Get(ctx, roleCollection(f), ps.ByName("id"), &ro); err != nil { - return nil, err - } - - ro.Members = stringslice.Filter(ro.Members, func(s string) bool { - return s == ps.ByName("member") - }) - - return &kstorage.UpsertRequest{ - Collection: roleCollection(f), - Key: ro.ID, - Value: &ro, - }, nil -} - -func (e *Engine) policiesCreate(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.UpsertRequest, error) { - var p kstorage.Policy - if err := json.NewDecoder(r.Body).Decode(&p); err != nil { - return nil, errors.WithStack(err) - } - - p, err := validatePolicy(p) - if err != nil { - return nil, err - } - - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.UpsertRequest{ - Collection: policyCollection(f), - Key: p.ID, - Value: &p, - }, nil -} - -func (e *Engine) policiesList(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.ListRequest, error) { - - p := make(kstorage.Policies, 0) - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.ListRequest{ - Collection: policyCollection(f), - Value: &p, - FilterFunc: kstorage.ListByQuery, - }, nil -} - -func (e *Engine) policiesDelete(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.DeleteRequest, error) { - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.DeleteRequest{ - Collection: policyCollection(f), - Key: ps.ByName("id"), - }, nil -} - -func (e *Engine) policiesGet(ctx context.Context, r *http.Request, ps httprouter.Params) (*kstorage.GetRequest, error) { - var p kstorage.Policy - - f, err := flavor(ps) - if err != nil { - return nil, err - } - - return &kstorage.GetRequest{ - Collection: policyCollection(f), - Key: ps.ByName("id"), - Value: &p, - }, nil -} - -func flavor(ps httprouter.Params) (string, error) { - t := ps.ByName("flavor") - if !stringslice.Has(EnabledFlavors, t) { - return "", errors.WithStack(&herodot.ErrNotFound) - } - - return t, nil -} - -func (e *Engine) eval(ctx context.Context, r *http.Request, ps httprouter.Params) ([]func(*rego.Rego), error) { - f, err := flavor(ps) - if err != nil { - return nil, err - } - - query := fmt.Sprintf("data.ory.%s.allow", f) - store, err := e.s.Storage(ctx, schema, []string{policyCollection(f), roleCollection(f)}) - if err != nil { - return nil, err - } - - var i Input - dec := json.NewDecoder(r.Body) - dec.DisallowUnknownFields() - if err := dec.Decode(&i); err != nil { - return nil, errors.WithStack(err) - } - - return []func(*rego.Rego){ - rego.Query(query), - rego.Store(store), - rego.Input(&i), - }, nil -} diff --git a/engine/ladon/handler_helper.go b/engine/ladon/handler_helper.go deleted file mode 100644 index bacf2fb96..000000000 --- a/engine/ladon/handler_helper.go +++ /dev/null @@ -1,20 +0,0 @@ -package ladon - -import ( - "github.com/go-errors/errors" - "github.com/pborman/uuid" - - kstorage "github.com/ory/keto/storage" -) - -func validatePolicy(p kstorage.Policy) (kstorage.Policy, error) { - if len(p.ID) == 0 { - p.ID = uuid.New() - } - - if p.Effect != "allow" && p.Effect != "deny" { - return kstorage.Policy{}, errors.Errorf("invalid policy effect %s, only allow and deny are supported", p.Effect) - } - - return p, nil -} diff --git a/engine/ladon/handler_helper_test.go b/engine/ladon/handler_helper_test.go deleted file mode 100644 index a07dfc5fb..000000000 --- a/engine/ladon/handler_helper_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package ladon - -import ( - "github.com/ory/keto/internal/httpclient/models" - - kstorage "github.com/ory/keto/storage" -) - -var ( - roles = map[string]kstorage.Roles{ - "regex": {{ - ID: "group1", - Description: "group1 description", - Members: []string{"ken"}, - }, { - ID: "group2", - Description: "group12 description", - Members: []string{"ken"}, - }, { - ID: "group3", - Description: "group3 description", - Members: []string{"ben"}, - }}, - "exact": {{ - ID: "group1", - Description: "group1 description", - Members: []string{"ken"}, - }, { - ID: "group2", - Description: "group2 description", - Members: []string{"ken"}, - }, { - ID: "group3", - Description: "group3 description", - Members: []string{"ben"}, - }}, - } - requests = map[string][]struct { - req models.OryAccessControlPolicyAllowedInput - allowed bool - }{ - "regex": { - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "other-thing", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "matrix", - Action: "delete", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: true, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "ken", - Resource: "forbidden_matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "ken", - Resource: "allowed_matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: true, - }, - }, - "exact": { - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "other-thing", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "matrix", - Action: "delete", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "alice", - Resource: "matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: true, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "ken", - Resource: "forbidden_matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: false, - }, - { - req: models.OryAccessControlPolicyAllowedInput{ - Subject: "ken", - Resource: "allowed_matrix", - Action: "create", - Context: map[string]interface{}{}, - }, - allowed: true, - }, - }, - } - policies = map[string]kstorage.Policies{ - "regex": { - kstorage.Policy{ - ID: "1", - Subjects: []string{"alice", "group1", "client"}, - Resources: []string{"matrix", "forbidden_matrix", "rn:hydra:token<.*>"}, - Actions: []string{"create", "decide"}, - Effect: Allow, - }, - kstorage.Policy{ - ID: "2", - Subjects: []string{"siri"}, - Resources: []string{"<.*>"}, - Actions: []string{"decide"}, - Effect: Allow, - }, - kstorage.Policy{ - ID: "3", - Subjects: []string{"group1"}, - Resources: []string{"forbidden_matrix", "rn:hydra:token<.*>"}, - Actions: []string{"create", "decide"}, - Effect: Deny, - }, - kstorage.Policy{ - ID: "4", - Subjects: []string{"group1"}, - Resources: []string{"allowed_matrix", "rn:hydra:token<.*>"}, - Actions: []string{"create", "decide"}, - Effect: Allow, - }, - }, - "exact": { - kstorage.Policy{ - ID: "1", - Subjects: []string{"alice", "group1", "client"}, - Resources: []string{"matrix", "forbidden_matrix", "rn:hydra:token"}, - Actions: []string{"create", "decide"}, - Effect: Allow, - }, - kstorage.Policy{ - ID: "2", - Subjects: []string{"siri"}, - Resources: []string{""}, - Actions: []string{"decide"}, - Effect: Allow, - }, - kstorage.Policy{ - ID: "3", - Subjects: []string{"group1"}, - Resources: []string{"forbidden_matrix", "rn:hydra:token"}, - Actions: []string{"create", "decide"}, - Effect: Deny, - }, - kstorage.Policy{ - ID: "4", - Subjects: []string{"group1"}, - Resources: []string{"allowed_matrix", "rn:hydra:token"}, - Actions: []string{"create", "decide"}, - Effect: Allow, - }, - }, - } -) diff --git a/engine/ladon/handler_test.go b/engine/ladon/handler_test.go deleted file mode 100644 index 0a28cd346..000000000 --- a/engine/ladon/handler_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package ladon - -import ( - "fmt" - "net/http/httptest" - "net/url" - "testing" - - "github.com/ory/x/logrusx" - - "github.com/ory/keto/internal/httpclient/client" - "github.com/ory/keto/internal/httpclient/client/engines" - "github.com/ory/keto/internal/httpclient/models" - - "github.com/gobuffalo/packr" - "github.com/julienschmidt/httprouter" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/urfave/negroni" - - "github.com/ory/herodot" - - "github.com/ory/keto/engine" - kstorage "github.com/ory/keto/storage" -) - -func nc(t *testing.T, u string) *client.OryKeto { - uu, err := url.ParseRequestURI(u) - require.NoError(t, err) - - return client.NewHTTPClientWithConfig(nil, &client.TransportConfig{ - Host: uu.Host, - BasePath: uu.Path, - Schemes: []string{uu.Scheme}, - }) -} - -func TestAllowed(t *testing.T) { - box := packr.NewBox("./rego") - compiler, err := engine.NewCompiler(box, logrusx.New("", "")) - require.NoError(t, err) - - s := kstorage.NewMemoryManager() - sh := kstorage.NewHandler(s, herodot.NewJSONWriter(nil)) - e := engine.NewEngine(compiler, herodot.NewJSONWriter(nil)) - le := NewEngine(s, sh, e, herodot.NewJSONWriter(nil)) - - n := negroni.Classic() - r := httprouter.New() - le.Register(r) - n.UseHandler(r) - - ts := httptest.NewServer(n) - defer ts.Close() - - cl := nc(t, ts.URL) - for _, f := range EnabledFlavors { - t.Run(fmt.Sprintf("flavor=%s", f), func(t *testing.T) { - t.Run(fmt.Sprint("action=create"), func(t *testing.T) { - for _, p := range policies[f] { - t.Run(fmt.Sprintf("policy=%s", p.ID), func(t *testing.T) { - _, err := cl.Engines.UpsertOryAccessControlPolicy(engines.NewUpsertOryAccessControlPolicyParams().WithFlavor(f).WithBody(toSwaggerPolicy(p))) - require.NoError(t, err) - }) - } - for _, r := range roles[f] { - t.Run(fmt.Sprintf("role=%s", r.ID), func(t *testing.T) { - _, err := cl.Engines.UpsertOryAccessControlPolicyRole(engines.NewUpsertOryAccessControlPolicyRoleParams().WithFlavor(f).WithBody(toSwaggerRole(r))) - require.NoError(t, err) - }) - } - }) - - t.Run("action=authorize", func(t *testing.T) { - for k, c := range requests[f] { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - d, err := cl.Engines.DoOryAccessControlPoliciesAllow(engines.NewDoOryAccessControlPoliciesAllowParams().WithFlavor(f).WithBody(&c.req)) - if c.allowed { - require.NoError(t, err) - assert.Equal(t, c.allowed, *d.Payload.Allowed) - } else { - require.IsType(t, engines.NewDoOryAccessControlPoliciesAllowForbidden(), err) - assert.Equal(t, c.allowed, *(err.(*engines.DoOryAccessControlPoliciesAllowForbidden).Payload.Allowed)) - } - }) - } - }) - }) - } -} - -func TestValidatePolicy(t *testing.T) { - _, err := validatePolicy(kstorage.Policy{}) - require.Error(t, err) - - _, err = validatePolicy(kstorage.Policy{Effect: "bar"}) - require.Error(t, err) - - p, err := validatePolicy(kstorage.Policy{Effect: "allow"}) - require.NoError(t, err) - assert.NotEmpty(t, p.ID) - - p, err = validatePolicy(kstorage.Policy{Effect: "deny", ID: "foo"}) - require.NoError(t, err) - assert.Equal(t, "foo", p.ID) -} - -func crudts() *httptest.Server { - s := kstorage.NewMemoryManager() - sh := kstorage.NewHandler(s, herodot.NewJSONWriter(nil)) - e := NewEngine(s, sh, nil, herodot.NewJSONWriter(nil)) - r := httprouter.New() - e.Register(r) - return httptest.NewServer(r) -} - -func toSwaggerPolicy(p kstorage.Policy) *models.OryAccessControlPolicy { - return &models.OryAccessControlPolicy{ - Actions: p.Actions, - ID: p.ID, - Resources: p.Resources, - Subjects: p.Subjects, - Effect: p.Effect, - Conditions: p.Conditions, - Description: p.Description, - } -} - -func fromSwaggerPolicy(p models.OryAccessControlPolicy) kstorage.Policy { - conditions, ok := p.Conditions.(map[string]interface{}) - if !ok { - conditions = nil - } - return kstorage.Policy{ - Actions: p.Actions, - ID: p.ID, - Resources: p.Resources, - Subjects: p.Subjects, - Effect: p.Effect, - Conditions: conditions, - Description: p.Description, - } -} - -func toSwaggerRole(r kstorage.Role) *models.OryAccessControlPolicyRole { - return &models.OryAccessControlPolicyRole{ - Members: r.Members, - ID: r.ID, - Description: r.Description, - } -} - -func fromSwaggerRole(r models.OryAccessControlPolicyRole) kstorage.Role { - return kstorage.Role{ - Members: r.Members, - ID: r.ID, - Description: r.Description, - } -} - -func TestPolicyCRUD(t *testing.T) { - ts := crudts() - defer ts.Close() - - c := nc(t, ts.URL) - for _, f := range EnabledFlavors { - for l, p := range policies[f] { - _, err := c.Engines.GetOryAccessControlPolicy(engines.NewGetOryAccessControlPolicyParams().WithFlavor(f).WithID(p.ID)) - require.Error(t, err) - - _, err = c.Engines.UpsertOryAccessControlPolicy(engines.NewUpsertOryAccessControlPolicyParams().WithFlavor(f).WithBody(toSwaggerPolicy(p))) - require.NoError(t, err) - - o, err := c.Engines.GetOryAccessControlPolicy(engines.NewGetOryAccessControlPolicyParams().WithFlavor(f).WithID(p.ID)) - require.NoError(t, err) - assert.Equal(t, p, fromSwaggerPolicy(*o.Payload)) - - limit, offset := int64(100), int64(0) - os, err := c.Engines.ListOryAccessControlPolicies(engines.NewListOryAccessControlPoliciesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset)) - require.NoError(t, err) - - var ps kstorage.Policies - for _, v := range os.Payload { - ps = append(ps, fromSwaggerPolicy(*v)) - } - - assert.Equal(t, ps, policies[f][:l+1]) - - } - - // test action filter - { - limit, offset := int64(100), int64(0) - action := "create" - os1, err := c.Engines.ListOryAccessControlPolicies(engines.NewListOryAccessControlPoliciesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset).WithAction(&action)) - require.NoError(t, err) - - var ps kstorage.Policies - for _, v := range os1.Payload { - ps = append(ps, fromSwaggerPolicy(*v)) - } - - if len(policies[f]) > 0 { - assert.Equal(t, ps, kstorage.Policies{policies[f][0], policies[f][2], policies[f][3]}) - } - } - - // test subject filter - { - limit, offset := int64(100), int64(0) - subject := "siri" - os1, err := c.Engines.ListOryAccessControlPolicies(engines.NewListOryAccessControlPoliciesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset).WithSubject(&subject)) - require.NoError(t, err) - - var ps kstorage.Policies - for _, v := range os1.Payload { - ps = append(ps, fromSwaggerPolicy(*v)) - } - - if len(policies[f]) > 0 { - assert.Equal(t, ps, kstorage.Policies{policies[f][1]}) - } - } - - // test resource filter - { - limit, offset := int64(100), int64(0) - resource := "matrix" - os1, err := c.Engines.ListOryAccessControlPolicies(engines.NewListOryAccessControlPoliciesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset).WithResource(&resource)) - require.NoError(t, err) - - var ps kstorage.Policies - for _, v := range os1.Payload { - ps = append(ps, fromSwaggerPolicy(*v)) - } - - if len(policies[f]) > 0 { - assert.Equal(t, ps, kstorage.Policies{policies[f][0]}) - } - } - - // test combined filters - { - limit, offset := int64(100), int64(0) - subject := "group1" - action := "create" - resource := "forbidden_matrix" - os1, err := c.Engines.ListOryAccessControlPolicies(engines.NewListOryAccessControlPoliciesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset).WithAction(&action).WithResource(&resource).WithSubject(&subject)) - require.NoError(t, err) - - var ps kstorage.Policies - for _, v := range os1.Payload { - ps = append(ps, fromSwaggerPolicy(*v)) - } - - if len(policies[f]) > 0 { - assert.Equal(t, ps, kstorage.Policies{policies[f][0], policies[f][2]}) - } - } - - for _, p := range policies[f] { - _, err := c.Engines.DeleteOryAccessControlPolicy(engines.NewDeleteOryAccessControlPolicyParams().WithFlavor(f).WithID(p.ID)) - require.NoError(t, err) - - _, err = c.Engines.GetOryAccessControlPolicy(engines.NewGetOryAccessControlPolicyParams().WithFlavor(f).WithID(p.ID)) - require.Error(t, err) - } - } -} - -func TestRoleCRUD(t *testing.T) { - ts := crudts() - defer ts.Close() - - c := nc(t, ts.URL) - for _, f := range EnabledFlavors { - for l, r := range roles[f] { - _, err := c.Engines.GetOryAccessControlPolicyRole(engines.NewGetOryAccessControlPolicyRoleParams().WithFlavor(f).WithID(r.ID)) - require.Error(t, err) - - ou, err := c.Engines.UpsertOryAccessControlPolicyRole(engines.NewUpsertOryAccessControlPolicyRoleParams().WithFlavor(f).WithBody(toSwaggerRole(r))) - require.NoError(t, err) - require.EqualValues(t, r, fromSwaggerRole(*ou.Payload)) - - o, err := c.Engines.GetOryAccessControlPolicyRole(engines.NewGetOryAccessControlPolicyRoleParams().WithFlavor(f).WithID(r.ID)) - require.NoError(t, err) - require.EqualValues(t, r, fromSwaggerRole(*o.Payload)) - - limit, offset := int64(100), int64(0) - os, err := c.Engines.ListOryAccessControlPolicyRoles(engines.NewListOryAccessControlPolicyRolesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset)) - require.NoError(t, err) - - var ps kstorage.Roles - for _, v := range os.Payload { - ps = append(ps, fromSwaggerRole(*v)) - } - - assert.Equal(t, ps, roles[f][:l+1]) - } - - // Test member filter - { - limit, offset := int64(100), int64(0) - member := "ben" - os, err := c.Engines.ListOryAccessControlPolicyRoles(engines.NewListOryAccessControlPolicyRolesParams().WithFlavor(f).WithLimit(&limit).WithOffset(&offset).WithMember(&member)) - require.NoError(t, err) - - var ps kstorage.Roles - for _, v := range os.Payload { - ps = append(ps, fromSwaggerRole(*v)) - } - - if len(roles[f]) > 0 { - assert.Equal(t, ps, kstorage.Roles{roles[f][2]}) - } - } - - for _, r := range roles[f] { - _, err := c.Engines.DeleteOryAccessControlPolicyRole(engines.NewDeleteOryAccessControlPolicyRoleParams().WithFlavor(f).WithID(r.ID)) - require.NoError(t, err) - - _, err = c.Engines.GetOryAccessControlPolicyRole(engines.NewGetOryAccessControlPolicyRoleParams().WithFlavor(f).WithID(r.ID)) - require.Error(t, err) - } - } -} diff --git a/engine/ladon/rego/condition/boolean.rego b/engine/ladon/rego/condition/boolean.rego deleted file mode 100644 index eda8419c0..000000000 --- a/engine/ladon/rego/condition/boolean.rego +++ /dev/null @@ -1,19 +0,0 @@ -package ory.condition - -eval_condition("BooleanCondition", request, options, key) { - is_boolean(request.context[key], output) - output == true - - request.context[key] == options.value -} - -test_condition_boolean { - eval_condition("BooleanCondition", { "context": {"foobar": false } }, { "value": false }, "foobar") - eval_condition("BooleanCondition", { "context": {"foobar": true } }, { "value": true }, "foobar") - - not eval_condition("BooleanCondition", { "context": {"foobar": false } }, { "value": true }, "foobar") - not eval_condition("BooleanCondition", { "context": {"foobar": true } }, { "value": false }, "foobar") - not eval_condition("BooleanCondition", { "context": {"not-foobar": true } }, { "value": false }, "foobar") - not eval_condition("BooleanCondition", { "context": {"foobar": true } }, { "not-value": false }, "foobar") - not eval_condition("BooleanCondition", { "context": {"not-foobar": true } }, { "not-value": false }, "foobar") -} diff --git a/engine/ladon/rego/condition/cidr.rego b/engine/ladon/rego/condition/cidr.rego deleted file mode 100644 index ffce0d92c..000000000 --- a/engine/ladon/rego/condition/cidr.rego +++ /dev/null @@ -1,15 +0,0 @@ -package ory.condition - -eval_condition("CIDRCondition", request, options, key) { - net.cidr_overlap(options.cidr, request.context[key], output) - output == true -} - -test_condition_boolean { - eval_condition("CIDRCondition", { "context": {"foobar": "192.168.178.0" } }, { "cidr": "192.168.178.0/16" }, "foobar") - eval_condition("CIDRCondition", { "context": {"foobar": "192.168.178.1" } }, { "cidr": "192.168.178.0/16" }, "foobar") - - not eval_condition("CIDRCondition", { "context": {"foobar": "92.168.178.1" } }, { "cidr": "192.168.178.0/16" }, "foobar") - not eval_condition("CIDRCondition", { "context": {"foobar": "192.168.178.1" } }, { "cidr": "192.168.178.0/16" }, "foobar2") - not eval_condition("CIDRCondition", { "context": {"foobar2": "192.168.178.1" } }, { "cidr": "192.168.178.0/16" }, "foobar") -} diff --git a/engine/ladon/rego/condition/condition.rego b/engine/ladon/rego/condition/condition.rego deleted file mode 100644 index 92d52c51b..000000000 --- a/engine/ladon/rego/condition/condition.rego +++ /dev/null @@ -1,16 +0,0 @@ -package ory.condition - -all_conditions_true(policy) { - not any_condition_false(policy) -} - -any_condition_false(policy) { - c := policy.conditions[condition_key] - not condition_true(policy, c, condition_key) -} - -condition_true(policy, c, condition_key) { - eval_condition(c.type, input, c.options, condition_key) -} { - false -} diff --git a/engine/ladon/rego/condition/doc.go b/engine/ladon/rego/condition/doc.go deleted file mode 100644 index e71377ca3..000000000 --- a/engine/ladon/rego/condition/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package condition is placeholder package to force download this package when we run `go mod vendor` -package condition diff --git a/engine/ladon/rego/condition/helpers.rego b/engine/ladon/rego/condition/helpers.rego deleted file mode 100644 index 38e64e2ea..000000000 --- a/engine/ladon/rego/condition/helpers.rego +++ /dev/null @@ -1,8 +0,0 @@ -package ory.condition - -cast_string_empty(r, key) = value { - not r[key] - value := "" -}{ - cast_string(r[key], value) -} diff --git a/engine/ladon/rego/condition/resource_contains.rego b/engine/ladon/rego/condition/resource_contains.rego deleted file mode 100644 index 104264489..000000000 --- a/engine/ladon/rego/condition/resource_contains.rego +++ /dev/null @@ -1,36 +0,0 @@ -package ory.condition - -eval_condition("ResourceContainsCondition", request, options, key) { - value := cast_string_empty(options, "value") - delimiter := cast_string_empty(options, "delimiter") - - needle := concat("", [delimiter, value, delimiter]) - haystack := concat("", [delimiter, request.resource, delimiter]) - - contains(haystack, needle) == true -} - -test_condition_resource_contains { - not eval_condition("ResourceContainsCondition", { "resource": "foo:bar" }, { "delimiter": ":", "value": "foo:ba" }, "") - - eval_condition("ResourceContainsCondition", { "resource": "foo:bar" }, { "delimiter": ":", "value": "foo:bar" }, "") - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "delimiter": ":", "value": "foo:bar" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "delimiter": ":", "value": "foo:baz" }, "") - - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "delimiter": ":", "value": "bar:baz" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "delimiter": ":", "value": "foo:baz" }, "") - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "delimiter": ":", "value": "bar" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "baz:foo:baz" }, { "delimiter": ":", "value": "bar" }, "") - - eval_condition("ResourceContainsCondition", { "resource": "foo:bar" }, { "value": "foo:ba" }, "") - eval_condition("ResourceContainsCondition", { "resource": "foo:bar" }, { "value": "foo:bar" }, "") - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "value": "foo:bar" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "foo:baz" }, { "value": "foo:bar" }, "") - - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "value": "bar:baz" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "value": "foo:baz" }, "") - eval_condition("ResourceContainsCondition", { "resource": "foo:bar:baz" }, { "value": "bar" }, "") - not eval_condition("ResourceContainsCondition", { "resource": "baz:foo:baz" }, { "value": "bar" }, "") - - not eval_condition("ResourceContainsCondition", { "resource": "abc" }, { "value": "", "delimiter": ":" }, "") -} diff --git a/engine/ladon/rego/condition/string_equal.rego b/engine/ladon/rego/condition/string_equal.rego deleted file mode 100644 index 1f9dc5865..000000000 --- a/engine/ladon/rego/condition/string_equal.rego +++ /dev/null @@ -1,24 +0,0 @@ -package ory.condition - -eval_condition("StringEqualCondition", request, options, key) { - is_string(request.context[key], aok) - aok == true - - is_string(options.equals, bok) - bok == true - - cast_string(request.context[key], a) - cast_string(options.equals, b) - a == b -} - -test_condition_string_equal { - eval_condition("StringEqualCondition", { "context": {"foobar": "the-value-should-be-this" } }, { "equals": "the-value-should-be-this" }, "foobar") - - not eval_condition("StringEqualCondition", { "context": {"not-foobar": "the-value-should-be-this" } }, { "equals": "the-value-should-be-this" }, "foobar") - not eval_condition("StringEqualCondition", { "context": {"foobar": "the-value-should-be-this" } }, { "not-equals": "the-value-should-be-this" }, "foobar") - not eval_condition("StringEqualCondition", { "context": {"not-foobar": "the-value-should-be-this" } }, { "not-equals": "the-value-should-be-this" }, "foobar") - not eval_condition("StringEqualCondition", { "context": {"foobar": "the-value-should-be-this" } }, { "equals": "not-the-value-should-be-this" }, "foobar") - not eval_condition("StringEqualCondition", { "context": {"foobar": 1234 } }, { "equals": "not-the-value-should-be-this" }, "foobar") - not eval_condition("StringEqualCondition", { "context": {"foobar": "the-value-should-be-this" } }, { "equals": 1234 }, "foobar") -} diff --git a/engine/ladon/rego/condition/string_match.rego b/engine/ladon/rego/condition/string_match.rego deleted file mode 100644 index 78d901a4f..000000000 --- a/engine/ladon/rego/condition/string_match.rego +++ /dev/null @@ -1,13 +0,0 @@ -package ory.condition - -eval_condition("StringMatchCondition", request, options, key) { - re_match(options.matches, request.context[key]) == true -} - -test_condition_string_match { - eval_condition("StringMatchCondition", { "context": {"foobar": "abc"} }, { "matches": ".*" }, "foobar") - eval_condition("StringMatchCondition", { "context": {"foobar": "abc"} }, { "matches": "abc.*" }, "foobar") - - not eval_condition("StringMatchCondition", { "context": {"not-foobar": "abc" } }, { "matches": ".+" }, "foobar") - not eval_condition("StringMatchCondition", { "context": {"foobar": "abc" } }, { "matches": "abc.+" }, "foobar") -} diff --git a/engine/ladon/rego/condition/string_pairs_equal.rego b/engine/ladon/rego/condition/string_pairs_equal.rego deleted file mode 100644 index 555a0c570..000000000 --- a/engine/ladon/rego/condition/string_pairs_equal.rego +++ /dev/null @@ -1,32 +0,0 @@ -package ory.condition - -eval_condition("StringPairsEqualCondition", request, options, key) { - cast_array(request.context[key], context) - count(context, c) - c > 0 - - not any_not_string_pair(context) -} - -any_not_string_pair(v) { - cast_array(v[_], vv) - not is_string_pair(vv) -} - -is_string_pair(v) { - count(v, c) - c == 2 - v[0] == v[1] -} - -test_condition_string_pairs_eqal { - not eval_condition("StringPairsEqualCondition", { "context": { } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [] } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [[]] } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1"]] } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1", "2"]] } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1", "1", "2"]] } }, {}, "foobar") - not eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1", "1"], ["2", "3"]] } }, {}, "foobar") - eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1", "1"], ["2", "2"]] } }, {}, "foobar") - eval_condition("StringPairsEqualCondition", { "context": { "foobar": [["1", "1"]] } }, {}, "foobar") -} diff --git a/engine/ladon/rego/condition/string_subject_equal.rego b/engine/ladon/rego/condition/string_subject_equal.rego deleted file mode 100644 index f0a51d0bd..000000000 --- a/engine/ladon/rego/condition/string_subject_equal.rego +++ /dev/null @@ -1,11 +0,0 @@ -package ory.condition - -eval_condition("EqualsSubjectCondition", request, options, key) { - request.context[key] == request.subject -} - -test_condition_equals_subject { - eval_condition("EqualsSubjectCondition", { "subject": "some-subject", "context": { "foobar": "some-subject" } }, {}, "foobar") - not eval_condition("EqualsSubjectCondition", { "subject": "some-subject", "context": { "foobar": "not-some-subject" } }, {}, "foobar") - not eval_condition("EqualsSubjectCondition", { "subject": "some-subject", "context": { "not-foobar": "some-subject" } }, {}, "foobar") -} diff --git a/engine/ladon/rego/core/doc.go b/engine/ladon/rego/core/doc.go deleted file mode 100644 index 7d043fefb..000000000 --- a/engine/ladon/rego/core/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package core is placeholder package to force download this package when we run `go mod vendor` -package core diff --git a/engine/ladon/rego/core/effect.rego b/engine/ladon/rego/core/effect.rego deleted file mode 100644 index 8462c3926..000000000 --- a/engine/ladon/rego/core/effect.rego +++ /dev/null @@ -1,10 +0,0 @@ -package ory.core - -effect_allow(effects) { - effects[_] == "allow" - not any_effect_deny(effects) -} - -any_effect_deny(effects) { - effects[_] == "deny" -} diff --git a/engine/ladon/rego/core/role.rego b/engine/ladon/rego/core/role.rego deleted file mode 100644 index 49d7dd4e8..000000000 --- a/engine/ladon/rego/core/role.rego +++ /dev/null @@ -1,7 +0,0 @@ -package ory.core - -role_ids(roles, subject) = r { - r := [role | role := roles[i].id - roles[i].members[_] == subject - ] -} diff --git a/engine/ladon/rego/doc.go b/engine/ladon/rego/doc.go deleted file mode 100644 index 5798c6466..000000000 --- a/engine/ladon/rego/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Package rego is a placeholder package to force download this package and its subpackages when we run `go mod vendor` -package rego - -import ( - _ "github.com/ory/keto/engine/ladon/rego/condition" - _ "github.com/ory/keto/engine/ladon/rego/core" - _ "github.com/ory/keto/engine/ladon/rego/exact" - _ "github.com/ory/keto/engine/ladon/rego/glob" - _ "github.com/ory/keto/engine/ladon/rego/regex" -) diff --git a/engine/ladon/rego/exact/doc.go b/engine/ladon/rego/exact/doc.go deleted file mode 100644 index 7fe1640a8..000000000 --- a/engine/ladon/rego/exact/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package exact is placeholder package to force download this package when we run `go mod vendor` -package exact diff --git a/engine/ladon/rego/exact/main.rego b/engine/ladon/rego/exact/main.rego deleted file mode 100644 index f39b593a2..000000000 --- a/engine/ladon/rego/exact/main.rego +++ /dev/null @@ -1,33 +0,0 @@ -package ory.exact - -import data.store.ory.exact as store -import data.ory.core as core -import data.ory.condition as condition -import input as request - -default allow = false - -allow { - decide_allow(store.policies, store.roles) -} - -decide_allow(policies, roles) { - effects := [effect | effect := policies[i].effect - policies[i].resources[_] == request.resource - match_subjects(policies[i].subjects, roles, request.subject) - policies[i].actions[_] == request.action - condition.all_conditions_true(policies[i]) - ] - - count(effects, c) - c > 0 - - core.effect_allow(effects) -} - -match_subjects(matches, roles, subject) { - matches[_] == subject -} { - r := core.role_ids(roles, subject) - matches[_] == r[_] -} diff --git a/engine/ladon/rego/exact/main_test.rego b/engine/ladon/rego/exact/main_test.rego deleted file mode 100644 index e9b37c6f0..000000000 --- a/engine/ladon/rego/exact/main_test.rego +++ /dev/null @@ -1,107 +0,0 @@ -package ory.exact - -policies = [ - { - "id": "1", - "resources": [`articles:1`], - "subjects": [`subjects:1`], - "actions": [`actions:1`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "StringEqualCondition", - "options": { - "equals": "the-value-should-be-this" - } - } - } - }, - { - "id": "2", - "resources": [`articles:2`], - "subjects": [`subjects:2`], - "actions": [`actions:2`], - "effect": "deny", - }, - { - "id": "3-1", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, - { - "id": "3-2", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "deny", - }, - { - "id": "3-3", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, - { - "id": "4", - "resources": [`articles:4`], - "subjects": [`subjects:4`], - "actions": [`actions:4`], - "effect": "allow", - }, - { - "id": "5", - "resources": [`articles:5`], - "subjects": [`subjects:5`], - "actions": [`actions:5`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "InvalidCondition" - } - } - }, - { - "id": "6", - "resources": [`articles:6`], - "subjects": [`subjects:6`, `roles:6`], - "actions": [`actions:6`], - "effect": "allow", - }, -] - -test_allow_policy { - decide_allow(policies, []) with input as {"resource": "articles:4", "subject": "subjects:4", "action": "actions:4"} -} - -test_allow_policy_role { - decide_allow(policies, []) with input as {"resource": "articles:6", "subject": "subjects:6", "action": "actions:6"} - decide_allow(policies, [{"id": "roles:6", "members": ["other-role", "role-subject"]}]) with input as {"resource": "articles:6", "subject": "role-subject", "action": "actions:6"} -} - -test_deny_policy { - not decide_allow(policies, []) with input as {"resource": "articles:2", "subject": "subjects:2", "action": "actions:2"} -} - -test_deny_overrides { - not decide_allow(policies, []) with input as {"resource": "articles:3", "subject": "subjects:3", "action": "actions:3"} -} - -test_deny_without_match { - not decide_allow(policies, []) with input as {"resource": "unknown", "subject": "unknown", "action": "unknown", "context": {"unknown": "unknown"}} -} - -test_with_condition { - decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "not-the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"not-foobar": "the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": 1234}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1"} -} - -test_with_unknown_condition { - not decide_allow(policies, []) with input as {"resource": "articles:5", "subject": "subjects:5", "action": "actions:5", "context": {"foobar": {}}} -} diff --git a/engine/ladon/rego/glob/doc.go b/engine/ladon/rego/glob/doc.go deleted file mode 100644 index 9ba170b6c..000000000 --- a/engine/ladon/rego/glob/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package exact is placeholder package to force download this package when we run `go mod vendor` -package glob diff --git a/engine/ladon/rego/glob/main.rego b/engine/ladon/rego/glob/main.rego deleted file mode 100644 index 702a14299..000000000 --- a/engine/ladon/rego/glob/main.rego +++ /dev/null @@ -1,40 +0,0 @@ -package ory.glob - -import data.store.ory.glob as store -import data.ory.core as core -import data.ory.condition as condition -import input as request - -default allow = false - -allow { - decide_allow(store.policies, store.roles) -} - -decide_allow(policies, roles) { - effects := [effect | effect := policies[i].effect - matcher(policies[i].resources, request.resource) - match_subjects(policies[i].subjects, roles, request.subject) - matcher(policies[i].actions, request.action) - condition.all_conditions_true(policies[i]) - ] - - count(effects, c) - c > 0 - - core.effect_allow(effects) -} - -matcher(patterns, compare) { - pattern := patterns[_] - glob.match(pattern, [":"], compare, output) - output == true -} - -match_subjects(matches, roles, subject) { - matcher(matches, subject) -} { - r := core.role_ids(roles, subject) - rr := r[_] - matcher(matches, rr) -} diff --git a/engine/ladon/rego/glob/main_test.rego b/engine/ladon/rego/glob/main_test.rego deleted file mode 100644 index f9bea7327..000000000 --- a/engine/ladon/rego/glob/main_test.rego +++ /dev/null @@ -1,223 +0,0 @@ -package ory.glob - -simple_policy = { - "id": "4", - "resources": [`articles:4`], - "subjects": [`subjects:4`], - "actions": [`actions:4`], - "effect": "allow", -} - -test_allow_policy { - decide_allow([simple_policy], []) with input as {"resource": "articles:4", "subject": "subjects:4", "action": "actions:4"} -} - -test_policy_must_match_resource_subject_and_action { - not decide_allow([simple_policy], []) with input as {"resource": "articles:5", "subject": "subjects:4", "action": "actions:4"} - not decide_allow([simple_policy], []) with input as {"resource": "articles:4", "subject": "subjects:5", "action": "actions:4"} - not decide_allow([simple_policy], []) with input as {"resource": "articles:4", "subject": "subjects:4", "action": "actions:5"} -} - -invalid_condition_policy = { - "id": "5", - "resources": [`articles:5`], - "subjects": [`subjects:5`], - "actions": [`actions:5`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "InvalidCondition" - } - } -} - -test_invalid_condition_policy { - not decide_allow(invalid_condition_policy, []) with input as {"resource": "articles:5", "subject": "subjects:5", "action": "actions:5"} -} - -group_policy = { - "id": "6", - "resources": [`articles:6`], - "subjects": [`{subjects,groups}:6`], - "actions": [`actions:6`], - "effect": "allow" -} - -test_allow_group_policy { - decide_allow([group_policy], []) with input as {"resource": "articles:6", "subject": "subjects:6", "action": "actions:6"} - decide_allow([group_policy], []) with input as {"resource": "articles:6", "subject": "groups:6", "action": "actions:6"} - - decide_allow([group_policy], [{"id": "groups:6", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "group-subject", "action": "actions:6"} - - not decide_allow([group_policy], [{"id": "groups:6", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "not-group-subject", "action": "actions:6"} - not decide_allow([group_policy], [{"id": "not-groups", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "group-subject", "action": "actions:6"} -} - -deny_policies = [ - { - "id": "2", - "resources": [`articles:2`], - "subjects": [`subjects:2`], - "actions": [`actions:2`], - "effect": "deny", - }, - { - "id": "3-1", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, - { - "id": "3-2", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "deny", - }, - { - "id": "3-3", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, -] - -test_deny_policy { - not decide_allow(deny_policies, []) with input as {"resource": "articles:2", "subject": "subjects:2", "action": "actions:2"} -} - -test_deny_overrides { - not decide_allow(deny_policies, []) with input as {"resource": "articles:3", "subject": "subjects:3", "action": "actions:3"} -} - -test_deny_without_match { - not decide_allow(deny_policies, []) with input as {"resource": "unknown", "subject": "unknown", "action": "unknown", "context": {"unknown": "unknown"}} -} - -condition_policy = { - "id": "1", - "resources": [`articles:1`], - "subjects": [`subjects:1`], - "actions": [`actions:1`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "StringEqualCondition", - "options": { - "equals": "the-value-should-be-this" - } - } - } -} - -test_with_condition { - decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "the-value-should-be-this"}} - not decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "not-the-value-should-be-this"}} - not decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"not-foobar": "the-value-should-be-this"}} - not decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": 1234}} - not decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {}} - not decide_allow([condition_policy], []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1"} -} - -test_with_unknown_condition { - not decide_allow([condition_policy], []) with input as {"resource": "articles:5", "subject": "subjects:5", "action": "actions:5", "context": {"foobar": {}}} -} - -wildcard_policy = { - "id": "7", - # Allows single character - "resources": [`articles:?:7`], - # Allows any number of characters - "subjects": [`subjects:*:7`], - # Allows any number of characters spanning delimiters - "actions": [`actions:**:7`], - "effect": "allow" -} - -test_allow_wildcards_single_char { - decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:7", "action": "actions:a:7"} -} - -test_question_mark_exactly_one_character { - not decide_allow([wildcard_policy], []) with input as {"resource": "articles::7", "subject": "subjects:a:7", "action": "actions:a:7"} - not decide_allow([wildcard_policy], []) with input as {"resource": "articles:ab:7", "subject": "subjects:a:7", "action": "actions:a:7"} -} - -test_star_respects_delimiters { - decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:ab:7", "action": "actions:a:7"} - not decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:7", "action": "actions:a:7"} - not decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:b:7", "action": "actions:a:7"} -} - -test_allow_star_star_with_delimiters { - decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:7", "action": "actions:ab:7"} - decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:7", "action": "actions:a:b:7"} - decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:7", "action": "actions:7"} -} - -test_star_star_requires_a_delimiter { - not decide_allow([wildcard_policy], []) with input as {"resource": "articles:a:7", "subject": "subjects:a:7", "action": "actions7"} -} - -list_policy = { - "id": "8", - # Character list (bat or cat) - "resources": [`articles:[cb]at:8`], - # Ranged character list (aat, bat, cat) - "subjects": [`subjects:[a-c]at:8`], - # Negated character lists and ranges - "actions": [`actions:[!cb]a[!x-z]:8`], - "effect": "allow" -} - -test_allow_lists { - decide_allow([list_policy], []) with input as {"resource": "articles:cat:8", "subject": "subjects:cat:8", "action": "actions:tat:8"} - decide_allow([list_policy], []) with input as {"resource": "articles:bat:8", "subject": "subjects:bat:8", "action": "actions:dad:8"} -} - -test_allow_character_list { - not decide_allow([list_policy], []) with input as {"resource": "articles:dat:8", "subject": "subjects:cat:8", "action": "actions:tat:8"} - not decide_allow([list_policy], []) with input as {"resource": "articles:cay:8", "subject": "subjects:cat:8", "action": "actions:tat:8"} -} - -test_allow_character_ranges { - not decide_allow([list_policy], []) with input as {"resource": "articles:cat:8", "subject": "subjects:dat:8", "action": "actions:tat:8"} -} - -test_allow_negated_lists { - not decide_allow([list_policy], []) with input as {"resource": "articles:cat:8", "subject": "subjects:cat:8", "action": "actions:cat:8"} - not decide_allow([list_policy], []) with input as {"resource": "articles:cat:8", "subject": "subjects:cat:8", "action": "actions:tay:8"} -} - -# Various combinations to guard against interaction effects -combination_policy = { - "id": "9", - "resources": [`articles:foo**{bar,baz}:9`], - "subjects": [`subjects:{?at,d*g}:9`], - "actions": [`actions:{[cbm]at,d[!j-n]g}:9`], - "effect": "allow" -} - -test_allow_valid_combinations { - decide_allow([combination_policy], []) with input as {"resource": "articles:foobar:9", "subject": "subjects:cat:9", "action": "actions:cat:9"} - decide_allow([combination_policy], []) with input as {"resource": "articles:foobarbaz:9", "subject": "subjects:doooog:9", "action": "actions:dig:9"} - decide_allow([combination_policy], []) with input as {"resource": "articles:foo:bar::quux:baz:9", "subject": "subjects:dg:9", "action": "actions:dig:9"} -} - -test_allow_combinations_star_star_preserves_surrounding_context { - not decide_allow([combination_policy], []) with input as {"resource": "articles:foo:9", "subject": "subjects:cat:9", "action": "actions:cat:9"} -} -test_allow_combinations_no_extra_chars { - not decide_allow([combination_policy], []) with input as {"resource": "articles:foobard:9", "subject": "subjects:cat:9", "action": "actions:cat:9"} - not decide_allow([combination_policy], []) with input as {"resource": "articles:foobar:9", "subject": "subjects:cat:9", "action": "actions:doog:9"} -} -test_allow_combinations_no_missing_chars { - not decide_allow([combination_policy], []) with input as {"resource": "articles:foobar:9", "subject": "subjects:at:9", "action": "actions:cat:9"} -} - -test_allow_combinations_exactly_one_alternative { - not decide_allow([combination_policy], []) with input as {"resource": "articles:foobar:9", "subject": "subjects:catdog:9", "action": "actions:cat:9"} - not decide_allow([combination_policy], []) with input as {"resource": "articles:foobar:9", "subject": "subjects:cat:9", "action": "actions:catdog:9"} -} diff --git a/engine/ladon/rego/regex/doc.go b/engine/ladon/rego/regex/doc.go deleted file mode 100644 index d5a33dc58..000000000 --- a/engine/ladon/rego/regex/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package regex is placeholder package to force download this package when we run `go mod vendor` -package regex diff --git a/engine/ladon/rego/regex/main.rego b/engine/ladon/rego/regex/main.rego deleted file mode 100644 index 3d2a03ffe..000000000 --- a/engine/ladon/rego/regex/main.rego +++ /dev/null @@ -1,40 +0,0 @@ -package ory.regex - -import data.store.ory.regex as store -import data.ory.core as core -import data.ory.condition as condition -import input as request - -default allow = false - -allow { - decide_allow(store.policies, store.roles) -} - -decide_allow(policies, roles) { - effects := [effect | effect := policies[i].effect - matcher(policies[i].resources, request.resource) - match_subjects(policies[i].subjects, roles, request.subject) - matcher(policies[i].actions, request.action) - condition.all_conditions_true(policies[i]) - ] - - count(effects, c) - c > 0 - - core.effect_allow(effects) -} - -matcher(patterns, compare) { - pattern := patterns[_] - regex.template_match(pattern, compare, "<", ">", output) - output == true -} - -match_subjects(matches, roles, subject) { - matcher(matches, subject) -} { - r := core.role_ids(roles, subject) - rr := r[_] - matcher(matches, rr) -} diff --git a/engine/ladon/rego/regex/main_test.rego b/engine/ladon/rego/regex/main_test.rego deleted file mode 100644 index e0245a505..000000000 --- a/engine/ladon/rego/regex/main_test.rego +++ /dev/null @@ -1,114 +0,0 @@ -package ory.regex - -policies = [ - { - "id": "1", - "resources": [`articles:1`], - "subjects": [`subjects:1`], - "actions": [`actions:1`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "StringEqualCondition", - "options": { - "equals": "the-value-should-be-this" - } - } - } - }, - { - "id": "2", - "resources": [`articles:2`], - "subjects": [`subjects:2`], - "actions": [`actions:2`], - "effect": "deny", - }, - { - "id": "3-1", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, - { - "id": "3-2", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "deny", - }, - { - "id": "3-3", - "resources": [`articles:3`], - "subjects": [`subjects:3`], - "actions": [`actions:3`], - "effect": "allow", - }, - { - "id": "4", - "resources": [`articles:<4|44>`], - "subjects": [`subjects:<4|44>`], - "actions": [`actions:<4|44>`], - "effect": "allow", - }, - { - "id": "5", - "resources": [`articles:5`], - "subjects": [`subjects:5`], - "actions": [`actions:5`], - "effect": "allow", - "conditions": { - "foobar": { - "type": "InvalidCondition" - } - } - }, - { - "id": "6", - "resources": [`articles:6`], - "subjects": [`:6`], - "actions": [`actions:6`], - "effect": "allow" - }, -] - -test_allow_policy { - decide_allow(policies, []) with input as {"resource": "articles:4", "subject": "subjects:4", "action": "actions:4"} - decide_allow(policies, []) with input as {"resource": "articles:44", "subject": "subjects:44", "action": "actions:44"} - not decide_allow(policies, []) with input as {"resource": "articles:454", "subject": "subjects:454", "action": "actions:454"} -} - -test_allow_group_policy { - decide_allow(policies, []) with input as {"resource": "articles:6", "subject": "subjects:6", "action": "actions:6"} - decide_allow(policies, []) with input as {"resource": "articles:6", "subject": "groups:6", "action": "actions:6"} - - decide_allow(policies, [{"id": "groups:6", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "group-subject", "action": "actions:6"} - - not decide_allow(policies, [{"id": "groups:6", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "not-group-subject", "action": "actions:6"} - not decide_allow(policies, [{"id": "not-groups", "members": ["group-subject"]}]) with input as {"resource": "articles:6", "subject": "group-subject", "action": "actions:6"} -} - -test_deny_policy { - not decide_allow(policies, []) with input as {"resource": "articles:2", "subject": "subjects:2", "action": "actions:2"} -} - -test_deny_overrides { - not decide_allow(policies, []) with input as {"resource": "articles:3", "subject": "subjects:3", "action": "actions:3"} -} - -test_deny_without_match { - not decide_allow(policies, []) with input as {"resource": "unknown", "subject": "unknown", "action": "unknown", "context": {"unknown": "unknown"}} -} - -test_with_condition { - decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": "not-the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"not-foobar": "the-value-should-be-this"}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {"foobar": 1234}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1", "context": {}} - not decide_allow(policies, []) with input as {"resource": "articles:1", "subject": "subjects:1", "action": "actions:1"} -} - -test_with_unknown_condition { - not decide_allow(policies, []) with input as {"resource": "articles:5", "subject": "subjects:5", "action": "actions:5", "context": {"foobar": {}}} -} diff --git a/engine/ladon/types.go b/engine/ladon/types.go deleted file mode 100644 index d44c01bcc..000000000 --- a/engine/ladon/types.go +++ /dev/null @@ -1,25 +0,0 @@ -package ladon - -type Context map[string]interface{} - -const ( - Allow = "allow" - Deny = "deny" -) - -// Input for checking if a request is allowed or not. -// -// swagger:ignore -type Input struct { - // Resource is the resource that access is requested to. - Resource string `json:"resource"` - - // Action is the action that is requested on the resource. - Action string `json:"action"` - - // Subject is the subject that is requesting access. - Subject string `json:"subject"` - - // Context is the request's environmental context. - Context map[string]interface{} `json:"context"` -} diff --git a/engine/registry.go b/engine/registry.go deleted file mode 100644 index effb1bf79..000000000 --- a/engine/registry.go +++ /dev/null @@ -1,5 +0,0 @@ -package engine - -type Registry interface { - Engine() *Engine -} diff --git a/go_mod_indirect_pins.go b/go_mod_indirect_pins.go index aea11c506..10920b600 100644 --- a/go_mod_indirect_pins.go +++ b/go_mod_indirect_pins.go @@ -13,7 +13,7 @@ import ( // FIXME See https://github.com/gobuffalo/buffalo/pull/1999 _ "github.com/gorilla/websocket" - _ "github.com/ory/go-acc" _ "github.com/ory/cli" + _ "github.com/ory/go-acc" _ "github.com/ory/x/tools/listx" ) diff --git a/persistence/definitions.go b/persistence/definitions.go new file mode 100644 index 000000000..a163c20a5 --- /dev/null +++ b/persistence/definitions.go @@ -0,0 +1,3 @@ +package persistence + +type Persister interface{} diff --git a/storage/filter_helper_test.go b/storage/filter_helper_test.go deleted file mode 100644 index e8b9ff30d..000000000 --- a/storage/filter_helper_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package storage - -var ( - rolReq = Roles{ - { - ID: "role1", - Members: []string{"mem1"}, - }, - { - ID: "role2", - Members: []string{"mem1", "mem2"}, - }, - } - polReq = Policies{ - { - ID: "policy1", - Actions: []string{"create"}, - Subjects: []string{"mem1", "mem2"}, - Resources: []string{"res1", "res2"}, - }, - { - ID: "policy2", - Actions: []string{"create"}, - Subjects: []string{"mem3", "mem4"}, - Resources: []string{"res1", "res2"}, - }, - } - paramsReq = []map[string][]string{ - {"member": {"mem1"}}, - {"member": {"mem2"}}, - {"member": {"mem3"}}, - {"action": {"create"}}, - {"subject": {"mem3"}}, - {"action": {"create"}, "subject": {"mem3"}, "resource": {"res2"}}, - {"action": {"create"}, "subject": {"mem3"}, "resource": {"res3"}}, - {"action": {"delete"}}, - } - rolRes = []Roles{ - Roles{ - { - ID: "role1", - Members: []string{"mem1"}, - }, - { - ID: "role2", - Members: []string{"mem1", "mem2"}, - }, - }, - Roles{ - { - ID: "role2", - Members: []string{"mem1", "mem2"}, - }, - }, - Roles{}, - rolReq, - rolReq, - rolReq, - rolReq, - rolReq, - } - polRes = []Policies{ - polReq, - polReq, - polReq, - Policies{ - { - ID: "policy1", - Actions: []string{"create"}, - Subjects: []string{"mem1", "mem2"}, - Resources: []string{"res1", "res2"}, - }, - { - ID: "policy2", - Actions: []string{"create"}, - Subjects: []string{"mem3", "mem4"}, - Resources: []string{"res1", "res2"}, - }, - }, - Policies{ - { - ID: "policy2", - Actions: []string{"create"}, - Subjects: []string{"mem3", "mem4"}, - Resources: []string{"res1", "res2"}, - }, - }, - Policies{ - { - ID: "policy2", - Actions: []string{"create"}, - Subjects: []string{"mem3", "mem4"}, - Resources: []string{"res1", "res2"}, - }, - }, - Policies{}, - Policies{}, - } -) diff --git a/storage/filter_test.go b/storage/filter_test.go deleted file mode 100644 index ec5205105..000000000 --- a/storage/filter_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package storage - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestListRequest_Filter(t *testing.T) { - for i := range paramsReq { - t.Run(fmt.Sprintf("Filter Policies: case=%s", paramsReq[i]), func(t *testing.T) { - l := ListRequest{ - Collection: "filter_test", - Value: &polReq, - FilterFunc: ListByQuery, - } - assert.Equal(t, &polRes[i], l.Filter(paramsReq[i]).Value) - }) - - t.Run(fmt.Sprintf("Filter Roles: case=%s", paramsReq[i]), func(t *testing.T) { - l := ListRequest{ - Collection: "filter_test", - Value: &rolReq, - FilterFunc: ListByQuery, - } - assert.Equal(t, &rolRes[i], l.Filter(paramsReq[i]).Value) - }) - } -} diff --git a/storage/handler.go b/storage/handler.go deleted file mode 100644 index 6f3dc10c1..000000000 --- a/storage/handler.go +++ /dev/null @@ -1,152 +0,0 @@ -package storage - -import ( - "context" - "net/http" - - "github.com/julienschmidt/httprouter" - - "github.com/ory/herodot" - "github.com/ory/x/pagination" -) - -type Handler struct { - s Manager - h herodot.Writer -} - -func NewHandler(s Manager, h herodot.Writer) *Handler { - return &Handler{ - s: s, - h: h, - } -} - -type GetRequest struct { - Collection string - Key string - Value interface{} -} - -func (h *Handler) Get(factory func(context.Context, *http.Request, httprouter.Params) (*GetRequest, error)) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ctx := r.Context() - d, err := factory(ctx, r, ps) - if err != nil { - h.h.WriteError(w, r, err) - return - } - - if err := h.s.Get(ctx, d.Collection, d.Key, d.Value); err != nil { - h.h.WriteError(w, r, err) - return - } - - h.h.Write(w, r, d.Value) - } -} - -type DeleteRequest struct { - Collection string - Key string -} - -func (h *Handler) Delete(factory func(context.Context, *http.Request, httprouter.Params) (*DeleteRequest, error)) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ctx := r.Context() - d, err := factory(ctx, r, ps) - if err != nil { - h.h.WriteError(w, r, err) - return - } - - if err := h.s.Delete(ctx, d.Collection, d.Key); err != nil { - h.h.WriteError(w, r, err) - return - } - - w.WriteHeader(http.StatusNoContent) - } -} - -type ListRequest struct { - Collection string - Value interface{} - FilterFunc func(*ListRequest, map[string][]string) -} - -func (l *ListRequest) Filter(m map[string][]string) *ListRequest { - if l.FilterFunc != nil { - l.FilterFunc(l, m) - } - return l -} - -func ListByQuery(l *ListRequest, m map[string][]string) { - switch val := l.Value.(type) { - case *Roles: - res := make(Roles, 0) - for _, role := range *val { - filteredRole := role.withMembers(m["member"]).withIDs(m["id"]) - if filteredRole != nil { - res = append(res, *filteredRole) - } - } - l.Value = &res - case *Policies: - res := make(Policies, 0) - for _, policy := range *val { - filteredPolicy := policy.withSubjects(m["subject"]).withResources(m["resource"]).withActions(m["action"]).withIDs(m["id"]) - if filteredPolicy != nil { - res = append(res, *filteredPolicy) - } - } - l.Value = &res - default: - panic("storage:unable to cast list request to a known type!") - } -} - -func (h *Handler) List(factory func(context.Context, *http.Request, httprouter.Params) (*ListRequest, error)) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ctx := r.Context() - l, err := factory(ctx, r, ps) - if err != nil { - h.h.WriteError(w, r, err) - return - } - limit, offset := pagination.Parse(r, 100, 0, 500) - - if err := h.s.List(ctx, l.Collection, l.Value, limit, offset); err != nil { - h.h.WriteError(w, r, err) - return - } - - m := r.URL.Query() - h.h.Write(w, r, l.Filter(m).Value) - } -} - -type UpsertRequest struct { - Collection string - Key string - Value interface{} -} - -func (h *Handler) Upsert(factory func(context.Context, *http.Request, httprouter.Params) (*UpsertRequest, error)) httprouter.Handle { - return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { - ctx := r.Context() - u, err := factory(ctx, r, ps) - if err != nil { - h.h.WriteError(w, r, err) - return - } - - if err := h.s.Upsert(ctx, u.Collection, u.Key, u.Value); err != nil { - h.h.WriteError(w, r, err) - return - } - - h.h.Write(w, r, u.Value) - } -} diff --git a/storage/handler_test.go b/storage/handler_test.go deleted file mode 100644 index c510d1465..000000000 --- a/storage/handler_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package storage - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "testing" - - "github.com/julienschmidt/httprouter" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ory/herodot" -) - -func TestCRUD(t *testing.T) { - for k, m := range map[string]Manager{ - "memory": NewMemoryManager(), - } { - t.Run(fmt.Sprintf("manager=%s", k), func(t *testing.T) { - h := NewHandler(m, herodot.NewJSONWriter(nil)) - i := &mockHandler{c: "tests", sh: h} - r := httprouter.New() - i.Register(r) - ts := httptest.NewServer(r) - defer ts.Close() - - t.Run("case=404", func(t *testing.T) { - res, err := ts.Client().Get(ts.URL + "/1234") - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, http.StatusNotFound, res.StatusCode) - }) - - t.Run("case=create", func(t *testing.T) { - res, err := ts.Client().Post(ts.URL+"/?key=1234&value=bar", "application/json", bytes.NewBuffer(nil)) - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, http.StatusOK, res.StatusCode) - }) - - t.Run("case=get", func(t *testing.T) { - res, err := ts.Client().Get(ts.URL + "/1234") - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - b, err := ioutil.ReadAll(res.Body) - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, `"bar"`, string(b)) - }) - - t.Run("case=list", func(t *testing.T) { - res, err := ts.Client().Get(ts.URL + "/") - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - b, err := ioutil.ReadAll(res.Body) - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, `["bar"]`, string(b)) - }) - - t.Run("case=delete", func(t *testing.T) { - req, err := http.NewRequest("DELETE", ts.URL+"/1234", nil) - require.NoError(t, err) - res, err := ts.Client().Do(req) - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, http.StatusNoContent, res.StatusCode) - }) - - t.Run("case=list", func(t *testing.T) { - res, err := ts.Client().Get(ts.URL + "/") - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - b, err := ioutil.ReadAll(res.Body) - require.NoError(t, err) - res.Body.Close() - assert.Equal(t, `[]`, string(b)) - }) - - }) - } -} - -type mockHandler struct { - c string - sh *Handler -} - -func (e *mockHandler) Register(r *httprouter.Router) { - r.POST("/", e.sh.Upsert(e.create)) - r.GET("/", e.sh.List(e.list)) - r.GET("/:id", e.sh.Get(e.get)) - r.DELETE("/:id", e.sh.Delete(e.delete)) -} - -func (e *mockHandler) create(ctx context.Context, r *http.Request, ps httprouter.Params) (*UpsertRequest, error) { - return &UpsertRequest{ - Collection: e.c, - Key: r.URL.Query().Get("key"), - Value: r.URL.Query().Get("value"), - }, nil -} - -func (e *mockHandler) list(ctx context.Context, r *http.Request, ps httprouter.Params) (*ListRequest, error) { - var p []string - return &ListRequest{ - Collection: e.c, - Value: &p, - }, nil -} - -func (e *mockHandler) delete(ctx context.Context, r *http.Request, ps httprouter.Params) (*DeleteRequest, error) { - return &DeleteRequest{ - Collection: e.c, - Key: ps.ByName("id"), - }, nil -} - -func (e *mockHandler) get(ctx context.Context, r *http.Request, ps httprouter.Params) (*GetRequest, error) { - var p string - return &GetRequest{ - Collection: e.c, - Key: ps.ByName("id"), - Value: &p, - }, nil -} diff --git a/storage/manager.go b/storage/manager.go deleted file mode 100644 index 0fe498ed8..000000000 --- a/storage/manager.go +++ /dev/null @@ -1,84 +0,0 @@ -package storage - -import ( - "bytes" - "context" - "encoding/json" - - "github.com/open-policy-agent/opa/storage" - "github.com/open-policy-agent/opa/storage/inmem" - "github.com/pkg/errors" -) - -type Manager interface { - Get(ctx context.Context, collection string, key string, value interface{}) error - List(ctx context.Context, collection string, value interface{}, limit, offset int) error - Upsert(ctx context.Context, collection string, key string, value interface{}) error - Delete(ctx context.Context, collection string, key string) error - Storage(ctx context.Context, schema string, collections []string) (storage.Store, error) -} - -func roundTrip(in, out interface{}) error { - var b bytes.Buffer - - if err := json.NewEncoder(&b).Encode(in); err != nil { - return errors.WithStack(err) - } - - dec := json.NewDecoder(&b) - dec.DisallowUnknownFields() - if err := dec.Decode(out); err != nil { - return errors.WithStack(err) - } - - return nil -} - -func toRegoStore(ctx context.Context, schema string, collections []string, query func(context.Context, string) ([]json.RawMessage, error)) (storage.Store, error) { - var s map[string]interface{} - dec := json.NewDecoder(bytes.NewBufferString(schema)) - dec.UseNumber() - if err := dec.Decode(&s); err != nil { - return nil, errors.WithStack(err) - } - - db := inmem.NewFromObject(s) - txn, err := db.NewTransaction(ctx, storage.WriteParams) - if err != nil { - return nil, errors.WithStack(err) - } - - for _, c := range collections { - path, ok := storage.ParsePath(c) - if !ok { - return nil, errors.Errorf("unable to parse storage path: %s", c) - } - - var val []interface{} - var b bytes.Buffer - - d, err := query(ctx, c) - if err != nil { - return nil, err - } - - if err := json.NewEncoder(&b).Encode(d); err != nil { - return nil, errors.WithStack(err) - } - - dec := json.NewDecoder(&b) - dec.UseNumber() - if err := dec.Decode(&val); err != nil { - return nil, errors.WithStack(err) - } - - if err := db.Write(ctx, txn, storage.AddOp, path, val); err != nil { - return nil, errors.WithStack(err) - } - } - - if err := db.Commit(ctx, txn); err != nil { - return nil, errors.WithStack(err) - } - return db, nil -} diff --git a/storage/manager_memory.go b/storage/manager_memory.go deleted file mode 100644 index d12f51c3b..000000000 --- a/storage/manager_memory.go +++ /dev/null @@ -1,140 +0,0 @@ -package storage - -import ( - "bytes" - "context" - "encoding/json" - "sync" - - "github.com/open-policy-agent/opa/storage" - "github.com/pkg/errors" - - "github.com/ory/herodot" - "github.com/ory/x/pagination" -) - -type MemoryManager struct { - sync.RWMutex - items map[string][]memoryItem -} - -type memoryItem struct { - Key string - Data json.RawMessage -} - -func NewMemoryManager() *MemoryManager { - return &MemoryManager{ - items: map[string][]memoryItem{}, - } -} - -func (m *MemoryManager) collection(collection string) []memoryItem { - m.RLock() - v, ok := m.items[collection] - m.RUnlock() - if !ok { - m.Lock() - v = []memoryItem{} - m.items[collection] = v - m.Unlock() - } - return v -} - -func (m *MemoryManager) Upsert(_ context.Context, collection, key string, value interface{}) error { - b := bytes.NewBuffer(nil) - if err := json.NewEncoder(b).Encode(value); err != nil { - return errors.WithStack(err) - } - - // no need to evaluate, just create collection if necessary. - m.collection(collection) - - m.Lock() - defer m.Unlock() - - var found bool - for k, i := range m.items[collection] { - if i.Key == key { - m.items[collection][k].Data = b.Bytes() - found = true - break - } - } - if !found { - m.items[collection] = append(m.items[collection], memoryItem{Key: key, Data: b.Bytes()}) - } - - return nil -} - -func (m *MemoryManager) List(ctx context.Context, collection string, value interface{}, limit, offset int) error { - c := m.collection(collection) - start, end := pagination.Index(limit, offset, len(c)) - items := m.list(ctx, collection)[start:end] - return roundTrip(&items, value) -} - -func (m *MemoryManager) list(ctx context.Context, collection string) []json.RawMessage { - c := m.collection(collection) - items := make([]json.RawMessage, len(c)) - - m.RLock() - for k, i := range c { - items[k] = i.Data - } - m.RUnlock() - - return items -} - -func (m *MemoryManager) Get(_ context.Context, collection, key string, value interface{}) error { - c := m.collection(collection) - - m.RLock() - defer m.RUnlock() - - var v []byte - for _, i := range c { - if i.Key == key { - v = i.Data - break - } - } - - if len(v) == 0 { - return errors.WithStack(&herodot.ErrNotFound) - } - - b := bytes.NewBuffer(v) - d := json.NewDecoder(b) - d.DisallowUnknownFields() - if err := d.Decode(value); err != nil { - return errors.WithStack(err) - } - - return nil -} - -func (m *MemoryManager) Delete(_ context.Context, collection, key string) error { - // no need to evaluate, just create collection if necessary. - m.collection(collection) - - m.Lock() - for k, i := range m.items[collection] { - if i.Key == key { - m.items[collection] = append(m.items[collection][:k], m.items[collection][k+1:]...) - break - } - } - m.Unlock() - - return nil -} - -func (m *MemoryManager) Storage(ctx context.Context, schema string, collections []string) (storage.Store, error) { - return toRegoStore(ctx, schema, collections, func(i context.Context, s string) ([]json.RawMessage, error) { - return m.list(i, s), nil - }) -} diff --git a/storage/manager_sql.go b/storage/manager_sql.go deleted file mode 100644 index 9b0138934..000000000 --- a/storage/manager_sql.go +++ /dev/null @@ -1,168 +0,0 @@ -package storage - -import ( - "bytes" - "context" - "encoding/json" - - "github.com/jmoiron/sqlx" - "github.com/open-policy-agent/opa/storage" - "github.com/pkg/errors" - migrate "github.com/rubenv/sql-migrate" - - "github.com/ory/x/dbal" - "github.com/ory/x/sqlcon" -) - -type sqlItem struct { - Key string `db:"pkey"` - Collection string `db:"collection"` - Data string `db:"document"` -} - -var Migrations = map[string]*migrate.MemoryMigrationSource{ - dbal.DriverMySQL: { - Migrations: []*migrate.Migration{ - { - Id: "1", - Up: []string{ - `CREATE TABLE IF NOT EXISTS rego_data ( - id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, - collection VARCHAR(64) NOT NULL, - pkey VARCHAR(64) NOT NULL, - document JSON, - UNIQUE KEY rego_data_uidx_ck (collection, pkey) -)`, - }, - Down: []string{ - "DROP TABLE rego_data", - }, - }, - }, - }, - dbal.DriverPostgreSQL: { - Migrations: []*migrate.Migration{ - { - Id: "1", - Up: []string{ - `CREATE TABLE IF NOT EXISTS rego_data ( - id SERIAL PRIMARY KEY, - collection VARCHAR(64) NOT NULL, - pkey VARCHAR(64) NOT NULL, - document JSON -)`, - `CREATE UNIQUE INDEX rego_data_uidx_ck ON rego_data (collection, pkey)`, - }, - Down: []string{ - "DROP TABLE rego_data", - }, - }, - }, - }, -} - -type SQLManager struct { - db *sqlx.DB -} - -func NewSQLManager(db *sqlx.DB) *SQLManager { - return &SQLManager{ - db: db, - } -} - -func (m *SQLManager) CreateSchemas(db *sqlx.DB) (int, error) { - migrate.SetTable("keto_storage_migration") - n, err := migrate.Exec(db.DB, dbal.Canonicalize(db.DriverName()), Migrations[dbal.MustCanonicalize(db.DriverName())], migrate.Up) - if err != nil { - return 0, errors.Wrapf(err, "could not migrate sql schema completely, applied only %d migrations", n) - } - return n, nil -} - -func (m *SQLManager) Upsert(ctx context.Context, collection, key string, value interface{}) error { - b := bytes.NewBuffer(nil) - if err := json.NewEncoder(b).Encode(value); err != nil { - return errors.WithStack(err) - } - - var query string - switch database := dbal.Canonicalize(m.db.DriverName()); database { - case dbal.DriverMySQL: - query = "INSERT INTO rego_data (pkey, collection, document) VALUES (:pkey, :collection, :document) ON DUPLICATE KEY UPDATE document=:document" - case dbal.DriverPostgreSQL: - query = `INSERT INTO rego_data (pkey, collection, document) VALUES (:pkey, :collection, :document) ON CONFLICT(collection, pkey) DO UPDATE SET document = :document` - default: - return errors.Errorf("unknown database driver: %s", m.db.DriverName()) - } - - if _, err := m.db.NamedExecContext(ctx, query, &sqlItem{ - Key: key, - Collection: collection, - Data: b.String(), - }); err != nil { - return errors.WithStack(err) - } - - return nil -} - -func (m *SQLManager) List(ctx context.Context, collection string, value interface{}, limit, offset int) error { - var items []string - query := "SELECT document FROM rego_data WHERE collection=? ORDER BY id ASC LIMIT ? OFFSET ?" - if err := m.db.SelectContext( - ctx, - &items, - m.db.Rebind(query), collection, limit, offset, - ); err != nil { - return sqlcon.HandleError(err) - } - - ji := make([]json.RawMessage, len(items)) - for k, v := range items { - ji[k] = json.RawMessage(v) - } - - return roundTrip(&ji, value) -} - -func (m *SQLManager) Get(ctx context.Context, collection, key string, value interface{}) error { - query := "SELECT document FROM rego_data WHERE collection=? AND pkey=?" - var item string - if err := m.db.GetContext( - ctx, - &item, - m.db.Rebind(query), collection, key, - ); err != nil { - return sqlcon.HandleError(err) - } - - ji := json.RawMessage(item) - return roundTrip(&ji, value) -} - -func (m *SQLManager) Delete(ctx context.Context, collection, key string) error { - query := "DELETE FROM rego_data WHERE pkey=:pkey AND collection=:collection" - if _, err := m.db.NamedExecContext(ctx, query, &sqlItem{ - Key: key, - Collection: collection, - }); err != nil { - return errors.WithStack(err) - } - - return nil -} - -func (m *SQLManager) Storage(ctx context.Context, schema string, collections []string) (storage.Store, error) { - return toRegoStore(ctx, schema, collections, func(i context.Context, s string) ([]json.RawMessage, error) { - var items []json.RawMessage - if err := m.db.SelectContext( - ctx, - &items, - m.db.Rebind("SELECT document FROM rego_data WHERE collection=? ORDER BY id ASC"), s, - ); err != nil { - return nil, errors.WithStack(err) - } - return items, nil - }) -} diff --git a/storage/manager_test.go b/storage/manager_test.go deleted file mode 100644 index 1cfb57ea4..000000000 --- a/storage/manager_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package storage - -import ( - "context" - "flag" - "fmt" - "log" - "sync" - "testing" - - _ "github.com/go-sql-driver/mysql" - _ "github.com/jackc/pgx/v4" - "github.com/open-policy-agent/opa/storage" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ory/x/sqlcon/dockertest" -) - -var managers = map[string]Manager{ - "memory": NewMemoryManager(), -} -var m sync.Mutex - -func TestMain(m *testing.M) { - runner := dockertest.Register() - - flag.Parse() - if !testing.Short() { - dockertest.Parallel([]func(){ - connectToPG, - connectToMySQL, - }) - } - - runner.Exit(m.Run()) -} - -func connectToMySQL() { - db, err := dockertest.ConnectToTestMySQL() - if err != nil { - log.Fatalf("Could not connect to database: %v", err) - } - - s := NewSQLManager(db) - m.Lock() - managers["mysql"] = s - m.Unlock() - - if _, err := s.CreateSchemas(db); err != nil { - log.Fatalf("Unable to create schemas: %s", err) - } -} - -func connectToPG() { - db, err := dockertest.ConnectToTestPostgreSQL() - if err != nil { - log.Fatalf("Could not connect to database: %v", err) - } - - s := NewSQLManager(db) - m.Lock() - managers["postgres"] = s - m.Unlock() - - if _, err := s.CreateSchemas(db); err != nil { - log.Fatalf("Unable to create schemas: %s", err) - } -} - -func TestMemoryManager(t *testing.T) { - for k, m := range managers { - t.Run(fmt.Sprintf("manager=%s", k), func(t *testing.T) { - ctx := context.Background() - - require.Error(t, m.Get(ctx, "test", "string", nil)) - - t.Run("case=string", func(t *testing.T) { - var vs string - require.NoError(t, m.Upsert(ctx, "test", "string", "foobar")) - require.NoError(t, m.Get(ctx, "test", "string", &vs)) - assert.EqualValues(t, "foobar", vs) - }) - - t.Run("case=int", func(t *testing.T) { - var vs int - require.NoError(t, m.Upsert(ctx, "test", "int", 1234)) - require.NoError(t, m.Get(ctx, "test", "int", &vs)) - assert.EqualValues(t, 1234, vs) - }) - - t.Run("case=upsert", func(t *testing.T) { - var v string - require.NoError(t, m.Upsert(ctx, "test-upsert", "foo", "bar")) - require.NoError(t, m.Get(ctx, "test-upsert", "foo", &v)) - assert.Equal(t, "bar", v) - - require.NoError(t, m.Upsert(ctx, "test-upsert", "foo", "baz")) - require.NoError(t, m.Get(ctx, "test-upsert", "foo", &v)) - assert.Equal(t, "baz", v) - - var vs []string - require.NoError(t, m.List(ctx, "test-upsert", &vs, 10, 0)) - assert.Equal(t, 1, len(vs)) - }) - - t.Run("case=list", func(t *testing.T) { - for i := 0; i < 10; i++ { - require.NoError(t, m.Upsert(ctx, "test-list", fmt.Sprintf("list-%d", i), i)) - } - - var v int - require.NoError(t, m.Get(ctx, "test-list", "list-1", &v)) - assert.EqualValues(t, 1, v) - - var vs []int - require.NoError(t, m.List(ctx, "test-list", &vs, 10, 0)) - assert.Len(t, vs, 10) - assert.EqualValues(t, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, vs) - - require.NoError(t, m.List(ctx, "test-list", &vs, 5, 5)) - assert.Len(t, vs, 5) - assert.EqualValues(t, []int{5, 6, 7, 8, 9}, vs) - }) - - t.Run("case=delete", func(t *testing.T) { - for i := 0; i < 10; i++ { - require.NoError(t, m.Upsert(ctx, "test-delete", fmt.Sprintf("delete-%d", i), i)) - - var v int - require.NoError(t, m.Get(ctx, "test-delete", fmt.Sprintf("delete-%d", i), &v)) - assert.EqualValues(t, i, v) - require.NoError(t, m.Delete(ctx, "test-delete", fmt.Sprintf("delete-%d", i))) - require.Error(t, m.Get(ctx, "test-delete", fmt.Sprintf("delete-%d", i), &v)) - } - }) - - t.Run("case=storage", func(t *testing.T) { - for i := 0; i < 2; i++ { - require.NoError(t, m.Upsert(ctx, "/tests/storage/bars", fmt.Sprintf("list-%d", i), fmt.Sprintf("a-%d", i))) - require.NoError(t, m.Upsert(ctx, "/tests/storage/foos", fmt.Sprintf("list-%d", i), fmt.Sprintf("b-%d", i))) - } - - s, err := m.Storage(ctx, `{"tests": {"storage": {"foos": [], "bars": []}}}`, []string{"/tests/storage/foos", "/tests/storage/bars"}) - require.NoError(t, err) - - tx, err := s.NewTransaction(ctx) - require.NoError(t, err) - - res, err := s.Read(ctx, tx, storage.MustParsePath("/tests/storage/bars")) - require.NoError(t, err) - assert.Equal(t, `[a-0 a-1]`, fmt.Sprintf("%s", res)) - - res, err = s.Read(ctx, tx, storage.MustParsePath("/tests/storage/foos")) - require.NoError(t, err) - assert.Equal(t, `[b-0 b-1]`, fmt.Sprintf("%s", res)) - }) - }) - } -} diff --git a/storage/policy.go b/storage/policy.go deleted file mode 100644 index 219c45a7c..000000000 --- a/storage/policy.go +++ /dev/null @@ -1,60 +0,0 @@ -package storage - -// Policies is an array of policies. -// -// swagger:ignore -type Policies []Policy - -// Policy specifies an ORY Access Policy document. -// -// swagger:ignore -type Policy struct { - // ID is the unique identifier of the ORY Access Policy. It is used to query, update, and remove the ORY Access Policy. - ID string `json:"id"` - - // Description is an optional, human-readable description. - Description string `json:"description"` - - // Subjects is an array representing all the subjects this ORY Access Policy applies to. - Subjects []string `json:"subjects"` - - // Resources is an array representing all the resources this ORY Access Policy applies to. - Resources []string `json:"resources"` - - // Actions is an array representing all the actions this ORY Access Policy applies to. - Actions []string `json:"actions"` - - // Effect is the effect of this ORY Access Policy. It can be "allow" or "deny". - Effect string `json:"effect"` - - // Conditions represents a keyed object of conditions under which this ORY Access Policy is active. - Conditions map[string]interface{} `json:"conditions"` -} - -func (p *Policy) withSubjects(subjects []string) *Policy { - if p == nil || len(subjects) == 0 || contains(subjects[0], p.Subjects) { - return p - } - return nil -} - -func (p *Policy) withResources(resources []string) *Policy { - if p == nil || len(resources) == 0 || contains(resources[0], p.Resources) { - return p - } - return nil -} - -func (p *Policy) withActions(actions []string) *Policy { - if p == nil || len(actions) == 0 || contains(actions[0], p.Actions) { - return p - } - return nil -} - -func (p *Policy) withIDs(ids []string) *Policy { - if p == nil || len(ids) == 0 || contains(p.ID, ids) { - return p - } - return nil -} diff --git a/storage/registry.go b/storage/registry.go deleted file mode 100644 index b0fe88737..000000000 --- a/storage/registry.go +++ /dev/null @@ -1,5 +0,0 @@ -package storage - -type Registry interface { - StorageManager() Manager -} diff --git a/storage/role.go b/storage/role.go deleted file mode 100644 index 82862dfda..000000000 --- a/storage/role.go +++ /dev/null @@ -1,35 +0,0 @@ -package storage - -// A list of roles. -// -// swagger:ignore -type Roles []Role - -// Role represents a group of users that share the same role. A role could be an administrator, a moderator, a regular -// user or some other sort of role. -// -// swagger:ignore -type Role struct { - // ID is the role's unique id. - ID string `json:"id"` - - // Description is the description of the role. - Description string `json:"description"` - - // Members is who belongs to the role. - Members []string `json:"members"` -} - -func (r *Role) withMembers(members []string) *Role { - if r == nil || len(members) == 0 || contains(members[0], r.Members) { - return r - } - return nil -} - -func (r *Role) withIDs(ids []string) *Role { - if r == nil || len(ids) == 0 || contains(r.ID, ids) { - return r - } - return nil -} diff --git a/storage/util.go b/storage/util.go deleted file mode 100644 index 8135852cd..000000000 --- a/storage/util.go +++ /dev/null @@ -1,10 +0,0 @@ -package storage - -func contains(target string, source []string) bool { - for _, i := range source { - if i == target { - return true - } - } - return false -} diff --git a/tests/stubs/policies.json b/tests/stubs/policies.json deleted file mode 100644 index 3a7e19cc6..000000000 --- a/tests/stubs/policies.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "id": "policy-1", - "subjects": [ - "peter-1", - "group-1" - ], - "resources": [ - "resources-11", - "resources-12" - ], - "actions": [ - "actions-11", - "actions-12" - ], - "effect": "allow" - }, - { - "id": "policy-2", - "subjects": [ - "peter-2", - "group-2" - ], - "resources": [ - "resources-11", - "resources-12" - ], - "actions": [ - "actions-11", - "actions-12" - ], - "effect": "allow" - } -] diff --git a/tests/stubs/roles.json b/tests/stubs/roles.json deleted file mode 100644 index 855046d84..000000000 --- a/tests/stubs/roles.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "id": "role-1", - "description": "role-1 test", - "members": [ - "peter-1", - "maria-1" - ] - }, - { - "id": "role-2", - "description": "role-2 test", - "members": [ - "peter-2", - "maria-2" - ] - } -]