Role-based Access Control Lists Support

Introduction

OpenSRP introduces role-based access control lists in version 3.0.0.

More information on the ACL implementation can be found here Implementing Access Control in OpenSRP.

Migrating to ACL

Data Clean-up

OpenSRP ACLs use locationId and teamId to filter clients based on what team or location a user is assigned to. In some cases, this information is not present in client records.

To resolve this, the database script below should be ran to update the records with the values missing.

The script loops through clients whose teamId or locationId are null. Each client record found to have any of the values missing is updated with the teamId or locationId in the corresponding event.

-- Updates Clients teamId and locationId CREATE OR REPLACE FUNCTION update_teamId_locationId() RETURNS void LANGUAGE plpgsql AS $$ DECLARE rec core.client%rowtype; v_team_id CHARACTER VARYING(100); v_location_id CHARACTER VARYING(100); BEGIN FOR rec IN SELECT * FROM core.client WHERE json->'teamId' IS NULL OR json->'locationId' IS NULL LOOP --RAISE NOTICE 'baseEntityId: %', rec.json->'baseEntityId'; SELECT json->'teamId', json->'locationId' INTO v_team_id, v_location_id FROM core.event WHERE json->'baseEntityId' = rec.json->'baseEntityId' LIMIT 1; --exit when v_team_id is null or v_location_id is null; IF v_team_id IS NOT NULL THEN UPDATE core.client SET json = jsonb_set(json, '{teamId}', v_team_id::jsonb, true) WHERE id = rec.id; END IF; IF v_location_id IS NOT NULL THEN UPDATE core.client SET json = jsonb_set(json, '{locationId}', v_location_id::jsonb, true) WHERE id = rec.id; END IF; END LOOP; END; $$

Realm and Roles Creation in Keycloak

Before deploying OpenSRP version with ACLs enabled, the Keycloak realm must be set up with a minimum set of roles (new_realm_roles.json) and groups (new_realm_groups.json) as defined below.

The python script below (new_realm_keycloak_script.py) creates a new realm whose name and admin details are defined in config.ini file.

Additional details on the new realm are defined in new_realm.json. The configuration values in this file provide more details on the realm such as session lifespans, token timeouts, etc.

The deployment script and configuration files below can also be found here.

import requests import json from keycloak import KeycloakAdmin from jinja2 import Environment, BaseLoader import configparser # Read Realm specifications from config.ini config = configparser.ConfigParser() config.read('config.ini') # Get the default realm admin keycloak_admin = KeycloakAdmin( server_url=config["DEFAULT"]["server_url"], username=config["DEFAULT_REALM"]["admin_username"], password=config["DEFAULT_REALM"]["admin_password"], realm_name=config["DEFAULT_REALM"]["realm_name"], verify=True) # Create the new realm and the realm's default admin user using values defined in new_realm.json with open('new_realm.json') as f1: rtemplate = Environment(loader=BaseLoader).from_string(f1.read()) data = rtemplate.render( realm_name=config["NEW_REALM"]["realm_name"], client_name=config["NEW_REALM"]["client_name"], admin_username=config["NEW_REALM"]["admin_username"], admin_password=config["NEW_REALM"]["admin_password"], admin_first_name=config["NEW_REALM"]["admin_first_name"]) keycloak_admin.create_realm(payload=json.loads(data), skip_exists=True) # Get the newly created realm new_realm_admin = KeycloakAdmin( server_url=config["DEFAULT"]["server_url"], username=config["NEW_REALM"]["admin_username"], password=config["NEW_REALM"]["admin_password"], realm_name=config["NEW_REALM"]["realm_name"], verify=True) # Create roles as defined in new_realm_roles.json with open('new_realm_roles.json') as f2: data = json.load(f2) for d in data: new_realm_admin.create_realm_role(payload=d, skip_exists=True) # Create groups as defined in new_realm_groups.json with open('new_realm_groups.json') as f3: data = json.load(f3) for d in data: # Create groups new_realm_admin.create_group(payload=d, skip_exists=True) group_id = new_realm_admin.get_group_by_path("/"+d["name"]) roles = d["realmRoles"] # Assign roles for each of the groups, if any specified under realmRoles for role in roles: realm_role = new_realm_admin.get_realm_role(role) new_realm_admin.assign_group_realm_roles(group_id["id"], realm_role)
[DEFAULT] server_url = {{server_url}}/auth/ [DEFAULT_REALM] realm_name = master admin_username = {{admin_username}} admin_password = {{admin_password}} [NEW_REALM] realm_name = {{new_realm_name}} client_name = {{new_client_name}} admin_username = {{new_realm_admin_username}} admin_password = {{new_realm_admin_password}} admin_first_name = {{new_realm_admin_first_name}}