DSC-McMaster-U / Gamified-Learning-Platform

MIT License
6 stars 14 forks source link

Role based Access - New Teacher/Student Login & Reg - STILL needs fixing/testing #117

Closed angadk4 closed 7 months ago

angadk4 commented 8 months ago

Created a new system for RBAC. Essentially, individuals can now use a toggle at the top of the registration page to log in as either a teacher or student, which assigns the role of either "User" or "Teacher." Upon login, the system now uses an email query to verify whether the user is a teacher or student, and proceeds accordingly.

Changes Made:

Notes/Issues:

alexchen2 commented 8 months ago

Overall, there are two general things I wanted to ask you regarding the implementation of your RBAC model here: the mutual exclusivity of consumers being either Users or Teachers, and the design similarities of the Users & Teachers database tables.

For the former, how are you setting up the distinction between consumers within these roles? Can a consumer be both a teacher and a student, or is it an "either-or", one-or-the-other situation? Looking at your auth.py login code at lines 26 to 31, it appears as if you're going for the latter option. You attempt to query one entry in both User and Teacher with the given login email and expect one of them to be None:

# Check both User and Teacher tables
user = User.query.filter_by(email=email).first()
teacher = Teacher.query.filter_by(email=email).first()

# Determine if the email belongs to a Teacher or a User
account = teacher if teacher else user

However, if we take a look at lines 64 to 84:

role = request.form.get("role")
...
if role == "teacher":
    user_email = Teacher.query.filter_by(email=email).first()
    user_name = Teacher.query.filter_by(username=username).first()
else:
    user_email = User.query.filter_by(email=email).first()
    user_name = User.query.filter_by(username=username).first()
...
if user_name:
    flash("This username already exists.", "register_error")
    return redirect(url_for("auth.register"))
...
if user_email:
    flash("This email already exists.", "register_error")
    return redirect(url_for("auth.register"))   

This code shows that when a consumer signs up under some arbitrary username A and email B, the auth system checks for duplicate usernames/emails among only other teachers when signing up as a teacher, or only other students when signing up as a student. Thus, an actor/two separate actors could accidentally sign up with the same exact email A and password B under two accounts—one student, and one teacher. Problem is, given the way the if statement at line 31 is structured, the auth system will always choose only one account role over the other, and it always has a bias towards choosing teachers. As such, when logging in with email A and password B, the system will never log into the student's account and always access the teacher's.

If you're going for a "can be both" approach and want the same email to have a teacher and student role, then we should probably add a similar radio role select button/use separate pages for login. Otherwise, you should probably check for duplicate emails/usernames within both the User and Teacher tables in lines 64 to 84, no matter the role.

alexchen2 commented 8 months ago

For the second topic, this initially came to mind due to bugs with logging in as a Teacher; Flask-Login requires any entity inheriting UserMixin to specifically have an id attribute as its primary key (not tid), and Teacher was also missing an extra failed_signin_attempts field from User that was needed in auth.py. These fixes are pretty simple to fix by altering the Teacher table, but the User and Teacher tables have so many similarities between each other at this point that it feels inefficient and a waste of space to have them as separate tables. Wouldn't it just be better to have a main User table with shared attributes (name, hashed_password, email, etc.), then create ISA specializations for each role that inherit from the parent User table (Student having grade, points, etc; Teacher having yrs_experience, specialization, etc.)? This way, not only is our code more concise, but we wouldn't have to constantly create and manage duplicate columns between both tables taking up valuable storage.

I do understand, however, that changing this DB structure this late into the project would most likely take a bit more time in fixing any resulting bugs with queries dependent on the old User model (with Student-specific attributes), so I understand if you aren't too keen on the idea.

angadk4 commented 7 months ago

I have implemented all of the relevant changes recommended by Alex:

Here are some other important things to note:

angadk4 commented 7 months ago

Added changes to properly account for an error when email associated with both teacher & user.