Published on

Role Based Access with Django

Authors

Role Based Access Control

Provides restrictive access to the users in a system based on their role (User groups) Above implies the entire format will be implemented with group and no granular permissions assigned to the user directly

Explicit Features/Tasks

  • User is a member of one group or more groups
  • Group contains many users and many permisions
  • Each user created will have a group with their username
  • Sub users will be registered on parent users group and they will be able to cascade the permisions downstream.
  • Adding permission to the role/Group
  • Remove permission from the group/role
  • Add user to group/role
  • Remove user from role/group
  • Get all permisions of a role
  • Get all users of a role

Features Implemented in the application

  • Application/api security (JWT token generation)
  • Data normalizations (Database functionlity)
  • Auditable data (Timestamps and user profile on any data manupilation done)
  • Application testability (Unit tests to achieve coverage greater 90%)
  • Application documentation (Feature and code documentation on readme file)
  • Code versioning (Git hub)
  • Deployment and delivery via Heroku
  • Depandencies management and documentation on requirements.txt
  • Logging and log management.

Potential challenges

  • How to handle deletion of parent sub. so that the other subs remain but permision related to the parent sub are removed. NOTE: Group defines the role of the user in the system

Research material

Application setup

Get the application source code from github

git clone https://github.com/ryananyangu/tmpbuupassrepo.git

Change directory into the application directory

cd tmpbuupassrepo

Create virtual environment to host the application dependacies

python3 -m venv env

Activate the virtual environment

source ../env/bin/activate

Install application dependancies into your virtual directory

pip install -r requirements.txt

Add the following enviromental variables to be able to run the application smoothly

# Advisable never to use the default even though it exists esp in prod
export SECRET_KEY={insert your own !}
# Debug only accepts True or False values default is True
export DEBUG=True|False
# Database url if not set defaults to sqlite setup
export DATABASE_URL={insert your own postgresql url}

Making the model migrations and running the generated migrations For both default apps and cordinates app

python3 manage.py makemigrations
python3 manage.py makemigrations cordinates
python3 manage.py migrate

Create a supper user account to be able to access both the apis and admin portal

python3 manage.py createsuperuser
# Follow the prompt instructions recieved

Run the application

python3 manage.py runserver

Production setup is different as it uses

  1. Whitenoise to server static files and
  2. Gunicorn for serving the backend api

Following is the variation of production command for running the application Setup for whitenoise for deployment to heroku is already done in the settings.py file

# Collect all the static files to be served with application i.e. admin, rest_api browser etc.
python3 manage.py collectstatic --noinput

# Run the application on production
gunicorn --bind 0.0.0.0:$PORT buupass.wsgi:application --log-file -

Running test and getting the test coverage report.

coverage run --source='.' manage.py test cordinates
coverage report

APIs Implementation and Examples

Login API

login link

Sample request via curl

curl -X POST \
  https://ashiruma-buupass.herokuapp.com/api-token-auth/ \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
        "username": "rashiruma",
        "password": "XXXXXXXXX"
      }'

Sample response

{
  "token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

Verify Token API

token verification link

Sample request

curl -X POST \
  https://ashiruma-buupass.herokuapp.com/api-token-refresh/ \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
        "token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
      }'

Sample response

{
  "token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

Refresh token API

token refresh link

Sample request

curl -X POST \
  https://ashiruma-buupass.herokuapp.com/api-token-refresh/ \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
        "token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
      }'

Sample response with new token

{
  "token": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
}

GET Roles of logged in user

get roles of logged in user

curl --location --request GET 'https://ashiruma-buupass.herokuapp.com/user/roles/' \
--header 'Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
[
  {
    "id": 1,
    "name": "rashiruma",
    "admin_id__username": "rashiruma",
    "created_at": "2022-01-06T07:08:33.815437Z",
    "created_by__username": "rashiruma",
    "modified_at": "2022-01-06T07:08:33.832000Z",
    "modified_by__username": "rashiruma"
  },
  {
    "id": 3,
    "name": "ztech",
    "admin_id__username": "ztech",
    "created_at": "2022-01-06T10:32:20.586653Z",
    "created_by__username": "ztech",
    "modified_at": "2022-01-06T10:32:20.587621Z",
    "modified_by__username": "ztech"
  }
]

Add user to role

Add user to a role

curl --location --request POST 'https://ashiruma-buupass.herokuapp.com/user/roles/' \
--header 'Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXX' \
--header 'Content-Type: application/json' \
--data-raw '{
    "role_id":1,
    "user_id":3
}'

Sample response

{
  "message": "user ranyangu added to role rashiruma successfully"
}

Delete user from role

Remove user from role

curl --location --request DELETE 'https://ashiruma-buupass.herokuapp.com/user/roles/1/' \
--header 'Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \
--data-raw ''

Sample response

{
  "message": "Role rashiruma removed from user rashiruma profile."
}

Invite user (Sub registration) to personal role

Invited user request accept request invited role

Add remove permisions from group