I want to add object level access control.
(Explaining it with dummy student-notice schema)
Student should access(edit/view) the notice(news) only if student has same class(standard) and subject assigned as that of notice. There are two roles/groups - 'student' and 'teacher'
Database schema:
# model db.py
auth.define_tables(username=False, signature=True)
db.define_table('class', Field('name'))
db.define_table('subject', Field('name'))
db.define_table('notice', Field('title'),
Field('class', db.class),
Field('subject', db.subject))
db.define_table('user_class', Field('user', db.auth_user),
Field('class', db.class))
db.define_table('user_subject', Field('user', db.auth_user),
Field('subject', db.subject))
-
#controller default.py
def has_ownership():
# Check if logged in user has class and subject to view/edit this notice
pass
@auth.requires_login()
@auth.requires(lambda: has_ownership())
def notice():
user_classes = db(db.user_class.auth_user == auth.user.id).select()
user_class_list = [clss['id'] for clss in user_classes]
user_subjects = db(db.user_subject.auth_user == auth.user.id).select()
user_subject_list = [subject['id'] for subject in user_subjects]
query = db.notice.class.belongs(user_class_list) & db.notice.subject.belongs(user_subject_list)
grid = SQLFORM.grid(query, user_signature=True)
return dict(grid=grid)
All the urls are digitally signed and also i am showing records in the grid as per user's subject and class.
So my question is only digitally signed urls are enough to restrict user from accessing other records? (by changing id in the url)
Or i need to do extra check like i did using decorator has_ownership
?
Is there any other alternative to achieve object level access control in web2py? I dont want to use CRUD.
Thank You
Because the query
already restricts the set of records displayed by the grid to those the user is authorized to access, the digitally signed URLs of the grid (which are enabled by default) are sufficient to prevent access to any other records. Not only will changes to the record ID in the URL be rejected, but if the user attempts to tamper with the hidden "id" form field in the edit form, the form submission will be rejected. So, no need for the has_ownership
check.
As an aside, there is no need for a lambda when all the lambda does is call a single function with the same arguments passed to the lambda (in this case, no arguments). So, the decorator could be simplified to @auth.requires(has_ownership)
(of course, you don't actually need the decorator in this case).