{"id":13700946,"url":"https://github.com/ory/ladon","last_synced_at":"2025-05-12T13:20:20.202Z","repository":{"id":41070768,"uuid":"44393602","full_name":"ory/ladon","owner":"ory","description":"A SDK for access control policies: authorization for the microservice and IoT age. Inspired by AWS IAM policies. Written for Go.","archived":false,"fork":false,"pushed_at":"2025-03-12T16:19:08.000Z","size":16810,"stargazers_count":2421,"open_issues_count":3,"forks_count":224,"subscribers_count":63,"default_branch":"master","last_synced_at":"2025-05-12T13:19:54.257Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.ory.sh/?utm_source=github\u0026utm_medium=banner\u0026utm_campaign=ladon","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ory.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":"audit_logger.go","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"patreon":"_ory","open_collective":"ory"}},"created_at":"2015-10-16T15:21:28.000Z","updated_at":"2025-05-11T16:19:55.000Z","dependencies_parsed_at":"2024-03-05T11:26:30.464Z","dependency_job_id":"38f263b5-4e0e-4d17-95a8-a9d23f527e5b","html_url":"https://github.com/ory/ladon","commit_stats":{"total_commits":142,"total_committers":48,"mean_commits":"2.9583333333333335","dds":0.7605633802816901,"last_synced_commit":"42f4158fd9bff58cafdb27589e4a98add07aa8d6"},"previous_names":["ory-am/ladon"],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fladon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fladon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fladon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ory%2Fladon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ory","download_url":"https://codeload.github.com/ory/ladon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253745197,"owners_count":21957320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T20:01:10.276Z","updated_at":"2025-05-12T13:20:20.175Z","avatar_url":"https://github.com/ory.png","language":"Go","funding_links":["https://patreon.com/_ory","https://opencollective.com/ory"],"categories":["Go","Authorization","Authorization Development"],"sub_categories":["\u003ca name=\"authZ-golang\"\u003e\u003c/a\u003eGolang","ABAC frameworks"],"readme":"\u003ch1 align=\"center\"\u003e\u003cimg src=\"./docs/images/banner_ladon.png\" alt=\"ORY Ladon - Policy-based Access Control\"\u003e\u003c/h1\u003e\n\n[![Join the chat at https://www.ory.sh/chat](https://img.shields.io/badge/join-chat-00cc99.svg)](https://www.ory.sh/chat)\n[![Join newsletter](https://img.shields.io/badge/join-newsletter-00cc99.svg)](https://www.ory.sh/l/sign-up-newsletter)\n\n[![Build Status](https://travis-ci.org/ory/ladon.svg?branch=master)](https://travis-ci.org/ory/ladon)\n[![Coverage Status](https://coveralls.io/repos/ory/ladon/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/ory/ladon?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/ory/ladon)](https://goreportcard.com/report/github.com/ory/ladon)\n[![GoDoc](https://godoc.org/github.com/ory/ladon?status.png)](https://godoc.org/github.com/ory/ladon)\n\n[Ladon](https://en.wikipedia.org/wiki/Ladon_%28mythology%29) is the serpent dragon protecting your resources.\n\nLadon is a library written in [Go](https://golang.org) for access control policies, similar to [Role Based Access Control](https://en.wikipedia.org/wiki/Role-based_access_control)\nor [Access Control Lists](https://en.wikipedia.org/wiki/Access_control_list).\nIn contrast to [ACL](https://en.wikipedia.org/wiki/Access_control_list) and [RBAC](https://en.wikipedia.org/wiki/Role-based_access_control)\nyou get fine-grained access control with the ability to answer questions in complex environments such as multi-tenant or distributed applications\nand large organizations. Ladon is inspired by [AWS IAM Policies](http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html).\n\nLadon officially ships with an exemplary in-memory storage implementations.\nCommunity-supported adapters are available for [CockroachDB](https://github.com/wehco/ladon-crdb).\n\nLadon is now considered stable.\n\n---\n\nORY builds solutions for better internet security and accessibility. We have a couple more projects you might enjoy:\n\n* **[Hydra](https://github.com/ory/hydra)**, a security-first open source OAuth2 and OpenID Connect server for new and existing infrastructures that uses Ladon for access control.\n* **[ORY Editor](https://github.com/ory/editor)**, an extensible, modern WYSI editor for the web written in React.\n* **[Fosite](https://github.com/ory/fosite)**, an extensible security first OAuth 2.0 and OpenID Connect SDK for Go.\n* **[Dockertest](https://github.com/ory/dockertest)**: Write better integration tests with dockertest!\n\n---\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**\n\n- [Installation](#installation)\n- [Concepts](#concepts)\n- [Usage](#usage)\n  - [Policies](#policies)\n    - [Conditions](#conditions)\n      - [CIDR Condition](#cidr-condition)\n      - [String Equal Condition](#string-equal-condition)\n      - [Boolean Condition](#boolean-condition)\n      - [String Match Condition](#string-match-condition)\n      - [Subject Condition](#subject-condition)\n      - [String Pairs Equal Condition](#string-pairs-equal-condition)\n      - [Resource Contains Condition](#resource-contains-condition)\n      - [Adding Custom Conditions](#adding-custom-conditions)\n    - [Persistence](#persistence)\n  - [Access Control (Warden)](#access-control-warden)\n  - [Audit Log (Warden)](#audit-log-warden)\n  - [Metrics](#metrics)\n- [Limitations](#limitations)\n  - [Regular expressions](#regular-expressions)\n- [Examples](#examples)\n- [Good to know](#good-to-know)\n- [Useful commands](#useful-commands)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\nLadon utilizes ory-am/dockertest for tests.\nPlease refer to [ory-am/dockertest](https://github.com/ory-am/dockertest) for more information of how to setup testing environment.\n\n## Installation\n\nThis library works with Go 1.11+.\n\n```\nexport GO111MODULE=on\ngo get github.com/ory/ladon\n```\n\nLadon uses [semantic versioning](http://semver.org/) and versions beginning with zero (`0.1.2`) might introduce backwards compatibility\nbreaks with [each minor version](http://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase).\n\n## Concepts\n\nLadon is an access control library that answers the question:\n\n\u003e **Who** is **able** to do **what** on **something** given some **context**\n\n* **Who**: An arbitrary unique subject name, for example \"ken\" or \"printer-service.mydomain.com\".\n* **Able**: The effect which can be either \"allow\" or \"deny\".\n* **What**: An arbitrary action name, for example \"delete\", \"create\" or \"scoped:action:something\".\n* **Something**: An arbitrary unique resource name, for example \"something\", \"resources.articles.1234\" or some uniform\n    resource name like \"urn:isbn:3827370191\".\n* **Context**: The current context containing information about the environment such as the IP Address,\n    request date, the resource owner name, the department ken is working in or any other information you want to pass along.\n    (optional)\n\nTo decide what the answer is, Ladon uses policy documents which can be represented as JSON\n\n```json\n{\n  \"description\": \"One policy to rule them all.\",\n  \"subjects\": [\"users:\u003cpeter|ken\u003e\", \"users:maria\", \"groups:admins\"],\n  \"actions\" : [\"delete\", \"\u003ccreate|update\u003e\"],\n  \"effect\": \"allow\",\n  \"resources\": [\n    \"resources:articles:\u003c.*\u003e\",\n    \"resources:printer\"\n  ],\n  \"conditions\": {\n    \"remoteIP\": {\n        \"type\": \"CIDRCondition\",\n        \"options\": {\n            \"cidr\": \"192.168.0.1/16\"\n        }\n    }\n  }\n}\n```\n\nand can answer access requests that look like:\n\n```json\n{\n  \"subject\": \"users:peter\",\n  \"action\" : \"delete\",\n  \"resource\": \"resources:articles:ladon-introduction\",\n  \"context\": {\n    \"remoteIP\": \"192.168.0.5\"\n  }\n}\n```\n\nHowever, Ladon does not come with a HTTP or server implementation. It does not restrict JSON either. We believe that it is your job to decide\nif you want to use Protobuf, RESTful, HTTP, AMQP, or some other protocol. It's up to you to write the server!\n\nThe following example should give you an idea what a RESTful flow *could* look like. Initially we create a policy by\nPOSTing it to an artificial HTTP endpoint:\n\n```\n\u003e curl \\\n      -X POST \\\n      -H \"Content-Type: application/json\" \\\n      -d@- \\\n      \"https://my-ladon-implementation.localhost/policies\" \u003c\u003cEOF\n        {\n          \"description\": \"One policy to rule them all.\",\n          \"subjects\": [\"users:\u003cpeter|ken\u003e\", \"users:maria\", \"groups:admins\"],\n          \"actions\" : [\"delete\", \"\u003ccreate|update\u003e\"],\n          \"effect\": \"allow\",\n          \"resources\": [\n            \"resources:articles:\u003c.*\u003e\",\n            \"resources:printer\"\n          ],\n          \"conditions\": {\n            \"remoteIP\": {\n                \"type\": \"CIDRCondition\",\n                \"options\": {\n                    \"cidr\": \"192.168.0.1/16\"\n                }\n            }\n          }\n        }\n  EOF\n```\n\nThen we test if \"peter\" (ip: \"192.168.0.5\") is allowed to \"delete\" the \"ladon-introduction\" article:\n\n```\n\u003e curl \\\n      -X POST \\\n      -H \"Content-Type: application/json\" \\\n      -d@- \\\n      \"https://my-ladon-implementation.localhost/warden\" \u003c\u003cEOF\n        {\n          \"subject\": \"users:peter\",\n          \"action\" : \"delete\",\n          \"resource\": \"resources:articles:ladon-introduction\",\n          \"context\": {\n            \"remoteIP\": \"192.168.0.5\"\n          }\n        }\n  EOF\n\n{\n    \"allowed\": true\n}\n```\n\n## Usage\n\nWe already discussed two essential parts of Ladon: policies and access control requests. Let's take a closer look at those two.\n\n### Policies\n\nPolicies are the basis for access control decisions. Think of them as a set of rules. In this library, policies\nare abstracted as the `ladon.Policy` interface, and Ladon comes with a standard implementation of this interface\nwhich is `ladon.DefaultPolicy`. Creating such a policy could look like:\n\n```go\nimport \"github.com/ory/ladon\"\n\nvar pol = \u0026ladon.DefaultPolicy{\n\t// A required unique identifier. Used primarily for database retrieval.\n\tID: \"68819e5a-738b-41ec-b03c-b58a1b19d043\",\n\n\t// A optional human readable description.\n\tDescription: \"something humanly readable\",\n\n\t// A subject can be an user or a service. It is the \"who\" in \"who is allowed to do what on something\".\n\t// As you can see here, you can use regular expressions inside \u003c \u003e.\n\tSubjects: []string{\"max\", \"peter\", \"\u003czac|ken\u003e\"},\n\n\t// Which resources this policy affects.\n\t// Again, you can put regular expressions in inside \u003c \u003e.\n\tResources: []string{\n            \"myrn:some.domain.com:resource:123\", \"myrn:some.domain.com:resource:345\",\n            \"myrn:something:foo:\u003c.+\u003e\", \"myrn:some.domain.com:resource:\u003c(?!protected).*\u003e\",\n            \"myrn:some.domain.com:resource:\u003c[[:digit:]]+\u003e\",\n        },\n\n\t// Which actions this policy affects. Supports RegExp\n\t// Again, you can put regular expressions in inside \u003c \u003e.\n\tActions: []string{\"\u003ccreate|delete\u003e\", \"get\"},\n\n\t// Should access be allowed or denied?\n\t// Note: If multiple policies match an access request, ladon.DenyAccess will always override ladon.AllowAccess\n\t// and thus deny access.\n\tEffect: ladon.AllowAccess,\n\n\t// Under which conditions this policy is \"active\".\n\tConditions: ladon.Conditions{\n\t\t// In this example, the policy is only \"active\" when the requested subject is the owner of the resource as well.\n\t\t\"resourceOwner\": \u0026ladon.EqualsSubjectCondition{},\n\n\t\t// Additionally, the policy will only match if the requests remote ip address matches address range 127.0.0.1/32\n\t\t\"remoteIPAddress\": \u0026ladon.CIDRCondition{\n\t\t\tCIDR: \"127.0.0.1/32\",\n\t\t},\n\t},\n}\n```\n\n#### Conditions\n\nConditions are functions returning true or false given a context. Because conditions implement logic, they must\nbe programmed. Adding conditions to a policy consist of two parts, a key name and an implementation of `ladon.Condition`:\n\n```go\n// StringEqualCondition is an exemplary condition.\ntype StringEqualCondition struct {\n\tEquals string `json:\"equals\"`\n}\n\n// Fulfills returns true if the given value is a string and is the\n// same as in StringEqualCondition.Equals\nfunc (c *StringEqualCondition) Fulfills(value interface{}, _ *ladon.Request) bool {\n\ts, ok := value.(string)\n\n\treturn ok \u0026\u0026 s == c.Equals\n}\n\n// GetName returns the condition's name.\nfunc (c *StringEqualCondition) GetName() string {\n\treturn \"StringEqualCondition\"\n}\n\nvar pol = \u0026ladon.DefaultPolicy{\n    // ...\n    Conditions: ladon.Conditions{\n        \"some-arbitrary-key\": \u0026StringEqualCondition{\n            Equals: \"the-value-should-be-this\"\n        }\n    },\n}\n```\n\nThe default implementation of `Policy` supports JSON un-/marshalling. In JSON, this policy would look like:\n\n```json\n{\n  \"conditions\": {\n    \"some-arbitrary-key\": {\n        \"type\": \"StringEqualCondition\",\n        \"options\": {\n            \"equals\": \"the-value-should-be-this\"\n        }\n    }\n  }\n}\n```\n\nAs you can see, `type` is the value that `StringEqualCondition.GetName()` is returning and `options` is used to\nset the value of `StringEqualCondition.Equals`.\n\nThis condition is fulfilled by (we will cover the warden in the next section)\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n        \"some-arbitrary-key\": \"the-value-should-be-this\",\n    },\n}\n```\n\nbut not by\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n        \"some-arbitrary-key\": \"some other value\",\n    },\n}\n```\n\nand neither by:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n        \"same value but other key\": \"the-value-should-be-this\",\n    },\n}\n```\n\nLadon ships with a couple of default conditions:\n\n##### [CIDR Condition](condition_cidr.go)\n\nThe CIDR condition matches CIDR IP Ranges. Using this condition would look like this in JSON:\n\n```json\n{\n    \"conditions\": {\n        \"remoteIPAddress\": {\n            \"type\": \"CIDRCondition\",\n            \"options\": {\n                \"cidr\": \"192.168.0.1/16\"\n            }\n        }\n    }\n}\n```\n\nand in Go:\n\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n        \"remoteIPAddress\": \u0026ladon.CIDRCondition{\n            CIDR: \"192.168.0.1/16\",\n        },\n    },\n}\n```\n\nIn this case, we expect that the context of an access request contains a field `\"remoteIpAddress\"` matching\nthe CIDR `\"192.168.0.1/16\"`, for example `\"192.168.0.5\"`.\n\n\n##### [String Equal Condition](condition_string_equal.go)\n\nChecks if the value passed in the access request's context is identical with the string that was given initially\n\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n        \"some-arbitrary-key\": \u0026ladon.StringEqualCondition{\n            Equals: \"the-value-should-be-this\"\n        }\n    },\n}\n```\n\nand would match in the following case:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n         \"some-arbitrary-key\": \"the-value-should-be-this\",\n    },\n}\n```\n\n##### [Boolean Condition](condition_boolean.go)\n\nChecks if the boolean value passed in the access request's context is identical with the expected boolean value in the policy\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n        \"some-arbitrary-key\": \u0026ladon.BooleanCondition{\n            BooleanValue: true,\n        }\n    },\n}\n```\n\nand would match in the following case:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n        \"some-arbitrary-key\": true,\n    },\n})\n```\n\nThis condition type is particularly useful if you need to assert a policy dynamically on resources for multiple subjects. For example, consider\nif you wanted to enforce policy that only allows individuals that own a resource to view that resource. You'd have to be able to create a Ladon\npolicy that permits access to every resource for every subject that enters your system.\n\nWith the Boolean Condition type, you can use conditional logic at runtime to create a match for a policy's condition.\n\n##### [String Match Condition](condition_string_match.go)\n\nChecks if the value passed in the access request's context matches the regular expression that was given initially\n\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n      \"some-arbitrary-key\": \u0026ladon.StringMatchCondition{\n          Matches: \"regex-pattern-here.+\"\n      }\n    }\n}\n```\n\nand would match in the following case:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n          \"some-arbitrary-key\": \"regex-pattern-here111\"\n    }\n  }\n})\n```\n\n##### [Subject Condition](condition_subject_equal.go)\n\nChecks if the access request's subject is identical with the string that was given initially\n\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n        \"some-arbitrary-key\": \u0026ladon.EqualsSubjectCondition{}\n    },\n}\n```\n\nand would match\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Subject: \"peter\",\n    Context: ladon.Context{\n         \"some-arbitrary-key\": \"peter\",\n    },\n}\n```\n\nbut not:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Subject: \"peter\",\n    Context: ladon.Context{\n         \"some-arbitrary-key\": \"max\",\n    },\n}\n```\n\n##### [String Pairs Equal Condition](condition_string_pairs_equal.go)\n\nChecks if the value passed in the access request's context contains two-element arrays\nand that both elements in each pair are equal.\n\n```go\nvar pol = \u0026ladon.DefaultPolicy{\n    Conditions: ladon.Conditions{\n        \"some-arbitrary-key\": \u0026ladon.StringPairsEqualCondition{}\n    },\n}\n```\n\nand would match\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n         \"some-arbitrary-key\": [\n             [\"some-arbitrary-pair-value\", \"some-arbitrary-pair-value\"],\n             [\"some-other-arbitrary-pair-value\", \"some-other-arbitrary-pair-value\"],\n         ]\n    },\n}\n```\n\nbut not:\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Context: ladon.Context{\n         \"some-arbitrary-key\": [\n             [\"some-arbitrary-pair-value\", \"some-other-arbitrary-pair-value\"],\n         ]\n    },\n}\n```\n\n\n##### [Resource Contains Condition](condition_resource_contains.go)\n\nChecks if the string value passed in the access request's context is present in the resource string.\n\nThe Condition requires a value string and an optional delimiter (needs to match the resource string) to be passed.\n\nA resource could for instance be: `myrn:some.domain.com:resource:123` and `myrn:some.otherdomain.com:resource:123` (the `:` is then considered a delimiter, and used by the condition to be able to separate the resource components from each other) to allow an action to the resources on `myrn:some.otherdomain.com` you could for instance create a resource condition  with\n\n{value: `myrn:some.otherdomain.com`, Delimiter: \":\"}\n\nalternatively:\n\n{value: `myrn:some.otherdomain.com`}\n\n\u003e The delimiter is optional *but needed for* the condition to be able to separate resource string components:\n\u003e i.e. to make sure the value `foo:bar` matches `foo:bar` but not `foo:bara` nor `foo:bara:baz`.\n\u003e\n\u003e That is, a delimiter is necessary to separate:\n\u003e\n\u003e `{value: \"myrn:fo\", delimiter: \":\"}` from `{value: \"myrn:foo\", delimiter: \":\"}` or\n\u003e `{value: \"myid:12\"}` from `{value: \"myid:123\"}`.\n\n\n\nThis condition is fulfilled by this (allow for all resources containing `part:north`):\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Resource: \"rn:city:laholm:part:north\"\n    Context: ladon.Context{\n      delimiter: \":\",\n      value: \"part:north\"\n    },\n}\n```\n\nor ( allow all resources with `city:laholm`)\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Resource: \"rn:city:laholm:part:north\"\n    Context: ladon.Context{\n      delimiter: \":\",\n      value: \"city:laholm\"\n    },\n}\n```\n\nbut not (allow for all resources containing `part:west`, the resource does not contain `part:west`):\n\n```go\nvar err = warden.IsAllowed(\u0026ladon.Request{\n    // ...\n    Resource: \"rn:city:laholm:part:north\"\n    Context: ladon.Context{\n      delimiter: \":\",\n      value: \"part:west\"\n    },\n}\n```\n\n\n##### Adding Custom Conditions\n\nYou can add custom conditions by appending it to `ladon.ConditionFactories`:\n\n```go\nimport \"github.com/ory/ladon\"\n\nfunc main() {\n    // ...\n\n    ladon.ConditionFactories[new(CustomCondition).GetName()] = func() Condition {\n        return new(CustomCondition)\n    }\n\n    // ...\n}\n```\n\n#### Persistence\n\nObviously, creating such a policy is not enough. You want to persist it too. Ladon ships an interface `ladon.Manager` for\nthis purpose. You have to implement that interface for persistence. An exemplary in-memory adapter can be found in\n[./manager/memory/manager_memory.go](./manager/memory/manager_memory.go):\n\nLet's take a look how to instantiate those:\n\n**In-Memory** (officially supported)\n\n```go\nimport (\n\t\"github.com/ory/ladon\"\n\tmanager \"github.com/ory/ladon/manager/memory\"\n)\n\n\nfunc main() {\n\twarden := \u0026ladon.Ladon{\n\t\tManager: manager.NewMemoryManager(),\n\t}\n\terr := warden.Manager.Create(pol)\n\n    // ...\n}\n```\n\n### Access Control (Warden)\n\nNow that we have defined our policies, we can use the warden to check if a request is valid.\n`ladon.Ladon`, which is the default implementation for the `ladon.Warden` interface defines `ladon.Ladon.IsAllowed()` which\nwill return `nil` if the access request can be granted and an error otherwise.\n\n```go\nimport \"github.com/ory/ladon\"\n\nfunc main() {\n    // ...\n\n    err := warden.IsAllowed(\u0026ladon.Request{\n        Subject: \"peter\",\n        Action: \"delete\",\n        Resource: \"myrn:some.domain.com:resource:123\",\n        Context: ladon.Context{\n            \"ip\": \"127.0.0.1\",\n        },\n    })\n    if err != nil {\n        log.Fatal(\"Access denied\")\n    }\n\n    // ...\n}\n```\n\n### Audit Log (Warden)\n\nIn order to keep track of authorization grants and denials, it is possible to attach a `ladon.AuditLogger`.\nThe provided `ladon.AuditLoggerInfo` outputs information about the policies involved when responding to authorization requests.\n\n```go\nimport \"github.com/ory/ladon\"\nimport manager \"github.com/ory/ladon/manager/memory\"\n\nfunc main() {\n\n    warden := ladon.Ladon{\n        Manager: manager.NewMemoryManager(),\n        AuditLogger: \u0026ladon.AuditLoggerInfo{}\n    }\n\n    // ...\n\n```\n\nIt will output to `stderr` by default.\n\n### Metrics\n\nAbility to track authorization grants,denials and errors, it is possible to implement own interface for processing metrics.\n\n```go\ntype prometheusMetrics struct{}\n\nfunc (mtr *prometheusMetrics) RequestDeniedBy(r ladon.Request, p ladon.Policy) {}\nfunc (mtr *prometheusMetrics) RequestAllowedBy(r ladon.Request, policies ladon.Policies) {}\nfunc (mtr *prometheusMetrics) RequestNoMatch(r ladon.Request) {}\nfunc (mtr *prometheusMetrics) RequestProcessingError(r ladon.Request, err error) {}\n\nfunc main() {\n\n    warden := ladon.Ladon{\n        Manager: manager.NewMemoryManager(),\n        Metric:  \u0026prometheusMetrics{},\n    }\n\n    // ...\n```\n\n## Limitations\n\nLadon's limitations are listed here.\n\n### Regular expressions\n\nMatching regular expressions has a complexity of `O(n)` ([except](https://groups.google.com/d/msg/golang-nuts/7qgSDWPIh_E/OHTAm4wRZL0J) lookahead/lookbehind assertions) and databases such as MySQL or Postgres can not\nleverage indexes when parsing regular expressions. Thus, there is considerable overhead when using regular\nexpressions.\n\nWe have implemented various strategies for reducing policy matching time:\n\n1. An LRU cache is used for caching frequently compiled regular expressions. This reduces cpu complexity\nsignificantly for memory manager implementations.\n2. The SQL schema is 3NF normalized.\n3. Policies, subjects and actions are stored uniquely, reducing the total number of rows.\n4. Only one query per look up is executed.\n5. If no regular expression is used, a simple equal match is done in SQL back-ends.\n\nYou will get the best performance with the in-memory manager. The SQL adapters perform about 1000:1 compared to the in-memory solution. Please note that these tests where in laboratory environments with Docker, without an SSD, and single-threaded. You might get better results on your system. We are thinking about introducing simple cache strategies such as LRU with a maximum age to further reduce runtime complexity.\n\nWe are also considering to offer different matching strategies (e.g. wildcard match) in the future, which will perform better\nwith SQL databases. If you have ideas or suggestions, leave us an issue.\n\n## Examples\n\nCheck out [ladon_test.go](ladon_test.go) which includes a couple of policies and tests cases. You can run the code with `go test -run=TestLadon -v .`\n\n## Good to know\n\n* All checks are *case sensitive* because subject values could be case sensitive IDs.\n* If `ladon.Ladon` is not able to match a policy with the request, it will default to denying the request and return an error.\n\nLadon does not use reflection for matching conditions to their appropriate structs due to security considerations.\n\n## Useful commands\n\n**Create mocks**\n```sh\nmockgen -package ladon_test -destination manager_mock_test.go github.com/ory/ladon Manager\n```\n\n## Third Party Libraries\nBy implementing the warden.Manager it is possible to create your own adapters to persist data in a datastore of your choice. Below are a list of third party implementations.\n\n- [Redis and RethinkDB](https://github.com/ory/ladon-community)\n- [CockroachDB](https://github.com/dwin/ladon-crdb)\n- [sql.DB](https://github.com/wirepair/ladonsqlmanager)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fladon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fory%2Fladon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fory%2Fladon/lists"}