Reputation: 41
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
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