first commit

This commit is contained in:
2025-11-30 00:07:24 +01:00
commit b5e642aecb
78 changed files with 15162 additions and 0 deletions

79
docs/ARCHITECTURE.md Normal file
View File

@ -0,0 +1,79 @@
# Application Architecture
This document provides a detailed overview of the OIDC server's internal architecture. For a general overview, see the `README.md` file.
## 1. High-Level Overview
The application is a standard Flask web server that follows a monolithic architecture. It is designed to be run as a containerized service using Docker.
The main components are:
- **Flask Application (`oidc_server.py`)**: The core of the application, which handles all incoming requests, business logic, and OIDC flows.
- **Database (`models.py`)**: A PostgreSQL or SQLite database, managed by SQLAlchemy, that persists all data, including users, clients, tokens, and logs.
- **Configuration (`config.py` & `.env`)**: A flexible, environment-based configuration system for managing settings and secrets.
- **Templates (`templates.py` & `admin_templates.py`)**: In-memory HTML templates for rendering the user interface.
## 2. Configuration System
The application uses a layered configuration approach to separate concerns and keep secrets out of the codebase.
- **.env File**: This file (which is not committed to version control) is used to store all secrets and environment-specific settings. It is loaded at startup using `python-dotenv`.
- **`config.py`**: This file defines several configuration classes (`DevelopmentConfig`, `ProductionConfig`, `TestingConfig`) that inherit from a base `Config` class. It reads values from the environment (populated by the `.env` file) and sets sane defaults.
- **`oidc_server.py`**: At startup, the main application file reads the `FLASK_ENV` environment variable to determine which configuration class to load from `config.py`. This ensures that the correct settings (e.g., database URI, debug mode) are used for the environment.
## 3. Application Structure (`oidc_server.py`)
The main application file is responsible for:
1. **Initialization**:
- Creating the Flask `app` instance.
- Loading the correct configuration object.
- Initializing the database connection (`db.init_app(app)`).
- Initializing `Flask-Migrate` for database schema management.
- Initializing `Flask-Limiter` for rate limiting.
2. **Routing**: All of the application's routes are defined here. They can be grouped into:
- **OIDC Endpoints**: Standard endpoints required by the OpenID Connect specification (`/authorize`, `/token`, `/userinfo`, `/.well-known/openid-configuration`, `/jwks`).
- **User-Facing Pages**: Routes for user interaction, such as `/login`, `/register`, and `/dashboard`.
- **Admin Panel**: A set of routes under the `/admin/` prefix for managing users and clients. These routes are protected by the `@admin_required` decorator.
3. **CLI Commands**: The application defines custom `flask` commands, such as:
- `flask db`: For managing database migrations (e.g., `flask db upgrade`).
- `flask seed`: For populating the database with initial test data (users and clients).
## 4. Database Models (`models.py`)
All data is stored in a relational database, and the schema is defined using SQLAlchemy ORM models.
- **`User`**: Stores user information, including a hashed password (using `bcrypt`), role, and a flexible JSON-based permissions list.
- **`Client`**: Stores information about OIDC client applications. Each client has a `client_id`, a hashed `client_secret`, a list of allowed `redirect_uris`, and a list of `allowed_scopes`.
- **`AuthorizationCode`**: A temporary, single-use code that is issued during the first leg of the OIDC flow. It has a short TTL and is marked as used after it is exchanged for a token.
- **`AccessToken`**: A token that grants access to the `/userinfo` endpoint. It has a configurable lifetime and can be revoked.
- **`AuditLog`**: Records important security-related events, such as login attempts, user creation, and client modifications.
## 5. OIDC Authorization Code Flow
The core logic of the IdP is its implementation of the OIDC Authorization Code Flow.
1. **`/authorize` (GET)**:
- A client application redirects the user to this endpoint.
- The server validates the `client_id` and `redirect_uri` against the `Client` table in the database.
- It stores the authorization request parameters in the user's session and displays a login page.
2. **`/authorize` (POST)**:
- The user submits their credentials.
- The server validates the username and password against the `User` table.
- On success, it generates a new `AuthorizationCode`, saves it to the database, and redirects the user back to the client's `redirect_uri` with the code included as a query parameter.
3. **`/token` (POST)**:
- The client application makes a direct, back-channel request to this endpoint, sending the authorization code along with its `client_id` and `client_secret`.
- The server validates the client's credentials and the authorization code.
- It marks the authorization code as used.
- It generates a new `AccessToken` and an `id_token` (a JWT signed with the `RS256` algorithm).
- It returns the tokens to the client in a JSON response.
4. **`/userinfo` (GET)**:
- The client can use the `AccessToken` to request information about the user from this endpoint.
- The server validates the access token and returns the user's claims (e.g., name, email).
This flow ensures that the user's credentials are never exposed to the client application and that tokens are securely issued and validated.