83522ac52c
Updated the Teams Index and Printout components to prioritize sorting by EventFormat, enhancing the organization of team data. Introduced a regional filter toggle in the Teams Index to allow users to view only regional teams. Adjusted the ScheduledTeamsList to sort teams by EventFormat first, ensuring consistent ordering across components. Additionally, added necessary using directives for improved code clarity.
483 lines
14 KiB
Markdown
483 lines
14 KiB
Markdown
# Authentication Setup Guide
|
|
|
|
This guide explains how to configure login credentials for the TSA Chapter Organizer application. The application uses BCrypt password hashing and supports multiple authentication methods depending on your environment.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Available Roles](#available-roles)
|
|
- [Generating Password Hashes](#generating-password-hashes)
|
|
- [Development Setup](#development-setup)
|
|
- [Production Setup](#production-setup)
|
|
- [Managing Users](#managing-users)
|
|
- [Security Best Practices](#security-best-practices)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The TSA Chapter Organizer uses cookie-based authentication with BCrypt password hashing. User credentials are stored securely and never in plain text. The authentication system supports:
|
|
|
|
- **BCrypt password hashing** (work factor 11)
|
|
- **Case-insensitive email matching**
|
|
- **Role-based access control**
|
|
- **Rate limiting** (5 failed attempts result in 15-minute lockout)
|
|
- **Session management** (20 minutes default, 30 days with "Remember Me")
|
|
|
|
## Available Roles
|
|
|
|
The application supports two user roles:
|
|
|
|
- **Administrator** - Full access to all features
|
|
- **Advisor** - Standard user access
|
|
|
|
Roles are defined in `WebApp/Authentication/AuthRoles.cs` and can be customized if needed.
|
|
|
|
---
|
|
|
|
## Generating Password Hashes
|
|
|
|
Before setting up authentication, you need to generate BCrypt hashes for your passwords. The application provides a development endpoint for this purpose.
|
|
|
|
### Method 1: Development Endpoint (Recommended)
|
|
|
|
1. Start the application in **Development** mode
|
|
2. Navigate to: `https://localhost:<port>/dev/hash-password?password=YourPassword`
|
|
3. Copy the `hash` value from the JSON response
|
|
|
|
**Example:**
|
|
```
|
|
https://localhost:5001/dev/hash-password?password=MySecurePass123
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"password": "MySecurePass123",
|
|
"hash": "$2a$11$xyz123...",
|
|
"message": "Copy the hash value to your User Secrets configuration"
|
|
}
|
|
```
|
|
|
|
### Method 2: Programmatic (for automation)
|
|
|
|
You can also generate hashes programmatically using the `PasswordHashGenerator` class:
|
|
|
|
```csharp
|
|
using WebApp.Authentication;
|
|
|
|
var hash = PasswordHashGenerator.GenerateHash("YourPassword");
|
|
```
|
|
|
|
---
|
|
|
|
## Development Setup
|
|
|
|
For local development, the application uses .NET User Secrets to store authentication credentials securely.
|
|
|
|
### Prerequisites
|
|
|
|
- .NET SDK installed
|
|
- User Secrets ID configured in `WebApp.csproj` (already configured: `73972335-ec46-4ad6-a959-8ebe0b06147d`)
|
|
|
|
### Steps
|
|
|
|
1. **Generate password hashes** using the development endpoint (see above)
|
|
|
|
2. **Configure User Secrets** using the .NET CLI:
|
|
|
|
```bash
|
|
cd WebApp
|
|
|
|
# Set authentication configuration
|
|
dotnet user-secrets set "Authentication:Users:0:Email" "admin@example.com"
|
|
dotnet user-secrets set "Authentication:Users:0:PasswordHash" "$2a$11$your_hash_here"
|
|
dotnet user-secrets set "Authentication:Users:0:Role" "Administrator"
|
|
dotnet user-secrets set "Authentication:Users:0:DisplayName" "Administrator"
|
|
|
|
# Add additional users (increment the index)
|
|
dotnet user-secrets set "Authentication:Users:1:Email" "advisor@example.com"
|
|
dotnet user-secrets set "Authentication:Users:1:PasswordHash" "$2a$11$your_hash_here"
|
|
dotnet user-secrets set "Authentication:Users:1:Role" "Advisor"
|
|
dotnet user-secrets set "Authentication:Users:1:DisplayName" "Chapter Advisor"
|
|
```
|
|
|
|
3. **Verify your configuration**:
|
|
|
|
```bash
|
|
dotnet user-secrets list
|
|
```
|
|
|
|
4. **Run the application**:
|
|
|
|
```bash
|
|
dotnet run
|
|
```
|
|
|
|
5. **Login** at `https://localhost:<port>/login`
|
|
|
|
### Example: Complete Development Setup
|
|
|
|
```bash
|
|
# 1. Navigate to WebApp directory
|
|
cd WebApp
|
|
|
|
# 2. Generate hash (via browser or curl)
|
|
# Visit: https://localhost:5001/dev/hash-password?password=admin123
|
|
|
|
# 3. Configure admin user
|
|
dotnet user-secrets set "Authentication:Users:0:Email" "admin@myschool.edu"
|
|
dotnet user-secrets set "Authentication:Users:0:PasswordHash" "$2a$11$REPLACE_WITH_GENERATED_HASH"
|
|
dotnet user-secrets set "Authentication:Users:0:Role" "Administrator"
|
|
dotnet user-secrets set "Authentication:Users:0:DisplayName" "TSA Admin"
|
|
|
|
# 4. Configure advisor user (optional)
|
|
dotnet user-secrets set "Authentication:Users:1:Email" "advisor@myschool.edu"
|
|
dotnet user-secrets set "Authentication:Users:1:PasswordHash" "$2a$11$REPLACE_WITH_GENERATED_HASH"
|
|
dotnet user-secrets set "Authentication:Users:1:Role" "Advisor"
|
|
dotnet user-secrets set "Authentication:Users:1:DisplayName" "Chapter Advisor"
|
|
|
|
# 5. Verify
|
|
dotnet user-secrets list
|
|
|
|
# 6. Run
|
|
dotnet run
|
|
```
|
|
|
|
---
|
|
|
|
## Production Setup
|
|
|
|
For production environments (Docker, deployed servers), you have two options for configuring authentication credentials.
|
|
|
|
### Option 1: Volume-Mounted JSON File (Recommended)
|
|
|
|
This approach allows you to edit credentials without rebuilding the container.
|
|
|
|
#### Steps
|
|
|
|
1. **Generate Password Hashes** (on your development machine):
|
|
- Use the development endpoint or programmatic method
|
|
|
|
2. **Create `auth-secrets.json`** on your Docker host:
|
|
```bash
|
|
cp auth-secrets.example.json auth-secrets.json
|
|
```
|
|
|
|
3. **Edit `auth-secrets.json`** and replace the placeholder hashes:
|
|
```json
|
|
{
|
|
"Authentication": {
|
|
"Users": [
|
|
{
|
|
"Email": "admin@example.com",
|
|
"PasswordHash": "$2a$11$actual.hash.here",
|
|
"Role": "Administrator",
|
|
"DisplayName": "Administrator"
|
|
},
|
|
{
|
|
"Email": "advisor@example.com",
|
|
"PasswordHash": "$2a$11$actual.hash.here",
|
|
"Role": "Advisor",
|
|
"DisplayName": "Chapter Advisor"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
4. **Set proper file permissions**:
|
|
```bash
|
|
chmod 600 auth-secrets.json
|
|
chown root:root auth-secrets.json # Adjust user/group as needed
|
|
```
|
|
|
|
5. **Configure Docker Compose** (see `docker-compose.example.yml`):
|
|
```yaml
|
|
volumes:
|
|
- ./auth-secrets.json:/app/Data/auth-secrets.json:ro
|
|
```
|
|
|
|
6. **Update credentials**: Simply edit `auth-secrets.json` on the host and restart the container:
|
|
```bash
|
|
docker-compose restart webapp
|
|
```
|
|
|
|
**Security Note**: Never commit `auth-secrets.json` to version control. It should be in `.gitignore`.
|
|
|
|
### Option 2: Environment Variables
|
|
|
|
This approach is useful for container orchestration platforms (Kubernetes, Docker Swarm, etc.).
|
|
|
|
#### Docker Compose Example
|
|
|
|
```yaml
|
|
environment:
|
|
- TSA_Authentication__Users__0__Email=admin@example.com
|
|
- TSA_Authentication__Users__0__PasswordHash=$2a$11$hash...
|
|
- TSA_Authentication__Users__0__Role=Administrator
|
|
- TSA_Authentication__Users__0__DisplayName=Administrator
|
|
- TSA_Authentication__Users__1__Email=advisor@example.com
|
|
- TSA_Authentication__Users__1__PasswordHash=$2a$11$hash...
|
|
- TSA_Authentication__Users__1__Role=Advisor
|
|
- TSA_Authentication__Users__1__DisplayName=Chapter Advisor
|
|
```
|
|
|
|
#### Docker Run Example
|
|
|
|
```bash
|
|
docker run -d \
|
|
-p 8080:8080 \
|
|
-e ASPNETCORE_ENVIRONMENT=Production \
|
|
-e TSA_Authentication__Users__0__Email=admin@example.com \
|
|
-e TSA_Authentication__Users__0__PasswordHash='$2a$11$hash...' \
|
|
-e TSA_Authentication__Users__0__Role=Administrator \
|
|
-e TSA_Authentication__Users__0__DisplayName=Administrator \
|
|
tsa-chapter-organizer:latest
|
|
```
|
|
|
|
#### Kubernetes Secret Example
|
|
|
|
```yaml
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: tsa-auth-secrets
|
|
type: Opaque
|
|
stringData:
|
|
TSA_Authentication__Users__0__Email: "admin@example.com"
|
|
TSA_Authentication__Users__0__PasswordHash: "$2a$11$hash..."
|
|
TSA_Authentication__Users__0__Role: "Administrator"
|
|
TSA_Authentication__Users__0__DisplayName: "Administrator"
|
|
```
|
|
|
|
**Note**: Environment variable names use double underscores (`__`) to represent nested configuration paths, with the `TSA_` prefix.
|
|
|
|
---
|
|
|
|
## Managing Users
|
|
|
|
### Adding a New User
|
|
|
|
#### Development (User Secrets)
|
|
|
|
```bash
|
|
# Find the next available index (check existing users first)
|
|
dotnet user-secrets list | grep "Authentication:Users"
|
|
|
|
# Add new user (replace N with the next index)
|
|
dotnet user-secrets set "Authentication:Users:N:Email" "newuser@example.com"
|
|
dotnet user-secrets set "Authentication:Users:N:PasswordHash" "$2a$11$hash..."
|
|
dotnet user-secrets set "Authentication:Users:N:Role" "Advisor"
|
|
dotnet user-secrets set "Authentication:Users:N:DisplayName" "New User Name"
|
|
```
|
|
|
|
#### Production (JSON File)
|
|
|
|
1. Edit `auth-secrets.json` on the host
|
|
2. Add a new entry to the `Users` array:
|
|
```json
|
|
{
|
|
"Email": "newuser@example.com",
|
|
"PasswordHash": "$2a$11$hash...",
|
|
"Role": "Advisor",
|
|
"DisplayName": "New User Name"
|
|
}
|
|
```
|
|
3. Restart the container: `docker-compose restart webapp`
|
|
|
|
#### Production (Environment Variables)
|
|
|
|
Add new environment variables with the next index number and recreate the container.
|
|
|
|
### Changing a Password
|
|
|
|
1. **Generate a new password hash**:
|
|
- Development: Use `/dev/hash-password` endpoint
|
|
- Production: Generate on local dev machine
|
|
|
|
2. **Update the configuration**:
|
|
- **Development**: `dotnet user-secrets set "Authentication:Users:N:PasswordHash" "$2a$11$new_hash"`
|
|
- **Production (JSON)**: Edit `auth-secrets.json` and update the `PasswordHash` value
|
|
- **Production (Env Vars)**: Update the environment variable
|
|
|
|
3. **Restart the application**:
|
|
- Development: Restart the app (automatic on file change for User Secrets)
|
|
- Production: `docker-compose restart webapp`
|
|
|
|
### Removing a User
|
|
|
|
1. **Remove from configuration**:
|
|
- **Development**: Remove the User Secrets entries for that user index
|
|
- **Production (JSON)**: Remove the user entry from `auth-secrets.json`
|
|
- **Production (Env Vars)**: Remove the environment variables
|
|
|
|
2. **Restart the application**
|
|
|
|
**Note**: When removing users from JSON or environment variables, you may need to renumber remaining users' indices, or leave gaps (both approaches work).
|
|
|
|
---
|
|
|
|
## Security Best Practices
|
|
|
|
1. **Strong Passwords**: Use strong, unique passwords for each user. Consider using a password manager.
|
|
|
|
2. **File Permissions** (Production):
|
|
```bash
|
|
chmod 600 auth-secrets.json
|
|
chown root:root auth-secrets.json
|
|
```
|
|
|
|
3. **Never Commit Secrets**: Ensure the following are in `.gitignore`:
|
|
- `auth-secrets.json`
|
|
- `docker-compose.yml` (if it contains secrets)
|
|
- User Secrets files (automatically ignored by .NET)
|
|
|
|
4. **Use HTTPS in Production**: Always configure SSL/TLS certificates for production deployments.
|
|
|
|
5. **Backup Credentials Securely**: Store encrypted backups of `auth-secrets.json` in a secure location.
|
|
|
|
6. **Password Rotation**: Periodically regenerate password hashes and update credentials.
|
|
|
|
7. **Monitor Access**: Review application logs for failed login attempts:
|
|
```bash
|
|
docker-compose logs webapp | grep "Failed login"
|
|
```
|
|
|
|
8. **Limit Access**: Only grant Administrator role to trusted users. Use Advisor role for general access.
|
|
|
|
9. **Rate Limiting**: The application automatically enforces rate limiting (5 failed attempts = 15 minute lockout). Monitor logs for suspicious activity.
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Can't Login
|
|
|
|
1. **Verify configuration is loaded**:
|
|
- **Development**: Check User Secrets are configured: `dotnet user-secrets list`
|
|
- **Production**: Check if file is mounted: `docker exec tsa-app ls -la /app/Data/auth-secrets.json`
|
|
|
|
2. **Check JSON syntax** (if using JSON file):
|
|
```bash
|
|
cat auth-secrets.json | jq .
|
|
```
|
|
Or validate online using a JSON validator.
|
|
|
|
3. **Verify password hash**: Ensure the hash was copied completely (BCrypt hashes are ~60 characters)
|
|
|
|
4. **Check application logs**:
|
|
```bash
|
|
docker-compose logs webapp | grep -i "authentication\|login"
|
|
```
|
|
|
|
5. **Verify email is correct**: Email matching is case-insensitive, but ensure it matches exactly what you configured.
|
|
|
|
### Rate Limited / Locked Out
|
|
|
|
If you see "Too many failed attempts" error:
|
|
|
|
1. Wait 15 minutes for the lockout to expire
|
|
2. Or restart the container (resets rate limit tracking):
|
|
```bash
|
|
docker-compose restart webapp
|
|
```
|
|
|
|
### Forgot Admin Password
|
|
|
|
1. Generate a new password hash using the dev endpoint (on local dev machine)
|
|
2. Update `auth-secrets.json` (production) or User Secrets (development)
|
|
3. Restart the application
|
|
|
|
### No Users Configured Error
|
|
|
|
If you see "Authentication system not configured" or "No users configured":
|
|
|
|
1. **Development**: Verify User Secrets are set:
|
|
```bash
|
|
dotnet user-secrets list | grep Authentication
|
|
```
|
|
|
|
2. **Production**: Check that `auth-secrets.json` exists and is properly mounted:
|
|
```bash
|
|
docker exec tsa-app cat /app/Data/auth-secrets.json
|
|
```
|
|
|
|
3. Verify the JSON structure matches the expected format (see `auth-secrets.example.json`)
|
|
|
|
### Container Won't Start
|
|
|
|
Check logs for configuration errors:
|
|
```bash
|
|
docker-compose logs webapp
|
|
```
|
|
|
|
Common issues:
|
|
- JSON syntax error in `auth-secrets.json`
|
|
- File permissions preventing file access
|
|
- Missing required configuration values
|
|
|
|
---
|
|
|
|
## Example: Complete Production Setup
|
|
|
|
```bash
|
|
# 1. Generate password hash locally (in development)
|
|
# Visit: https://localhost:5001/dev/hash-password?password=SecurePass123
|
|
|
|
# 2. Create secrets file
|
|
cat > auth-secrets.json <<EOF
|
|
{
|
|
"Authentication": {
|
|
"Users": [
|
|
{
|
|
"Email": "admin@myschool.edu",
|
|
"PasswordHash": "$2a$11$paste_generated_hash_here",
|
|
"Role": "Administrator",
|
|
"DisplayName": "TSA Admin"
|
|
},
|
|
{
|
|
"Email": "advisor@myschool.edu",
|
|
"PasswordHash": "$2a$11$paste_generated_hash_here",
|
|
"Role": "Advisor",
|
|
"DisplayName": "Chapter Advisor"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
EOF
|
|
|
|
# 3. Set permissions
|
|
chmod 600 auth-secrets.json
|
|
|
|
# 4. Create docker-compose.yml (copy and customize from example)
|
|
cp docker-compose.example.yml docker-compose.yml
|
|
|
|
# 5. Ensure volume mount is configured in docker-compose.yml:
|
|
# volumes:
|
|
# - ./auth-secrets.json:/app/Data/auth-secrets.json:ro
|
|
|
|
# 6. Start the application
|
|
docker-compose up -d
|
|
|
|
# 7. Check it's running
|
|
docker-compose ps
|
|
curl http://localhost:8080
|
|
|
|
# 8. Login
|
|
# Navigate to http://localhost:8080/login
|
|
# Use configured credentials
|
|
```
|
|
|
|
---
|
|
|
|
## Additional Resources
|
|
|
|
- See `DEPLOYMENT.md` for Docker deployment details
|
|
- See `auth-secrets.example.json` for the expected JSON structure
|
|
- See `docker-compose.example.yml` for Docker Compose configuration examples
|
|
- Authentication implementation: `WebApp/Authentication/`
|
|
|
|
|