Implement Access Control: accounts, login and roles (2.1)

Open
#86 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
12/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
flask, python

Research direction

Start with the open decisions (role permission table, session length, password rule, failed sign-in limits) and get them settled before any code. The payload names backend/black_boxes/password_hashing/, backend/services/access_control/ (permissions.py, access_control_service.py), the Application Controller from #50, UserStore.store and User.to_dict(). Done means the checklist holds: every route except POST /api/login returns 401 when signed out, refused actions return 403 and are logged, and app_user stores only Argon2id hashes.

Written by the indexing model from the issue text.

Description

backend Low Priority Parent task

What to do

Build Access Control (2.1, OOD AccessControlService) so nobody can see or change network data without signing in, and each user can only do what their role allows. Hash passwords with Argon2id (BB-5), sign users in and out with a secure session, check the role on every request in the Application Controller, add a login screen, and let an admin manage accounts. Every other M4 feature (device edits, trust/flag, reference data, backup from the UI) relies on this to know who is acting and whether they may.

Background

  • Spec: SEC-01 (sign in before seeing or changing data), SEC-02 (secure password hashing), SEC-03 (access by role), SEC-07, SEC-08, SEC-09, SEC-10, POL-01, POL-03, POL-04, CP-01, CP-02, CM-11, IN-11
  • System design: 6.1 (AccessControlService; the Application Controller checks access and routes), 11.2 (session cookie Secure, HttpOnly, SameSite=Strict; salted Argon2id; checkPermissions() → authorizeAction() → hasRole()), 12 (argon2-cffi for BB-5; Flask's built-in sessions), acceptance tests AT-13 and AT-14
  • OOD: AccessControlService.authenticateUser(), authorizeAction(), verifyRole(); User.hasRole(role); ApplicationController.checkPermissions()
  • Already done (#17): the User record with UserRole (admin, editor, viewer) and AccountStatus (active, disabled), the app_user table, and UserStore.find / find_by_username / store (audited) / create_first_user. User.to_dict() already drops password_hash.

Decisions needed (before subtask 2 starts)

  • What each role may do. Proposal:

    Action viewer editor admin
    View devices, scans, evidence and reports; search and filter ✓ ✓ ✓
    Export JSON ✓ ✓ ✓
    Start a scan ✓ ✓
    Add, edit and delete devices; mark trusted or flagged ✓ ✓
    Add, edit and retire reference data (vendors, signatures, types) ✓ ✓
    Alert settings ✓
    Backup and restore (SEC-10) ✓
    Manage user accounts ✓
    View the audit log ✓
  • Session length. Proposal: signed out after 30 minutes without activity, and after 8 hours in any case.

  • Password rule. Proposal: 12 to 128 characters, and not the same as the username. No "must contain a symbol" rules (NIST SP 800-63B: length matters more). The upper limit stops someone sending a huge password to slow the server down.

  • Failed sign-ins. Proposal: after 5 wrong passwords for one username within 15 minutes, that username can't sign in for 15 minutes. Kept in memory; it resets if the server restarts.

Rules for every subtask

  • Deny by default. Every API route states which permission it needs. A route that states none fails a test instead of being open. Only POST /api/login works signed out.
  • The server decides. Hiding a button in the UI is only for convenience; the server checks the role on every request (SEC-09).
  • The session cookie holds only the user id, signed by Flask with SECRET_KEY from .env. The user is loaded again on every request, so a role change or a disabled account takes effect at once.
  • Passwords and hashes never leave the backend: not in API responses, logs, audit entries or exports (POL-03, POL-04, SEC-08). Use User.to_dict().
  • One message for a failed sign-in: "Username or password is incorrect." for both an unknown username and a wrong password, so the login page can't be used to find out which usernames exist.
  • Refused actions are logged (AT-13): who, which action and when, in the application log. Never the password.
  • Account changes go through UserStore.store, so each one is audited with the admin who made it (POL-02).
  • The leaves (BB-5, permissions, sign-in) contain no Flask code, and their unit tests need no database or browser.

Where the code goes

  • backend/black_boxes/password_hashing/ (BB-5)
  • backend/services/access_control/: permissions.py, access_control_service.py
  • The Application Controller from #50 (sessions and route protection)
  • frontend/app/src/ (login screen, sign-in state)
  • requirements.txt: argon2-cffi

Subtasks (in order)

  1. Password hashing (BB-5)
  2. Roles and permissions (2.1)
  3. Sign in and account rules (2.1)
  4. Sessions and route protection in the Application Controller (2.0)
  5. Login screen and signed-in layout
  6. Manage user accounts (admin)

Subtasks 1 and 2 can be worked on at the same time. 3 needs 1. 4 needs 2, 3 and #50. 5 needs 4. 6 needs 4 and 5.

Done when

  • Opening the app signed out shows the login screen, and every API route except POST /api/login answers 401
  • A viewer can browse, but every change (start a scan, edit a device, reference data, backup) is refused with 403 and logged (AT-13)
  • app_user holds only Argon2id hashes (AT-14)
  • Signing out, 30 minutes without activity, or an admin disabling the account ends the session
  • A scan records the signed-in user who started it (CM-11)
  • No API response, log line, audit entry or export contains a password or a hash
  • All unit tests pass without a database or browser

Depends on

  • Accounts and settings data access (#17): done
  • Application entry point and Application Controller (#50), for subtask 4
  • Scan and device API endpoints (#51) and the React app from the scan screen (#52), for subtasks 4 and 5

Blocks

Device add/edit/delete and trust/flag, the reference data screens, backup and restore from the UI, and edit conflict detection (M5). All of them need to know who is acting.

Dominant language
Python
Stars
1
Forks
1
Avg merge
9h 31m
Merged PRs (30d)
36

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Bearkat-Professionals/Software-Engineering-Project

All issues in Bearkat-Professionals/Software-Engineering-Project

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.