Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

As a developer, we have to secure the exposed endpoints (APIs) according the desired permission rules.

openIMIS backend is configured with 2 authorizations layers:

  • the django default (basic) permissions mechanism

  • the RBAC ‘django-rules’ extensions

If any of the 2 layer grants the access, the access is given to the user.


openIMIS endpoints can be:

  • django straight ‘views’ endpoints

  • django-rest-framework endpoints (recommended)

  • graphene GrapQL queries and mutations (via scheme definition)


At its very basis, backend modules can rely on:

  • The django straight ‘views’ endpoints must be explicitly defined by the developers (please refer to https://docs.djangoproject.com/en/2.1/topics/security/ )

  • The django-rest-framework, however, has been configured to enforce the default (type-based) django permissions mapping: GET on <module>.view_<model>, POST on <module>.add_<module>,...

  • The graphene 'resolve_xxx' hook to access (query) object graph, and 'async_mutate' resolution for mutation


The django default (basic) permissions mechanism has been extended to dynamically add the (legacy) users rights as 'permission'. So, on top of any configured GET <module>.view_<model> (,...) permission, user receives all coded permissions from the tblRoleRight table (for the roles he belongs to).

To check these roles (in the backend), the recommendation is to configure (via module configuration) the used constant for the check:

Example (claim read access):

in openimis-be-claim_py/claim/app.py:

DEFAULT_CFG

=

{

[...]

"gql_query_claims_perms":

["111001"],

[...]
}

... and check it via standard django permission in openimis-be-claim_py/claim/schema.py:

def

resolve_claims(self,

info,

**kwargs):

if

not

info.context.user.has_perms(ClaimConfig.gql_query_claims_perms):

raise

PermissionDenied(_("unauthorized"))

[...]


We recommend (and this is what is in place in reference modules such as claims,...) to enforce the fine-grained security in django model itslef (overriding the 'get_query' method). This ensures that security that security applies whatever endpoint technology (GraphQL, FHIR, ...) is exposing it.

Example (claim limit by user's registered HF):

in openimis-be-claim_py/claim/models.py:


class

Claim(core_models.VersionedModel):

id

=

models.AutoField(db_column='ClaimID',

primary_key=True)

[...]

@classmethod

def

get_queryset(cls,

queryset,

user):

queryset

=

Claim.filter_queryset(queryset)

#

GraphQL

calls

with

an

info

object

while

Rest

calls

with

the

user

itself

if

isinstance(user,

ResolveInfo):

user

=

user.context.user

if

settings.ROW_SECURITY

and

user.is_anonymous:

return

queryset.filter(id=-1)

if

settings.ROW_SECURITY:

#

TechnicalUsers

don't

have

health_facility_id

attribute

if

hasattr(user._u,

'health_facility_id')

and

user._u.health_facility_id:

return

queryset.filter(

health_facility_id=user._u.health_facility_id

)

else:

dist

=

UserDistrict.get_user_districts(user._u)

return

queryset.filter(

health_facility__location_id__in=[l.location_id

for

l

in

dist]

)

return

queryset


For finer (rule-based) grained security (object-level) the django-rules module has been configured and is readily available for use (declaring predicates,...). It is however not already used at the time of writing.