លំហសិក្សាកម្ពុជា លំហសិក្សាកម្ពុជា V1.0
ចូល ចុះឈ្មោះ

Advanced OOP Final Project

មូលសង្ខេប / Abstract

**ExamFlow** is a web-based examination platform developed with **Python, Flask, and PostgreSQL**. The system supports exam creation, question management, timed assessments, automated grading, and performance tracking. Its main focus is the implementation of a **Composed Role-Based Access Control (RBAC)** model, which combines direct role permissions with reusable **Permission Bundles**. This approach improves permission reuse, reduces duplication, and provides a centralized and maintainable method for managing access across students, instructors, and administrators.


University of Technology & Entrepreneurship logo

Advanced Object-Oriented Programming

R&D Project Report

Secure Online Examination System

with Composed Role-Based Access Control (RBAC)

( ExamFlow )

Prepared by: Sareth Pich, Men Sereyyuth, Veasna Panhareach

Lecturer: SEK SOCHEAT

Submission Date: September 25, 2026



Chapter 1: Introduction

1.1 Background

Educational institutions rely heavily on digital platforms to create, deliver, and grade examinations. As these platforms scale, restricting user actions becomes critical: instructors must author and publish tests, students should only see assigned assessments, and administrators need system-level oversight without unnecessary access to course content. Role-Based Access Control (RBAC) solves this by grouping permissions into roles and assigning those roles to users, eliminating the need to manage individual user rights directly.

This project, ExamFlow, is a web-based examination platform developed using Python, Flask, and PostgreSQL. Beyond managing core testing workflows—exam authoring, question banks, timed submissions, automated grading, and score analytics—the project's main focus is designing and evaluating a Composed RBAC model. In this setup, a role's effective permissions combine rights assigned directly to the role with reusable, named Permission Bundles.

1.2 Problem Statement

Standard RBAC setups usually map roles directly to permissions through a flat many-to-many relationship. While functional, this approach presents two main drawbacks in practice:

  • Permission duplication: when multiple roles share common responsibilities (such as administrators and auditors needing read-only report access), individual permissions must be attached separately to each role, raising the chance of configuration drift over time.

  • Limited grouping capabilities: flat models lack a direct mechanism to package and reuse related permissions (like an "exam authoring" set) across different roles.

ExamFlow addresses these issues by adding a composition layer—the Permission Bundle—between roles and individual permissions, structured and tested using object-oriented principles.

1.3 Objectives

  1. Design and implement a normalized database schema supporting both direct role to permission assignments and bundle-based permission groups.

  2. Build a centralized authorization service that determines effective user permissions by combining direct and bundle grants.

  3. Enforce route-level access control on all server endpoints, ensuring security is independent of client-side UI state.

  4. To provide a complete administrative interface allowing permissions, roles, and permission bundles to be created, configured, and safely deleted at runtime, without requiring code changes or redeployment.

  5. Validate security controls through automated integration tests and unauthorized access attempts, documenting issues found during development.

1.4 Scope

This project focuses primarily on the RBAC architecture: schema design, object-oriented structure, and authorization enforcement. The examination features (test authoring, question banks, timed attempts, automatic grading, and performance dashboards) serve as a realistic environment to demonstrate and evaluate access control. Exam proctoring, plagiarism monitoring, and manual essay grading are outside the project's scope.

1.5 Significance

Implementing and testing Composed RBAC within a multi-role application highlights core software design techniques: relational normalization, association tables, object composition, and decoupling authorization from application logic. The development history in Chapter 5 also documents the iterative testing and defect resolution process used throughout the project.

Chapter 2: Literature and Technology Review

2.1 Related Systems

Existing educational platforms handle access control in various ways, but few offer administrator-configurable permission bundles:

System

Access Control Approach

Relevant Observation

Moodle

Predefined roles (Admin, Teacher, Student, ...) with capability overrides at course/context level

Powerful but complex; capability overrides are context-scoped rather than composed from reusable named bundles

Google Classroom / Forms

Coarse account-level roles (Teacher / Student) tied to Google Workspace identity

Simple for end users, but offers no visible or customizable permission model for institutions

ClassMarker

Fixed Administrator / Test-taker roles

No granular permission system; role set cannot be extended


2.2 Technology Stack

2.2.1 Flask

Flask was selected for its minimal, unopinionated design, allowing the project to be structured into clear layers (routes, services, and repositories). This architecture keeps components loosely coupled, enabling the authorization module (Section 3.7) to be tested independently of web routing or database details.

2.2.2 PostgreSQL

PostgreSQL serves as the primary database due to its support for relational constraints, composite keys in association tables, and custom CHECK constraints. These features let us enforce key data rules—such as valid exam statuses and positive question point values—directly at the database level rather than depending entirely on application code.

2.2.3 Bcrypt

Bcrypt handles password hashing using a salted, key-stretching design that resists brute-force attacks. While slower than basic hashing algorithms, it provides appropriate security for authentication without affecting overall system responsiveness.

2.3 Object-Oriented Programming Concepts Applied

  • Encapsulation: domain logic resides within model objects—for instance, Exam.publish() verifies that an exam is in draft state and contains at least one question before publishing, rather than relying on caller checks.

  • Composition over inheritance: permissions are linked via object composition rather than deep role hierarchies—a Role combines individual Permission objects directly or aggregates them through PermissionBundle instances (Section 3.5).

  • Polymorphism (Strategy Pattern): grading logic uses a QuestionGrader interface with distinct implementations for single-choice, true/false, and multiple-choice questions. A GraderFactory selects the appropriate grader at runtime, allowing new question types without modifying existing grading code.

  • Layered architecture: web routes manage HTTP requests, services handle business rules, and repositories encapsulate database queries, as shown in Figure 3.4.

Chapter 3: System Analysis and Design

3.1 Requirements

ID

Requirement

Type

FR-1

An administrator shall be able to create, view, edit, and delete permissions, roles, and permission bundles.

Functional

FR-2

The system shall resolve a user's effective permissions as the union of permissions granted directly to their role(s) and permissions granted through bundles attached to their role(s).

Functional

FR-3

Every sensitive route (create, update, delete, publish) shall be protected by a server-side permission check, independent of client-side interface behavior.

Functional

FR-4

A teacher shall be able to author, publish, and manage examinations and questions they own.

Functional

FR-5

A student shall be able to attempt available examinations within their allotted attempts and time window, and view their own results.

Functional

FR-6

Protected system roles, permissions, and bundles shall not be deletable through the interface.

Functional

NFR-1

All state-changing form submissions shall be protected against Cross-Site Request Forgery (CSRF).

Non-functional (Security)

NFR-2

Passwords shall be stored using a salted, adaptive hashing algorithm (bcrypt).

Non-functional (Security)

NFR-3

Permission-change effects shall apply on a user's very next request, without requiring re-login.

Non-functional (Usability)


3.2 User Stories

As a…

I want to…

So that…

Administrator

group related permissions into a reusable bundle

I can attach a coherent capability set to a role in one action

Administrator

be prevented from deleting a permission still in use

I cannot accidentally break enforcement for an active route

Teacher

publish an exam only once it has at least one question

students never encounter an empty examination

Student

see only examinations I am eligible and able to attempt

I am not confused by drafts or exhausted attempts

Student

see my pass/fail status and average score accurately

I can track my own academic progress


3.3 Use Cases

Use Case

Primary Actor

Preconditions

Main Success Scenario

Manage Permission Bundle

Administrator

Actor holds role.manage

Actor creates a bundle, attaches permissions, attaches bundle to a role; enforcement updates on next request

Author Examination

Teacher

Actor holds exam.create

Actor creates a draft exam, adds questions, and publishes it once at least one question exists

Attempt Examination

Student

Exam is published, within window, attempts remain

Actor starts or resumes an attempt, answers questions, submits before the timer expires, and receives an automatically graded result

View Result Roster

Teacher / Admin

Actor holds result.view_teacher_exams or admin.access

Actor views aggregate pass-rate and per-student scores for an exam they authored (or, for admin, any exam)


3.4 Entity-Relationship Diagram

The database schema is fully normalized. The access-control layer uses four association tables (user_roles, role_permissions, bundle_permissions, and role_bundles) to allow roles to gather permissions through direct assignment or bundle inheritance. The testing domain (subjects, exams, questions, choices, attempts, and answers) is similarly structured, using CHECK constraints to enforce valid status values, positive timer values, and non-negative scores directly in the database.

Figure 3.1: Entity-Relationship Diagram


3.5 Class Diagram — Composed RBAC

Figure 3.2 details the core access-control design. AuthorizationService.get_user_permissions() calculates a user's active permissions by combining two paths: direct grants (Role → Permission via role_permissions) and bundle grants (Role → PermissionBundle → Permission via role_bundles and bundle_permissions). Roles can use either path or combine both as needed.

Figure 3.2: Composed RBAC Class Diagram

3.6 Class Diagram — Examination Domain

The grading subsystem uses the Strategy and Factory design patterns. Each supported question format (single choice, true/false, multiple choice) implements a shared QuestionGrader interface, retrieved dynamically via GraderFactory. This structure simplifies extending the platform with new question types without altering existing grading routines.

Figure 3.3: Examination Domain and Grading Strategy Class Diagram

3.7 System Architecture

The application uses a standard layered layout where components only interact with the layer directly below them. Routes delegate logic to services, and services use repositories for data access. This structure keeps AuthorizationService independent of HTTP contexts, making unit testing straightforward.

Figure 3.4: Layered System Architecture

Chapter 4: Implementation

4.1 Package Structure

The codebase follows the layered architecture described in Section 3.7. Templates are further split by role (admin, teacher, student) to keep each portal's presentation logic isolated.

Infographic diagram representing the app directory structure in a visual, modular layout showing models, domain, repositories, services, routes, templates, and static directories.

4.2 Key Classes, Services, and Repositories

Table 4.1 summarizes the primary service and repository classes referenced in the class diagrams of Section 3.5 and 3.6. Full method-level detail is provided in Appendix A.

Class

Layer

Responsibility

AuthorizationService

Service

Resolves effective permissions (direct + composed) and enforces access via @require_permission

RoleService / PermissionService / BundleService

Service

CRUD and guarded deletion for roles, permissions, and permission bundles

ExamService / QuestionService

Service

Exam lifecycle (draft → published → closed) and question authoring, enforcing ownership

AttemptService

Service

Starts/resumes attempts, saves answers, submits, and triggers grading

ResultService

Service

Builds per-attempt and per-exam Result read-models, including CSV export

RoleRepository / PermissionRepository / BundleRepository

Repository

Persistence and lookup for RBAC entities

ExamRepository / AttemptRepository

Repository

Persistence and availability queries for exams and attempts


4.3 Interface Screenshots

4.3.1 Administrator Portal

The administrator portal provides full lifecycle management for permissions, roles, and permission bundles, directly exercising the Composed RBAC design from Chapter 3.

Figure 4.1: Permission Registry (create, edit, guarded delete)

Figure 4.2: Role Management (direct permissions and attached bundles)

Figure 4.3: Permission Bundles (composed capability groups)

4.3.2 Teacher Portal

The teacher dashboard presents authored-exam KPIs and candidate performance analytics, backed by TeacherDashboardService.

Figure 4.4: Instructor Dashboard

4.3.3 Student Portal

The student portal lists available examinations (filtered by AuthorizationService independent business rules: publication status, attempt window, and remaining attempts) and presents results and progress analytics.

Figure 4.5: Available Examinations

Figure 4.6: My Results Dashboard


Chapter 5: Testing and Results

5.1 Testing Strategy

System testing combined three approaches: (1) automated unit and integration tests using Python's unittest module to check business logic and endpoint permissions; (2) manual browser checks on a local development server to test template rendering and CSRF protection (which are disabled during automated test runs); and (3) exploratory testing across user roles to uncover edge cases missed by automated scripts (Section 5.4).

The test suite grew iteratively alongside defect discovery rather than being written upfront and left static, as shown in Table 5.1.

Milestone

Test Count

Result

Initial teacher / student refinement

249

249 / 249 passing

After student dashboard fixes

253

253 / 253 passing

After student portal boolean fix

256

256 / 256 passing

After Composed RBAC implementation

270

270 / 270 passing

After CSRF regression coverage

273

273 / 273 passing


5.2 Notable Defects Identified and Resolved

The following examples illustrate the testing and debugging process. Each issue was investigated to determine the root cause, resolved in code, and followed by a regression test to prevent recurrence.

Defect 1: Alpine.js Component Crash from Unescaped JSON in an HTML Attribute

Symptom

The teacher exam list rendered zero rows despite the database containing valid exam records.

Root Cause

A Jinja {{ stats|tojson }} expression was interpolated inside a double-quoted x-data="..." HTML attribute. The JSON's internal double quotes prematurely terminated the attribute, corrupting the markup and causing a fatal Alpine.js SyntaxError on page load, preventing all x-show directives — including those controlling table row visibility — from evaluating.

Fix

Moved the JSON payload out of the reactive attribute into a data-* attribute, avoiding raw JSON inside a quoted HTML attribute.

Regression Test

An integration test asserting the response body contains each exam's title, rather than only asserting HTTP 200 — the latter would not have caught this defect, since the server-rendered HTML was syntactically correct and the failure occurred entirely client-side.


Defect 2: Boolean Identity Check Failing on Integer-Valued Fields

Symptom

Dashboards reported 0 passed exams and a 0.0% average score for students and teachers with genuinely passing, graded attempts.

Root Cause

Several service methods used “if value is True” / “is False” identity comparisons rather than truthy evaluation. Python's “1 is True” evaluates to False, so integer 1 values returned by the database for a boolean column silently failed the check.

Fix

Replaced identity checks with normalized boolean coercion across StudentDashboardService, TeacherDashboardService, and ResultService, including an independent CSV-export code path with the same defect.

Regression Test

A dedicated test constructing a record with passed = 1 (not True) and asserting it is correctly counted — reproducing the exact failure condition rather than testing with an already-boolean value.


Defect 3: Implicit Role Inference via Unrelated Permission Checks

Symptom

A design issue identified during code review: several service methods checked administrative privileges using proxy checks like has_permission(user, "system.view") OR has_permission(user, "user.manage").

Root Cause

The system lacked a single permission explicitly representing administrative portal access, relying instead on unrelated functional permissions.

Fix

Introduced an explicit admin.access permission, attached it to the admin role and the admin_suite bundle, and replaced all proxy checks with a direct capability check.

Regression Test

A test asserting that a user holding only system.view or only user.manage — without admin.access — is now correctly blocked from previously-proxied routes, proving the old logic was fully removed rather than merely supplemented.


Defect 4: Missing CSRF Token on Dynamically Added Delete Forms

Symptom

Deleting a custom permission, role, or bundle through the browser returned HTTP 400 (“The CSRF token is missing”), while all related automated tests passed.

Root Cause

The delete-action forms for these three admin views were hand-written raw HTML forms and did not include a CSRF hidden input, unlike the project's WTForms-based forms, which include this automatically. The defect was invisible to the automated test suite because CSRF enforcement is disabled in the testing configuration.

Fix

Added the missing csrf_token hidden input to all three forms, following a full codebase audit confirming no other form across admin, teacher, and student templates had the same gap.

Regression Test

New integration tests running with CSRF explicitly enabled, which parse the actual rendered HTML to extract a real token, then assert deletion fails without it and succeeds with it.


Defect 5: False-Positive Failure from Confirmation Dialog Behavior

Symptom

After Defect 4 was fixed, manual testing still appeared to show delete buttons “not working.”

Root Cause

Not a code defect. Each delete button used onsubmit="return confirm(...)"; if the native browser confirmation dialog was dismissed or interrupted before being explicitly accepted, form submission was correctly and silently blocked by the browser itself.

Resolution

No code change required. Retained here as a methodological finding: it illustrates the importance of precisely reproducing a defect — including exact user interaction steps — before attempting a fix.

5.3 Security and Access-Control Verification

In addition to functional testing, the authorization layer underwent unauthorized access testing to verify endpoint protections directly. Since hiding UI elements is insufficient for security, these tests sent direct HTTP requests to verify that backend endpoints properly block unauthorized actions regardless of client interface controls.

Boundary Test

Result

Teacher account attempting all 12 admin-only routes

Blocked (403) on all 12

Student account attempting all 12 admin-only routes

Blocked (403) on all 12

Student account attempting all 17 teacher-only routes

Blocked (403) on all 17

Anonymous requests to all 29 protected routes

Redirected (302) on all 29

Total boundary leaks detected

0


5.4 Discussion: Limitations of Automated Testing Observed in This Project

Development highlighted two important testing observations. First, automated suites can pass completely while user-facing bugs remain present (as seen in Defects 1 and 4). These gaps stemmed from test environment settings, such as checking response status codes instead of page content or disabling CSRF validation in test runs. To address this, later test updates focused on rendered output assertions and CSRF-enabled integration runs. Second, Defect 5 showed that perceived bugs can sometimes stem from unexpected user interaction behavior rather than application logic, proving the value of reproducing exact browser steps before modifying code.

5.5 Performance and Security Notes

  • Password storage uses bcrypt with per-password salting; raw passwords are never logged or persisted.

  • Login is rate-limited by email and client IP to mitigate brute-force credential attacks.

  • All state-changing requests (POST) are protected by Flask-WTF CSRF tokens, verified across all three admin RBAC management views following Defect 4.

  • Permission and role changes take effect on the very next request with no caching layer, eliminating a class of "stale privilege" bugs common in systems that cache authorization state in the session.

  • Database-level CHECK constraints (e.g. on exam status, attempt count, and score ranges) provide a defense-in-depth layer independent of application-level validation.

5.6 Demonstration Summary

End-to-end functionality was verified across all three user roles on a live development instance. As Administrator, custom permissions, roles, and bundles were created, edited, and removed, while system-default entities remained protected against deletion. As Teacher, an examination was created, populated with questions, published, and evaluated via score reports. As Student, published tests were taken within time limits, with results accurately recorded on the student dashboard.

Chapter 6: Conclusion and Future Work

6.1 Summary

This project implemented a Composed RBAC authorization framework within an online examination system. The platform resolves user privileges by combining direct permission grants with reusable Permission Bundles, enforced through a normalized database schema and a centralized AuthorizationService. Endpoint testing confirmed server-side enforcement across all 14 system permissions, with boundary tests showing no unauthorized access leaks. The development process documented in Chapter 5 helped refine both application features and system security controls.

6.2 Limitations

  • The composition model supports permission bundling but does not implement role inheritance (a role extending another role's full permission set); this was a deliberate scope decision to keep the authorization model focused and defensible rather than open-ended.

  • Resource-level ownership (for example, confirming a specific exam belongs to the requesting teacher) is enforced procedurally within service methods rather than being modeled as part of the authorization layer itself — a deliberate separation-of-concerns decision, but one that means ownership rules are not centrally auditable the way role/permission rules are.

  • There is no persistent audit trail (database-backed log) of who modified which role, permission, or bundle and when; changes are currently logged only to the application's runtime log.

  • The system currently supports only objective question types (single-choice, true/false, multiple-choice); free-text or essay questions requiring manual grading are not supported.

6.3 Lessons Learned

A key takeaway from development is that a fully passing test suite does not guarantee the absence of bugs. Early automated tests missed UI and configuration issues because they checked HTTP status codes rather than page contents and ran with CSRF protections disabled. Updating integration tests to validate rendered template output and test with active security settings proved essential for catching subtle interface and request handling issues.

6.4 Future Improvements

  1. Implement role inheritance (e.g. a role that extends another role's full permission and bundle set) to further reduce configuration duplication for closely related roles.

  2. Introduce a persistent, queryable audit log for all RBAC mutations (permission, role, and bundle changes), recording the acting administrator, timestamp, and before/after state.

  3. Extend the authorization layer to support resource-scoped permission checks natively (e.g. has_permission_on_resource), rather than handling ownership procedurally in each service.

  4. Support additional question types requiring manual or semi-automated grading (short answer, essay), extending the existing QuestionGrader strategy hierarchy.

  5. Add proctoring and integrity features (e.g. tab-switch detection, timed lockdown) which were explicitly excluded from this project's scope.


Slide Presentation.pdf
PDF ឯកសារ
ទាញយក អាន
ចែករំលែក
រក្សាទុក
ការផ្សព្វផ្សាយ
ការផ្សព្វផ្សាយ
មតិយោបល់ 0
ចូលគណនី ដើម្បីបញ្ចេញមតិ