Files
huntingclubroster/AUTHENTICATION.md
T
2026-10-18 19:27:17 -04:00

8.9 KiB
Raw Blame History

Authentication changes and deployment

Login, signup, password changes, and password reset now use classes/AuthService.php. The existing PHP/XSL presentation structure is retained. Signup creates an active User account; it does not grant administrator access or club membership.

Before using this version against your database

  1. Back up the database and use a maintenance window for the schema update.
  2. Use 64-bit PHP 8.3 or newer. Run composer install and composer check-platform-reqs with the same PHP configuration used by the web server.
  3. Configure database and SMTP settings as described below.
  4. From the project directory, run php bin/migrate-auth.php once. It is safe to rerun. It adds the session version, password reset storage, rate limit storage, and refreshes view_users. It preserves accounts and password hashes. MySQL schema changes may briefly lock tables; this is not a web-request migration.
  5. Serve the site over HTTPS and verify the private-directory blocking rules.
  6. Test delivery of a reset email to an account you control.

The migration expects the schema in tables/users.php, including user_password_hash, user_status, and user_last_login. It refuses to continue if those fields are missing. Do not rebuild the database to fix an older schema; map and migrate its existing account fields while preserving the data.

On October 18, 2026, the migration was applied to the configured development database, 192.168.1.190/huntingclubroster, after a complete backup was restored and checked locally. Existing account data and original table row counts were preserved. Signup, login, logout and password reset were verified using the local application against that database; the SMTP provider accepted a real test reset email over TLS. The temporary account and restored database copy were removed. The public hostname did not resolve from the verification machine, so these results do not confirm deployment or operation of the public site. See database verification for the backup and results.

Settings

Your existing settings were preserved in ignored xml/settings.local.xml. The tracked xml/settings.xml now contains no credentials. Settings are loaded in this order: HCR_SETTINGS_FILE, local settings if present, then tracked defaults. Environment variables override individual fields:

Variable XML field
HCR_ENVIRONMENT Environment
HCR_DB_HOST DatabaseServer
HCR_DB_PORT DatabasePort (default 3306)
HCR_DB_NAME DatabaseName
HCR_DB_USER DatabaseUser
HCR_DB_PASSWORD DatabasePassword
HCR_SMTP_HOST SmtpServer
HCR_SMTP_PORT SmtpPort
HCR_SMTP_USER SmtpUserName
HCR_SMTP_PASSWORD SmtpPassword
HCR_SMTP_FROM SmtpFromEmail (defaults to SMTP username)
HCR_APPLICATION_URL ApplicationUrl

The configured application URL is https://app.myhuntingclubroster.com. It must be the trusted HTTPS application directory, without /main.php, a query string, or a fragment. Request Host headers are never used to construct email links. SMTP uses implicit TLS on port 465 and required STARTTLS on other ports, including 587. Certificate verification remains enabled. The sender must be authorized by your SMTP provider. For production, use an external settings file outside the document root or environment variables and set Environment to Production. Production requests require the web server to set HTTPS=on. If TLS terminates at a reverse proxy, configure that mapping in the web server; the application does not trust arbitrary forwarded headers.

Moving credentials out of tracked files does not remove them from Git history. Rotate the previously committed database/SMTP credentials, webhook, and any account still using the former hardcoded initial administrator password.

Behavior and protections

  • Login accepts the email shown by the form, with username compatibility. SQL uses bound parameters. Passwords use PHP's password hashing API.
  • Signup validates names, email, username, duplicate accounts, password length, and confirmation on the server. Privilege fields submitted by the browser are ignored. New passwords must be 12–72 bytes to avoid bcrypt truncation.
  • Password reset emails contain 256-bit random links. Only token hashes are stored; links expire after 30 minutes. Completing a reset consumes every outstanding token for that account inside a transaction. Requesting a reset does not change the password. Failed email delivery removes the unsent token.
  • Reset requests return the same public message for unknown, inactive, throttled, and undeliverable accounts. Delivery errors go to the server log.
  • Password changes require the current password and matching confirmation. Successful changes and resets revoke all old sessions. Administrator role and status changes also revoke sessions. Account status and privileges are checked against the database on each authenticated request.
  • Sessions rotate on login/logout, expire after 30 idle minutes, and use HttpOnly/SameSite cookies plus Secure cookies on HTTPS.
  • CSRF checks cover public authentication forms and authenticated POST actions. Existing application forms and same-origin AJAX requests receive the token.
  • Database-backed limits apply across new cookies: 10 login attempts per account and 50 per IP in 15 minutes; 3 reset emails per account and 10 per IP per hour; 5 signup attempts per IP per hour. Reset submissions and password changes are limited separately.
  • Routing uses an explicit allowlist. Administrative screens, account editing, resets for other users, and destructive maintenance actions require an administrator role on the server. General helper methods are not endpoints. System administrator names in the old settings file no longer override the role stored in the database.
  • Errors are logged without recursively opening a database connection or emailing from the error handler. Visitors receive a generic failure message.

Run php bin/cleanup-auth.php daily using your normal server scheduler to remove expired reset tokens and old rate-limit rows. No scheduler was installed here. Exclude query strings containing reset tokens from retained access/analytics logs where your hosting supports it.

Hosting and setup scripts

Apache .htaccess and IIS web.config block private application directories. Apache needs the rewrite module and permission to apply these rules. On Nginx, configure equivalent denies for xml, classes, vendor, tables, views, bin, migrations, tests, reports, nbproject, and hidden files. Verify that /xml/settings.local.xml and setup scripts cannot be downloaded or executed. The production web server configuration has not been exercised by local tests.

Setup scripts also refuse HTTP execution independently. The system rebuild is disabled unless HCR_ALLOW_REBUILD=yes; it requires a unique HCR_INITIAL_ADMIN_PASSWORD of 12–72 bytes before doing any rebuilding. It is destructive and is not the authentication migration.

For local development only: php -S 127.0.0.1:8080 bin/dev-router.php. This router serves the entry point and static assets while denying private files. Set the environment to Development for plain HTTP development. Never use PHP's built-in server for production.

Dependencies and verification

Composer requirements now explicitly declare the PHP version and authentication extensions. PhpSpreadsheet was upgraded from 5.2.0 to 5.10.0 after the dependency audit found advisories. Compatible ZipStream and Composer PCRE dependencies were updated, and the lock file and installed autoloader were synchronized. Existing auxiliary TCPDF library files were preserved. Composer reported no known dependency security advisories after the update.

tests/auth_integration.php creates and drops a randomly named database on the server explicitly supplied by HCR_TEST_DSN, HCR_TEST_USER, and HCR_TEST_PASSWORD. It never reads the application's database credentials. Run php tests/auth_integration.php (or composer test:auth). The test server account needs permission to create and drop databases. Use an isolated server.

tests/auth_http.py runs the real forms against a temporary PHP development server and disposable database. Supply the same test variables plus HCR_DB_HOST, HCR_DB_PORT, HCR_DB_USER, and HCR_DB_PASSWORD for that isolated server. PHP_TEST_COMMAND can hold a JSON argument list for a PHP executable and extension options; it defaults to ["php"]. Run python tests/auth_http.py. Email delivery is disabled in HTTP tests; the service tests capture reset emails and simulate transport failure. Tests cover schema migration, signup/login, validation, SQL injection input, CSRF, authorization, token expiry/reuse, throttling, session revocation, logout, and rendering.

A wider review of unrelated roster/reporting logic and deployment penetration testing are outside this authentication change.