greenshirt
greenshirt

Reputation: 41

Pony ORM PermissionError in access rule for to_json function

I have a problem trying to grasp and to understand why it happens. I'm using Pony ORM, for models the problem I'm trying to solve.

I'm trying to send the query result in json format using to_json function from database instance.

Here the code I used.

from pony.orm import *
db = Database()

#entities definition

class User(db.Entity):
    nama = Required(str)
    admin = Required(bool, default=False)
    diklat = Optional('Diklat')


class Diklat(db.Entity):
    nama = Required(str)
    finished = Required(bool, default=False)
    peserta = Set(User)

# database binding
db.bind('sqlite', ':memory:', create_db=True)
db.generate_mapping(create_tables=True)

# test data
with db_session:
    u1 = User(nama='user 1')
    u2 = User(nama='user 2', admin=True)
    u3 = User(nama='user 3')
    d1 = Diklat(nama='diklat 1')
    d2 = Diklat(nama='diklat 2', finished=True)
    # add user to diklat
    d1.peserta.add(u1)
    d1.peserta.add(u2)
    d2.peserta.add(u3)
    flush()
    commit()

# access rules setup

@user_groups_getter(User)
def user_groups(user):
    if user.admin:
        return ['admin', 'user']
    return ['user']

@user_roles_getter(User, Diklat)
def user_roles(user, diklat):
    if user in diklat.peserta:
        return ['peserta']
    return ['nonpeserta']

@obj_labels_getter(Diklat)
def obj_labels(diklat):
    if diklat.finished:
        return ['finished']
    return ['process']


# permission setup
with db.set_perms_for(Diklat):
    perm('view', role='peserta')

# some function to get data in form of json 
def get_diklat():
    d = select(d for d in Diklat)
    return db.to_json(d)


if __name__ == '__main__':
    with db_session:
        user1 = User[1]
        user2 = User[2]
        user3 = User[3]
        diklat = Diklat[1]
        set_current_user(user1)
        print("current user should 'User[1]':", get_current_user())
        print("User group user should '['user']':", user_groups(user1))
        print("User group user2 should '['admin', 'user']':", user_groups(user2))
        print("User group user3 should '['user']':", user_groups(user3))
        print("Roles for user and diklat should '['peserta']' :", user_roles(user1, diklat))
        print("Roles for user2 and diklat should '['peserta']' :", user_roles(user2, diklat))
        print("Roles for user3 and diklat should '['nonpeserta']' :", user_roles(user3, diklat))
        print("Object labels for diklat, should '['process']':", obj_labels(diklat))
        print(get_diklat())

And the problems is permission setup for get_diklat() getting to access the role ...here the result traceback

current user should 'User[1]': User[1]
User group user should '['user']': ['user']
User group user2 should '['admin', 'user']': ['admin', 'user']
User group user3 should '['user']': ['user']
Roles for user and diklat should '['peserta']' : ['peserta']
Roles for user2 and diklat should '['peserta']' : ['peserta']
Roles for user3 and diklat should '['nonpeserta']' : ['nonpeserta']
Object labels for diklat, should '['process']': ['process']
Traceback (most recent call last):
  File "C:/Users/******/test.py", line 82, in <module>
    get_diklat()
  File "C:/Users/******/test.py", line 64, in get_diklat
    return db.to_json(d)
  File "<string>", line 2, in to_json
  File "C:\Miniconda3\envs\env35\lib\site-packages\pony\utils\utils.py", line 58, in cut_traceback
    return func(*args, **kwargs)
  File "C:\Miniconda3\envs\env35\lib\site-packages\pony\orm\core.py", line 1020, in to_json
    data_json = json.dumps(data, default=obj_converter)
  File "C:\Miniconda3\envs\env35\lib\json\__init__.py", line 237, in dumps
    **kw).encode(obj)
  File "C:\Miniconda3\envs\env35\lib\json\encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Miniconda3\envs\env35\lib\json\encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
  File "C:\Miniconda3\envs\env35\lib\site-packages\pony\orm\core.py", line 1014, in obj_converter
    user_has_no_rights_to_see(obj)
  File "C:\Miniconda3\envs\env35\lib\site-packages\pony\orm\core.py", line 1004, in user_has_no_rights_to_see
    % (user, sorted(user_groups), obj))
  File "C:\Miniconda3\envs\env35\lib\site-packages\pony\utils\utils.py", line 96, in throw
    raise exc
pony.orm.core.PermissionError: The current user User[1] which belongs to groups ['anybody', 'user'] has no rights to see the object Diklat[2] on the frontend

Based on above permission setup, and miss a bit docs, https://docs.ponyorm.com/ponyjs_security.html?highlight=permissions_for, I think the roles for the current user was setup with the right thing,

 # permission setup
    with db.set_perms_for(Diklat):
        perm('view', role='peserta')

role of the current user, (see example data)...i think its right so, what the problems was ?? why pony says :

pony.orm.core.PermissionError: The current user User[1] which belongs to groups ['anybody', 'user'] has no rights to see the object Diklat[2] on the frontend

Why does this happen?

If I change the permission setup like this,

# permission setup
with db.set_perms_for(Diklat):
    perm('view', group='user')

It works like I hope. This output from get_diklat() function:

{"data": [{"class": "Diklat", "pk": 1}, {"class": "Diklat", "pk": 2}], "objects": {"Diklat": {"1": {"nama": "diklat 1", "id": 1, "finished": false}, "2": {"nama": "diklat 2", "id": 2, "finished": true}}}, "schema": [{"name": "Diklat", "newAttrs": [{"auto": true, "kind": "PrimaryKey", "name": "id", "type": "int"}, {"kind": "Required", "name": "nama", "type": "str"}, {"kind": "Required", "name": "finished", "type": "bool"}], "pkAttrs": ["id"]}], "schema_hash": "600696882295084e228d496c580a1f77"}

If I check in interactive console, I think it has permit to view the diklat object

>>> diklat
Diklat[1]
>>> user1
User[1]
>>> user2
User[2]
>>> with db_session:
    has_perm(user2, 'view', diklat)

    
True
>>> 

Upvotes: 1

Views: 975

Answers (1)

Alexander Kozlovsky
Alexander Kozlovsky

Reputation: 4849

The exception arises because the current user does not have 'view' permission for a specific instance of Diklat entity, namely, Diklat[2]. This information is specified in the error message: "The current user User[1] which belongs to groups ['anybody', 'user'] has no rights to see the object Diklat[2] on the frontend".

The permission rules defined as:

with db.set_perms_for(Diklat):
    perm('view', role='peserta')

That means that in order to have the view permission a user need to have a role 'peserta' to specific instance of Diklat.

According to user_roles_getter hook, in order to have a 'peserta' role a user need to be an item of diklat.peserta collection:

@user_roles_getter(User, Diklat)
def user_roles(user, diklat):
    if user in diklat.peserta:
        return ['peserta']
    return ['nonpeserta']

The current user User[1] does not belong to Diklat[2].peserta collection, hence for Diklat[2] object it does not have peserta role. Because of this, User[1] does not have permission view for Diklat[2] object, and so Diklat[2] object cannot be serialized to JSON when the current user is User[1].

Upvotes: 0

Related Questions