Rules¶
Rule library that forms the core of Bridgekeeper.
This module defines the Rule
base class, as well as a
number of built-in rules.
The Rule
API¶
-
class
bridgekeeper.rules.
Rule
¶ Base class for rules.
All rules are instances of this class, but not directly; use (or write!) a subclass instead, as this class will raise
NotImplementedError
if you try to actually do anything with it.-
check
(user, instance=None)¶ Check if a user satisfies this rule.
Given a user, return a boolean indicating if that user satisfies this rule for a given instance, or if none is provided, every instance.
-
filter
(user, queryset)¶ Filter a queryset to instances that satisfy this rule.
Given a queryset and a user, this method will return a filtered queryset that contains only instances from the original queryset for which the user satisfies this rule.
Parameters: - queryset (django.db.models.QuerySet) – The initial queryset to filter
- user (django.contrib.auth.models.User) – The user to match against.
Returns: A filtered queryset
Return type: django.db.models.QuerySet
Warning
If you are subclassing this class, don’t override this method; override
query()
instead.
-
is_possible_for
(user)¶ Check if it is possible for a user to satisfy this rule.
Returns
True
if it is possible for an instance to exist for which the given user satisfies this rule,False
otherwise.For example, in a multi-tenanted app, you might have a rule that allows access to model instances if a user is a staff user, or if the instance’s tenant matches the user’s tenant.
In that case,
check()
, when called without an instance, would returnTrue
only for staff users (since only they can see every instance). This method would returnTrue
for all users, because every user could possibly see an instance (whether it’s one that exists currently in the database, or a hypothetical one that might in the future).Cases where this method would return
False
include where a user doesn’t have the right role or subscription plan to use a feature at all; this method is the single-permission equivalent of has-module-perms.
-
Built-in Blanket Rules¶
-
bridgekeeper.rules.
always_allow
¶ Rule that always allows access to everything.
-
bridgekeeper.rules.
always_deny
¶ Rule that never allows access to anything.
-
bridgekeeper.rules.
is_authenticated
¶ Rule that allows access to users for whom
is_authenticated
isTrue
.
-
bridgekeeper.rules.
is_superuser
¶ Rule that allows access to users for whom
is_superuser
isTrue
.
Rule Classes¶
-
class
bridgekeeper.rules.
Attribute
(attr, matches)¶ Rule class that checks the value of an instance attribute.
This rule is satisfied by model instances where the attribute given in
attr
matches the value given inmatches
.Parameters: - attr (str) – An attribute name to match against on the model instance.
- value – The value to match against, or a callable that takes a user and returns a value to match against.
For instance, if you had a model class
Widget
with an attributecolour
that was either'red'
,'green'
or'blue'
, you could limit access to blue widgets with the following:blue_widgets_only = Attribute('colour', matches='blue')
Restricting access in a multi-tenanted application by matching a model’s
tenant
to the user’s might look like this:applications_by_tenant = Attribute('tenant', lambda user: user.tenant)
Warning
This rule uses Python equality (
==
) when checking a retrieved Python object, but performs an equality check on the database when filtering a QuerySet. Avoid using it with imprecise types (e.g. floats), and ensure that you are using the correct Python type (e.g.decimal.Decimal
for decimals rather than floats or strings), to prevent inconsistencies.
-
class
bridgekeeper.rules.
Relation
(attr, rule)¶ Check that a rule applies to a ForeignKey.
Parameters: For example, given
Applicant
andApplication
models, to allow access to all applications to anyone who has permission to access the related applicant:perms['foo.view_application'] = Relation( 'applicant', perms['foo.view_applicant'])
-
class
bridgekeeper.rules.
ManyRelation
(query_attr, rule)¶ Check that a rule applies to a many-object relationship.
This can be used in a similar fashion to
Relation
, but across aManyToManyField
, or the remote end of aForeignKey
.Parameters: - query_attr (str) – Name of a many-object relationship to check. This
This is the name that you
use when filtering this relationship using
.filter()
. If you are on the side of the relationship where the field is defined, this is typically the lowercased model name (e.g.mymodel
on its own, notmymodel_set
), unless you’ve setrelated_name
orrelated_query_name
. - rule (Rule) – Rule to check the foreign object against.
For example, given
Agency
andCustomer
models, to allow agency users access only to customers that have a relationship with their agency:perms['foo.view_customer'] = ManyRelation( 'agency', Is(lambda user: user.agency))
- query_attr (str) – Name of a many-object relationship to check. This
This is the name that you
use when filtering this relationship using
-
class
bridgekeeper.rules.
Is
(instance)¶ Rule class that checks the identity of the instance.
This rule is satisfied only by a the provided model instance.
Parameters: instance – The instance to match against, or a callable that takes a user and returns a value to match against. For instance, if you only wanted a user to be able to update their own profile:
own_profile = Is(lambda user: user.profile)
-
class
bridgekeeper.rules.
In
(collection)¶ Rule class that checks the instance is a member of a collection.
This rule is satisfied only by model instances that are members of the provided collection.
Parameters: collection – The collection to match against, or a callable that takes a user and returns a value to match against. For instance, if you only wanted to match groups a user is in:
own_profile = Is(lambda user: user.profile)
Built-in rule instances¶
-
bridgekeeper.rules.
current_user
= Is(<function <lambda>>)¶ Rule class that checks the identity of the instance.
This rule is satisfied only by a the provided model instance.
Parameters: instance – The instance to match against, or a callable that takes a user and returns a value to match against. For instance, if you only wanted a user to be able to update their own profile:
own_profile = Is(lambda user: user.profile)
-
bridgekeeper.rules.
in_current_groups
= In(<function <lambda>>)¶ Rule class that checks the instance is a member of a collection.
This rule is satisfied only by model instances that are members of the provided collection.
Parameters: collection – The collection to match against, or a callable that takes a user and returns a value to match against. For instance, if you only wanted to match groups a user is in:
own_profile = Is(lambda user: user.profile)
Extension Points (For Writing Your Own Rule
Subclasses)¶
-
class
bridgekeeper.rules.
Rule
If you want to create your own rule class, these are the methods you need to override.
-
query
(user)¶ Generate a
Q
object.Note
This method is used internally by
filter()
; subclasses will need to override it but you should never need to call it directly.Given a user, return a
Q
object which will filter a queryset down to only instances for which the given user satisfies this rule.Alternatively, return
UNIVERSAL
if this user satisfies this rule for every possible object, orEMPTY
if this user cannot satisfy this rule for any possible object. (These two values are usually only returned in “blanket rules” which depend only on some property of the user, e.g. the built-inis_staff
, but these are usually best created with theblanket_rule
decorator.)Parameters: user (django.contrib.auth.models.User) – The user to match against. Returns: A query that will filter a queryset to match this rule. Return type: django.db.models.Q
-
check
(user, instance=None) Check if a user satisfies this rule.
Given a user, return a boolean indicating if that user satisfies this rule for a given instance, or if none is provided, every instance.
-
-
bridgekeeper.rules.
UNIVERSAL
= UNIVERSAL¶
-
bridgekeeper.rules.
EMPTY
= EMPTY¶