Skip to content

Commit

Permalink
new data filtering guide for all langs (#1500)
Browse files Browse the repository at this point in the history
  • Loading branch information
saolsen authored Jan 25, 2022
1 parent 7018862 commit e0ae6f1
Show file tree
Hide file tree
Showing 22 changed files with 3,870 additions and 478 deletions.
145 changes: 141 additions & 4 deletions docs/content/any/guides/data_filtering/index.go.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,148 @@
title: "Filter Data"
weight: 1
showContentForAnyLanguage: true
no_nav: true
---

# Filter Data: Coming Soon
# Filter Data

Data filtering is coming soon for {{< lang >}}!
When you call `authorize(actor, action, resource)` , Oso evaluates the allow
rule(s) you have defined in your policy to determine if `actor` is allowed
to perform `action` on `resource`. For example, if `jane` wants to `"edit"`
a `document`, Oso may check that `jane = document.owner`. But what if you
need the set of all documents that Jane is allowed to edit? For example, you
may want to render them as a list in your application.

One way to answer this question is to take every document in the system and
call `is_allowed` on it. This isn’t efficient and many times is just
impossible. There could be thousands of documents in a database but only three
that have the owner `"steve"`. Instead of fetching every document and passing
it into Oso, it's better to ask the database for only the documents that
have the owner `"steve"`. Using Oso to filter the data in your data
store based on the logic in your policy is what we call “Data Filtering”.

You can use data filtering to enforce authorization on queries made to your data
store. Oso will take the logic in the policy and turn it into a query for the
authorized data. Examples could include an ORM filter object, an HTTP request or
an elastic-search query. The query object and the way the logic maps to a query
are both user defined.

Data filtering is initiated through two methods on `Oso`.

`{{% exampleGet "authorizedResources" %}}` returns a list of all the
resources a user is allowed to do an action on. The results of a built and
executed query.

`{{% exampleGet "authorizedQuery" %}}` returns the query object itself.
This lets you add additional filters or sorts or any other data to it before
executing it.

The mapping from Polar to a query is defined by an `Adapter`. If an adapter exists
for your ORM or database you can use it, otherwise you may have to implement your own.

## Implementing an Adapter

### Adapters

An adapter is an interface that defines two methods. Once you've defined an adapter, you
can configure your Oso instance to use it with the
`{{% exampleGet "setDataFilteringAdapter" %}}` method.

#### Build a Query

`{{% exampleGet "buildQuery" %}}` takes some type information and a `Filter` object and returns a `Query`.

A `{{% exampleGet "filterName" %}}` is a representation of a query. It is very similar to a SQL query.
It has four fields:

- `{{% exampleGet "filterRoot" %}}` Is the name of the type we are filtering.
- {{% exampleGet "filterRelations" %}} Are named relations to other types, typically turned into joins.
- `{{% exampleGet "filterConditions" %}}` Are the individual pieces of logic that must be true with respect to objects
matching the filter. These typically get turned into where clauses.
- `{{% exampleGet "filterTypes" %}}` Is a map from type names to user type information, including registered relations.
We use this to generate the join SQL.

##### Relations

A relation has three properties: `{{% exampleGet "relationFrom" %}}`, `{{% exampleGet "relationName" %}}`, and `{{% exampleGet "relationTo" %}}`.
The adapter uses these properties to look up the tables and fields to join together for
the query.

##### Conditions

A condition has three properties `{{% exampleGet "conditionLeft" %}}`, `{{% exampleGet "conditionOp" %}}`, and `{{% exampleGet "conditionRight" %}}`.
The left and right fields will be either `Immediate` objects with a `{{% exampleGet "immediateValue" %}}` field that can
be inserted directly into a query, or `Projection` objects with string properties
`{{% exampleGet "projectionType" %}}` and optionally `{{% exampleGet "projectionField" %}}`. A
missing `{{% exampleGet "projectionField" %}}` property indicates the adapter should substitute
an appropriate unique identifier, usually a primary key.

#### Execute a Query

`{{% exampleGet "executeQuery" %}}` takes a query and returns a list of the results.

### Fields

The other thing you have to provide to use data filtering is type information
for registered classes. This lets Oso know what the types of an object's fields
are. Oso needs this information to handle specializers and other things in the
policy when we don't have a concrete resource. The fields are a
{{% exampleGet "map" %}} from field name to type.

## Relations

Often you need data that is not contained on the object to make
authorization decisions. This comes up when the role required to
do something is implied by a role on it's parent object. For instance,
you want to check the organization for a repository but that data isn't
embedded on the repository object. You can add a `Relation` type to the type
definition that states how the other resource is related to this one. Then
you can access this field in the policy like any other field and it will
fetch the data when it needs it (via the query functions).

`Relation`s are a special type that tells Oso how one Class is related to
another. They specify what the related type is and how it's related.

- `kind` is either "one" or "many". "one" means there is one related object and
"many" means there is a list of related objects.
- `other_type` is the class of the related objects.
- `my_field` Is the field on this object that matches `other_field`.
- `other_field` Is the field on the other object that matches `this_field`.

The `my_field` / `other_field` relationship is similar to a foreign key. It lets Oso
know what fields to match up with building a query for the other type.

## Example

For an example of how to implement an adapter in Go, see our [data
filtering test
adapter](https://github.com/osohq/oso/blob/70188629cb4630bab1b4128860520d4f28134706/languages/go/tests/data_filtering_test.go#L80)
which uses [GORM][]. Or, you can see [this example][] that uses [SQLBoiler][].

[this example]: https://github.com/osohq/oso-go-df-sqlboiler
[GORM]: https://gorm.io
[SQLBoiler]: https://github.com/volatiletech/sqlboiler

## Evaluation
When Oso is evaluating data filtering methods it uses the adapter to build queries
and execute them.

Relation fields also work when you are not using data filtering methods are also
use the adapter to query for the related resources when you access them.


## Limitations

Go data filtering is currently unsupported on Windows.

Some Polar operators including `cut` and arithmetic operators aren't supported in
data filtering queries.

You can't call any methods on the resource argument or pass the resource as an
argument to other methods. Many cases where you would want to do this are better
handled by `Relation` fields.

The new data filtering backend doesn't support queries where a given resource
type occurs more than once, so direct or indirect relations from a type to itself
are currently unsupported. This limitation will be removed in an upcoming release.

If you want to get data filtering in your app now or just want to
register your interest for Data Filtering in {{< lang >}}, [drop into our Slack](https://join-slack.osohq.com).
8 changes: 4 additions & 4 deletions docs/content/any/guides/data_filtering/index.java.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ weight: 1
showContentForAnyLanguage: true
---

# Filter Data: Coming Soon
# Filter Data

Data filtering is coming soon for {{< lang >}}!
Data filtering is coming soon for Java!

If you want to get data filtering in your app now or just want to
register your interest for Data Filtering in {{< lang >}}, [drop into our Slack](https://join-slack.osohq.com).
If you want to register your interest for Data Filtering in
Java, [drop into our Slack](https://join-slack.osohq.com).
Loading

1 comment on commit e0ae6f1

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust Benchmark

Benchmark suite Current: e0ae6f1 Previous: 7018862 Ratio
rust_get_attribute 51159 ns/iter (± 4367) 52093 ns/iter (± 22043) 0.98
n_plus_one/100 2446622 ns/iter (± 71120) 2464847 ns/iter (± 139138) 0.99
n_plus_one/500 12272661 ns/iter (± 542641) 12272455 ns/iter (± 1061250) 1.00
n_plus_one/1000 24220250 ns/iter (± 719619) 24871660 ns/iter (± 1974934) 0.97
unify_once 1085 ns/iter (± 86) 1135 ns/iter (± 139) 0.96
unify_twice 2713 ns/iter (± 110) 2969 ns/iter (± 629) 0.91
many_rules 68004 ns/iter (± 3302) 67131 ns/iter (± 3681) 1.01
fib/5 578905 ns/iter (± 27708) 565371 ns/iter (± 48786) 1.02
prime/3 19516 ns/iter (± 5703) 19431 ns/iter (± 2119) 1.00
prime/23 19548 ns/iter (± 1993) 19675 ns/iter (± 1618) 0.99
prime/43 19661 ns/iter (± 1723) 19671 ns/iter (± 1485) 1.00
prime/83 19452 ns/iter (± 1363) 19343 ns/iter (± 1963) 1.01
prime/255 17920 ns/iter (± 1017) 18400 ns/iter (± 1737) 0.97
indexed/100 6510 ns/iter (± 1387) 6864 ns/iter (± 1173) 0.95
indexed/500 8175 ns/iter (± 2227) 8618 ns/iter (± 2189) 0.95
indexed/1000 10178 ns/iter (± 6351) 9983 ns/iter (± 1177) 1.02
indexed/10000 18000 ns/iter (± 4181) 26675 ns/iter (± 37625) 0.67
not 6619 ns/iter (± 369) 6548 ns/iter (± 465) 1.01
double_not 13582 ns/iter (± 814) 14648 ns/iter (± 1353) 0.93
De_Morgan_not 8562 ns/iter (± 381) 8795 ns/iter (± 626) 0.97
load_policy 950472 ns/iter (± 23137) 966174 ns/iter (± 54467) 0.98
partial_and/1 35222 ns/iter (± 2491) 34835 ns/iter (± 2668) 1.01
partial_and/5 121439 ns/iter (± 6603) 118698 ns/iter (± 11205) 1.02
partial_and/10 231602 ns/iter (± 16696) 226219 ns/iter (± 15517) 1.02
partial_and/20 467711 ns/iter (± 21105) 461659 ns/iter (± 17482) 1.01
partial_and/40 998808 ns/iter (± 29374) 1054300 ns/iter (± 84846) 0.95
partial_and/80 2317162 ns/iter (± 89088) 2331312 ns/iter (± 171839) 0.99
partial_and/100 3109555 ns/iter (± 168321) 3473381 ns/iter (± 245021) 0.90
partial_rule_depth/1 111883 ns/iter (± 5461) 135430 ns/iter (± 10219) 0.83
partial_rule_depth/5 364256 ns/iter (± 23875) 387809 ns/iter (± 27055) 0.94
partial_rule_depth/10 806790 ns/iter (± 46649) 851922 ns/iter (± 125779) 0.95
partial_rule_depth/20 2326833 ns/iter (± 180110) 2667885 ns/iter (± 247998) 0.87
partial_rule_depth/40 8727450 ns/iter (± 290968) 10764097 ns/iter (± 535848) 0.81
partial_rule_depth/80 58064723 ns/iter (± 1783949) 62789354 ns/iter (± 5008214) 0.92
partial_rule_depth/100 109466550 ns/iter (± 3478705) 114313168 ns/iter (± 5782175) 0.96

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.