Skip to content

Refactor the authorization logic - #3

Open
JanciP wants to merge 1 commit into
Azrael3000:mainfrom
JanciP:authRefactor
Open

Refactor the authorization logic#3
JanciP wants to merge 1 commit into
Azrael3000:mainfrom
JanciP:authRefactor

Conversation

@JanciP

@JanciP JanciP commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

The admin interface was "protected" by a 6 character token in the URL (?auth=XXXXXX, the first 6 characters of FLASK_SECRET_KEY): 24 bits that leaked the cookie-signing secret into browser history, logs and screenshots, with no rate limit. Worse, only the admin HTML page checked it — every mutating endpoint (competition delete, uploads, athletes, judges, start lists, results, publish) was completely unauthenticated, and PUT /result accepted forged judge hashes, so anyone on the venue network could rewrite or delete a competition without ever seeing the admin page.

Backend:

  • New session-based login: /admin/login (GET form, POST check) and /admin/logout. The password comes from .env — FLASK_ADMIN_PASSWORD_HASH (a werkzeug hash, recommended for deployments) or plain FLASK_ADMIN_PASSWORD; if neither is set, admin login is disabled and an error is logged at startup. Comparisons are constant time, failed attempts are throttled (1s) and logged with the remote address.
  • An admin_required decorator now guards every admin endpoint; /admin redirects to the login form, api endpoints return 401. Public pages (results, clock) and the hash-validated judge pages are unchanged.
  • PUT /result accepts either an admin session or valid judge credentials; the judge hash is now actually validated, so forged hashes are rejected.
  • The session cookie is HttpOnly and SameSite=Lax (basic CSRF protection) and lives 12 hours, so one login covers a competition day. SECRET_KEY is back to its one job: signing that cookie.

Frontend:

  • New login page (templates/login.html), a Logout link in the admin nav, and a global ajax handler in compy.js that sends the user to the login page whenever an api call returns 401 (expired or missing session).

Docs:

  • .env_sample and Readme document the new password settings, including the one-liner to generate a password hash for deployments.

Tests:

  • compy_testing.py provides an adminSession() helper; the concurrency test logs in its admin pages while clock, judge and public results pages run unauthenticated. New tests: admin endpoints reject anonymous requests, wrong passwords are rejected, judge phones can save results without an admin session, forged judge hashes cannot. The robot suite logs in through the form instead of using the auth URL parameter.

The admin interface was "protected" by a 6 character token in the URL
(?auth=XXXXXX, the first 6 characters of FLASK_SECRET_KEY): 24 bits that
leaked the cookie-signing secret into browser history, logs and screenshots,
with no rate limit. Worse, only the admin HTML page checked it — every
mutating endpoint (competition delete, uploads, athletes, judges, start
lists, results, publish) was completely unauthenticated, and PUT /result
accepted forged judge hashes, so anyone on the venue network could rewrite
or delete a competition without ever seeing the admin page.

Backend:

* New session-based login: /admin/login (GET form, POST check) and
  /admin/logout. The password comes from .env — FLASK_ADMIN_PASSWORD_HASH
  (a werkzeug hash, recommended for deployments) or plain
  FLASK_ADMIN_PASSWORD; if neither is set, admin login is disabled and an
  error is logged at startup. Comparisons are constant time, failed
  attempts are throttled (1s) and logged with the remote address.
* An admin_required decorator now guards every admin endpoint; /admin
  redirects to the login form, api endpoints return 401. Public pages
  (results, clock) and the hash-validated judge pages are unchanged.
* PUT /result accepts either an admin session or valid judge credentials;
  the judge hash is now actually validated, so forged hashes are rejected.
* The session cookie is HttpOnly and SameSite=Lax (basic CSRF protection)
  and lives 12 hours, so one login covers a competition day. SECRET_KEY is
  back to its one job: signing that cookie.

Frontend:

* New login page (templates/login.html), a Logout link in the admin nav,
  and a global ajax handler in compy.js that sends the user to the login
  page whenever an api call returns 401 (expired or missing session).

Docs:

* .env_sample and Readme document the new password settings, including the
  one-liner to generate a password hash for deployments.

Tests:

* compy_testing.py provides an adminSession() helper; the concurrency test
  logs in its admin pages while clock, judge and public results pages run
  unauthenticated. New tests: admin endpoints reject anonymous requests,
  wrong passwords are rejected, judge phones can save results without an
  admin session, forged judge hashes cannot. The robot suite logs in
  through the form instead of using the auth URL parameter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant