The current REST api of the application does not have authorization mechanism configured. Without letting system know who you are any user can perform not just read, but creation, modification or removal of entitities via any REST endpoint of the system at the moment. Your first task will be to fix the authorization mechanism as described below.
NOTE:
- Authentication (AuthN) is a process that verifies that someone or something is who they say they are. e.g. Employing password, passport scan, face recognition,...
- Authorization (AuthZ) is a process of giving users or services permission to access some data or perform a particular action. e.g. adding new work items, removing users
The system has preloaded example data that includes users and groups. If you are curious how uploading of the data is done, you can find the code in one of the db bigrations here.
Here is the list of users preloaded to the system.
username | password | group | admin |
---|---|---|---|
admin |
admin!12345 |
Yes | |
janneke |
janneke!12345 |
municipality_workers |
No |
jeroen |
jeroen!12345 |
municipality_workers |
No |
sjoerd |
sjoerd!12345 |
art_managers |
No |
Here are groups and what users that belong to them allowed do on model entities:
group | Building |
Spots |
ArtItems |
ArtLocation |
ArtBorrowingRequest |
---|---|---|---|---|---|
municipality_workers |
view |
view |
view |
view |
view + add |
art_managers |
view + add + change + delete |
view + add + change + delete |
view + add + change + delete |
view + add + change + delete |
view + delete |
As admin user (having is_staff=True
) you don't have limits on what you can do using the admin panel.
Note that being part of the art managers group gives you permissions for viewing and deleting the art borrowing request only. And as the municipality worker you can view and add one. We want to add a possibility to a municipality worker to remove the requests he/she created further on in the tutorial using employing object level permissions.
Go to project folder and create the database:
python manage.py migrate
Start the application:
python manage.py runserver
Go to http://localhost:8000/admin and use the admin credentials from the above table to login to the admin panel. Scan the preloaded data.
Log out to become Anonymous again.
Go to http://localhost:8000/inventory/api/. Explore the endpoints and all operations UI gives you opportunity to do. As you see public user can do everything he/she wants with the data via the api. We don't employ the model permissions mentioned above yet.
NOTE: If you changed the data and want to start over you can achieve that by stopping the server, removing the database file (db.sqlite3
) and starting server again.
There are automatic test that check permissions for the endpoints given different users. Check the code here
You can run those test with:
python manage.py test
As you see most of them are failing. After fixing the authrorization all of them has to pass. You can the above testing command iteratively, after each change, to see whether you've impoved the code towards the goal.
The permission policy can be set globally (in settings.py
) or for each APIView/ViewSet.
Read more on this here.
Django REST framework comes with multiple permission classes. Read about them here and set the correct one for your application to fix the authorization for the app according with the model permissions.
All tests have to pass after you'll set the correct policy.
The second assignment requires you to write a custom policy that defines permissions for each object, not for the whole class of objects as we had before.
As we mentioned before a municipality worker can't remove his own art borrowing requests at the moment. The goal of this is to change this.
Start with reading the documentation on object level permissions.
Check the tests. There are two tests that are skipped. It's test_delete_art_borrowing_request_as_municipality_worker
and test_delete_art_borrowing_request_as_another_municipality_worker
. Remove @unittest.skip
line and run all tests. You will see those tests failing. After implementing the object level permissions correctly they have to pass.
Check examples of custom permission definition here.
Django has basic authentication enabled by default.
It gives you a possibility to query api from other clients passing username and password information. Here is example of curl:
curl -u 'admin:admin!12345' http://127.0.0.1:8000/inventory/api/users/
Try it on your own instance.
It's not recomended to use basic authentication in production though. The main concern is that you are exposing password by sending it with each request. As a solution we can implement the token authentication. The advantage is that tokens can be revoked (removed) easily later closing the access for the client.
With token authentication the above curl request could be made like this:
curl -X GET http://127.0.0.1:8000/inventory/api/users/ -H 'Authorization: Token 9944b09199c62bcf9418tu43545sdsdfgfg'
After implementing token authentication make sure the basic authentication is switched off.