generated from jric11/baseProject
156 lines
8.9 KiB
Markdown
156 lines
8.9 KiB
Markdown
# 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](DATABASE-VERIFICATION.md) 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.
|