Django¶
The oso Django integration adopts Django conventions and provides middleware, view decorators and ORM integrations to make it easier to use oso with Django.
Installation¶
The oso Django integration is available on PyPI and can be installed using pip
:
$ pip install django-oso
Usage¶
The django_oso
django plugin contains a reusable django app that makes authorization with oso and django easy. To use, ensure django_oso
is in INSTALLED_APPS
:
INSTALLED_APPS = [
'django_oso',
...
]
By default, django_oso
will consider policy files as source code and restart the server on any changes. To prevent this, add the configuration option: OSO_RELOAD_SERVER = False
to your application’s settings.py
file.
To reload policies on each request in DEBUG
mode without restarting the server, you can use the ReloadPolicyMiddleware
as a complement to the above configuration change.
Loading policies¶
django_oso
expects policy files to be included in the policy
directory of each installed app. Upon startup, all .polar
files found in that directory (or sub-directories) will be loaded using oso.Oso.load_file()
. To load additional files outside of these directories, call load_file()
on django_oso.oso.Oso
.
Registering classes & models¶
Often, authorization rules will be expressed over django models. Therefore, django_oso
will register every model for each installed app upon startup as a class with oso. The django.http.HttpRequest
is also registered under HttpRequest
. Django models are referenced in a Polar file using the syntax app_name::ModelName
. If an app name contains .
, for example django.contrib.auth
, it will be referenced in oso as django::contrib::auth
.
Additional classes can be registered as needed using oso.Oso.register_class()
on django_oso.oso.Oso
.
Performing authorization¶
To authorize a request, use the django_oso.auth.authorize()
function. It calls is_allowed()
, but provides sensible defaults for working with Django. The actor defaults to request.user
. The action
defaults to the method of the request. resource
must be provided.
Tip
If you aren’t familiar with how oso uses actors, actions, and resources to express authorization decisions, see Glossary or Quickstart.
django_oso.auth.authorize()
can be used within route handlers, or in the data access layer, depending upon how you want to express authorization.
Here’s a basic example in a route:
def get_expense(request, id):
try:
expense = Expense.objects.get(pk=id)
except Expense.DoesNotExist:
return HttpResponseNotFound()
authorize(request, expense, action="read")
return HttpResponse(expense.json())
Requiring authorization on every request¶
Since authorize()
is just a function call, it can be forgotten. To enforce authorization on every request, use the RequireAuthorization()
middleware. Any view that does not call authorize()
or skip_authorization()
will raise an exception.
Route authorization¶
One common usage of django_oso.auth.authorize()
is to perform authorization based on the request object. The authorize_request()
decorator does this:
from django_oso.decorators import authorize_request
@authorize_request
def auth_route(request):
pass
Rules can then be written using request attributes, like the path:
# Allow any actor to make a GET request to "/".
allow(_user: User, "GET", http_request: HttpRequest) if
http_request.path = "/";
To enforce route authorization on all requests (the equivalent of decorating every route as we did above), use the RouteAuthorization()
middleware during initialization.
Example¶
Check out the Django integration example app below on GitHub:
API Reference¶
Authorization¶
Authorize
request
forresource
,actor
andaction
.Calls
oso.Oso.is_allowed()
with the corresponding arguments. If authorization fails, raises adjango.core.exceptions.PermissionDenied
exception.- Parameters
actor – The actor making the request. Defaults to
request.user
.action – The action to authorize the actor to perform. Defaults to
request.method
.resource – The resource to authorize the actor to access.
- Raises
django.core.exceptions.PermissionDenied – If the request is not authorized.
See
django_oso.decorators.authorize()
for view decorator version of this function.
Mark
request
as not requiring authorization.Use with the
django_oso.middleware.RequireAuthorization()
middleware to silence missing authorization errors.See
django_oso.decorators.skip_authorization()
for view decorator version of this function.
Middleware¶
- class
django_oso.middleware.
ReloadPolicyMiddleware
(get_response)¶ Reloads all oso policies on every request when in DEBUG mode
- class
django_oso.middleware.
RequireAuthorization
(get_response)¶ Check that
authorize
was called during the request.- Raises
oso.OsoError – If
authorize
was not called during request processing.
Warning
This check is performed at the end of request processing before returning a response. If any database modifications are committed during the request, but it was not authorized, an OsoError will be raised, but the database modifications will not be rolled back.
- class
django_oso.middleware.
RouteAuthorization
(get_response)¶ Perform route authorization on every request.
A call to
authorize()
will be made before view functions are called with the parametersactor=request.user, action=request.method, resource=request
.Rules in oso policies can be written over requests using the
HttpRequest
specializer:allow(actor, action, resource: HttpRequest) if # Access request properties to perform authorization request.path = "/";
Note
If the view returns a 4**, or 5** HTTP status, this will be returned to the end user even if authorization was not performed.
View Decorators¶
Authorize view for
resource
,actor
, andaction
.All three parameters must be constant for this decorator to be used. If actor or action are omitted, the defaults from
django_oso.auth.authorize()
. are used.
Authorize the view function, using the request as the resource.
This performs route authorization, similarly to
RouteAuthorization
, but on a single view.
View-decorator that marks a view as not requiring authorization.
Use in combination with
django_oso.middleware.RequireAuthorization()
. Some views will not require authorization. This decorator marks those views so that the middleware can skip the check.
List endpoint authorization¶
The oso Django integration includes list filtering support for Django models.
Note
These features are in preview and will be stabilized in a future release. Please join our Slack to provide feedback or discuss with the engineering team.
Usage¶
See the list filtering usage guide for more information.
API Reference¶
Authorize
request
for django modelmodel
,actor
, andaction
.Warning
This feature is currently in preview.
Partially evaluates the Polar rule
allow(actor, action, Partial(model))
. If authorization fails, raises adjango.core.exceptions.PermissionDenied
exception.Otherwise, returns a django
Q
object representing a filter that must be applied tomodel
. This object can be applied to filter query results to only contain authorized objects.For example:
post_filter = authorize_model(request, Post) authorized_posts = Post.objects.filter(post_filter)
See also:
- Parameters
actor – The actor making the request. Defaults to
request.user
.action – The action to authorize the actor to perform. Defaults to
request.method
.model – The model to authorize access for.
- Raises
django.core.exceptions.PermissionDenied – If the request is not authorized.
- Returns
A django
Q
object representing the authorization filter.
- class
django_oso.models.
AuthorizedModel
(*args, **kwargs)¶ Use a manager based on
AuthorizedQuerySet
, allowing theauthorize()
method to be used.Warning
This feature is currently in preview.
- class
django_oso.models.
AuthorizedQuerySet
(model=None, query=None, using=None, hints=None)¶ QuerySet
withauthorize()
method.