A corporate portal built with Python (Flask), Keycloak for authentication, and PostgreSQL for persistence. Supports role-based access, user management, logging, and is ready for containerized deployment.
- Keycloak-based authentication (OIDC)
- Role-based access control (admin/user via Keycloak groups)
- PostgreSQL persistence with SQLAlchemy
- Configurable session timeout
- Comprehensive logging system
- User action logging
- Access logging
- Log rotation and cleanup
- Log export functionality
- Security Features
- Rate limiting
- IP whitelist/blacklist
- CIDR-based access control
- Session management
- Admin Panel Features
- User management (create, edit, delete)
- Group management with attributes
- Bulk user import via CSV
- Application management
- Announcement system
- Log viewing and management
- User Features
- Theme toggling (light/dark)
- Customizable user profile
- Language selection
- Application launcher
- System Features
- Health check endpoint with API key and IP restriction
- Docker support
- Multi-language support
- Customizable portal icon (favicon) via Settings page (supports PNG, JPG, SVG)
-
Clone the repository
-
Set up your environment variables (see Environment Variables section)
-
Create and activate a Python virtual environment
python -m venv venv source venv/bin/activate # or venv\Scripts\activate on Windows pip install -r requirements.txt
-
Run the application (development mode)
python server.py
The main entry point is
server.py, which uses Waitress by default. -
Or run with Docker
docker build -t leonardo-portal . docker run --env-file .env -p 3000:3000 leonardo-portal -
⚠️ IMPORTANT: After First Login- After the first login, you MUST go to the Settings page, navigate to the "System" tab
- Click the "Sync Now" button to synchronize Keycloak groups and memberships
- This step is CRITICAL - without it:
- Users won't be properly linked to their groups in the portal
- Applications won't be displayed correctly
- Existing users' permissions may not work as expected
Note: If applications are not showing up for some users despite them being in the correct groups, clicking "Sync Now" in the System Settings will re-synchronize users and groups with Keycloak.
All configuration is managed via environment variables. You can set these in your environment or in a .env file at the project root.
| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
change-this-secret |
Flask session secret key |
DB_HOST |
127.0.0.1 |
PostgreSQL host |
DB_PORT |
5432 |
PostgreSQL port |
DB_NAME |
leonardoportal |
PostgreSQL database name |
DB_USER |
dbuser |
PostgreSQL user |
DB_PASSWORD |
dbpassword |
PostgreSQL password |
KEYCLOAK_SERVER_URL |
http://127.0.0.1:8080 |
Keycloak server URL |
KEYCLOAK_REALM |
myrealm |
Keycloak realm name |
KEYCLOAK_CLIENT_ID |
myclient |
Keycloak client ID |
KEYCLOAK_CLIENT_SECRET |
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Keycloak client secret |
SMTP_HOST |
smtp.gmail.com |
SMTP server for email |
SMTP_PORT |
587 |
SMTP server port |
SMTP_USER |
john.doe@gmail.com |
SMTP username |
SMTP_PASSWORD |
jd123 |
SMTP password |
EMAIL_FROM |
john.doe@gmail.com |
Default sender email |
FLASK_ENV |
production |
Flask environment (production/development) |
FLASK_DEBUG |
0 |
Enable Flask debug output (0/1) |
HEALTH_ALLOWED_IPS |
127.0.0.1,::1 |
Comma-separated list of IPs allowed to access /health |
HEALTH_API_KEY |
your-api-key-here |
API key required for /health endpoint |
PORTAL_USER_GROUP |
portal-user |
Keycloak group name for regular users |
PORTAL_ADMIN_GROUP |
portal-admin |
Keycloak group name for admins |
FLASK_PORT |
3000 |
Port for Flask app to listen on |
SESSION_LIFETIME |
60 |
Session lifetime in minutes |
CIDR_WHITELIST |
127.0.0.1/24,192.168.1.1/24,::1/128,2001:db8::/32 |
Comma-separated list of allowed CIDR blocks |
CIDR_BLACKLIST |
(empty) | Comma-separated list of blocked CIDR blocks |
MAX_REQUESTS |
100 |
Max requests per window (rate limiting) |
WINDOW_SIZE |
60 |
Window size in seconds for rate limiting |
SERVER_TYPE |
waitress |
Server type: waitress (dev) or gunicorn (prod) |
GUNICORN_WORKERS |
4 |
Number of Gunicorn workers (if using Gunicorn) |
- The session timeout is controlled by
SESSION_LIFETIME(in minutes). Set this in your environment or.envfile to control how long user sessions remain valid.
- The app uses PostgreSQL. Ensure your database is running and accessible with the credentials provided in your environment variables.
- You must configure a Keycloak client and groups as described in
docs/keycloakconfig.md.
The application includes comprehensive test coverage:
# Run all tests
pytest
# Run with coverage report
pytest --cov=app tests/
# Run specific test categories
pytest tests/test_auth.py
pytest tests/test_admin.py- Unit tests
- Integration tests
- Selenium-based UI tests
- API endpoint tests
The portal supports multiple languages:
- English (default)
- German
- Spanish
- French
- Italian
- Dutch
- Portuguese
To add a new language:
- Create a new directory under
app/translations/ - Generate translation files using Flask-Babel
- Update the language selection in user preferences
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests
- Submit a pull request
Please follow the existing code style and include appropriate tests.
MIT License
Copyright (c) 2025 Leonardo Portal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
For production deployment, follow these additional steps:
-
Use Gunicorn instead of Waitress
export SERVER_TYPE=gunicorn export GUNICORN_WORKERS=4 # Adjust based on your server capacity
-
Set up SSL/TLS
- Configure your reverse proxy (nginx/Apache) with SSL
- Update Keycloak configuration to use HTTPS
- Set appropriate security headers
-
Database Configuration
- Use a dedicated PostgreSQL instance
- Set up proper database backups
- Configure connection pooling (see .env.example for pool settings)
- Set a query timeout at the PostgreSQL level (see installation guide for details)
-
Portal Icon (Favicon)
- The favicon is dynamically set to the uploaded portal icon (PNG, JPG, or SVG) from the Settings page, System tab.
- If no icon is uploaded, a default icon is used.
-
Security Considerations
- Change all default passwords and keys
- Set up proper firewall rules
- Configure rate limiting appropriately
- Use secure SMTP settings
- Regular backups are recommended
- Log cleanup runs automatically based on
LOG_RETENTION_DAYS - Database migrations are managed through SQL scripts in
app/scripts/sql/