Интеграция OAuth2/OIDC и LDAP/AD¶
Руководство по настройке для команд ИТ и информационной безопасности
Содержание¶
- Обзор
- Ключевые возможности
- Архитектура
- Поток аутентификации
- Регистрация поставщиков
- OAuth2/OIDC
- Поддерживаемые поставщики
- Настройка
- Поток авторизации
- Автоматическое создание пользователей
- LDAP/Active Directory
- Настройка LDAP
- Маппинг групп на роли
- Создание пользователей из LDAP
- Интеграция с SIEM
- События аутентификации
- Примеры событий
- API Reference
- конечные точки OAuth
- конечные точки LDAP
- Запуск и остановка
- Устранение неполадок
- Связанные документы
Обзор¶
CodeGraph поддерживает корпоративную единую аутентификацию (SSO) через OAuth2/OIDC и интеграцию с LDAP/Active Directory. Оба метода инициализируются при запуске приложения и генерируют события безопасности для SIEM при каждой попытке аутентификации.
Ключевые возможности¶
| Возможность | Описание |
|---|---|
| 4 поставщика OAuth2 | GitHub, GitLab, Google, Keycloak (OIDC) |
| Поддержка LDAP/AD | Active Directory, OpenLDAP с синхронизацией групп |
| Автопровижининг | Пользователи создаются при первом входе через SSO/LDAP |
| Маппинг RBAC | Группы LDAP сопоставляются с ролями CodeGraph (ADMIN, REVIEWER, ANALYST, VIEWER) |
| Защита от CSRF | Параметр state с серверной валидацией |
| Аудит в SIEM | События AUTH_SUCCESS / AUTH_FAILURE при каждом входе |
| Грациозная деградация | Приложение запускается даже без OAuth/LDAP |
Архитектура¶
Поток аутентификации¶
┌──────────────┐
│ Браузер / │
│ API-клиент │
└──────┬───────┘
│
┌─────────────┼─────────────┐
│ │ │
┌──────▼──────┐ ┌───▼────┐ ┌──────▼──────┐
│ OAuth2 │ │ LDAP │ │ Локальный │
│ /OIDC │ │ /AD │ │ JWT + API │
└──────┬──────┘ └───┬────┘ └──────┬──────┘
│ │ │
└─────────────┼─────────────┘
│
┌───────▼───────┐
│ User Repo │
│ (найти или │
│ создать) │
└───────┬───────┘
│
┌───────▼───────┐ ┌──────────────┐
│ JWT-токены │ │ SIEM-событие│
│ (access + │──────►│ Диспетчер │
│ refresh) │ │ (auth.*) │
└───────────────┘ └──────────────┘
Регистрация поставщиков¶
При запуске функция lifespan() инициализирует обе подсистемы:
- OAuth —
setup_oauth_providers()читает переменные окруженияOAUTH_*, регистрирует включённые поставщики вOAuthManager - LDAP —
setup_ldap_authenticator()читает переменные окруженияLDAP_*, создаёт синглтонLDAPAuthenticator
Оба блока обёрнуты в try/except — приложение нормально запускается, даже если SSO не сконфигурирован.
OAuth2/OIDC¶
Поддерживаемые поставщики¶
| Поставщик | URL авторизации | URL токена | Области доступа |
|---|---|---|---|
| GitHub | github.com/login/oauth/authorize |
github.com/login/oauth/access_token |
read:user, user:email |
| GitLab | gitlab.com/oauth/authorize (или локальный) |
gitlab.com/oauth/token |
read_user, openid |
accounts.google.com/o/oauth2/v2/auth |
oauth2.googleapis.com/token |
openid, profile, email |
|
| Keycloak | {server}/realms/{realm}/protocol/openid-connect/auth |
.../token |
openid, profile, email |
Настройка¶
Установите переменные окружения для каждого поставщика, который необходимо включить:
# GitHub
export OAUTH_GITHUB_CLIENT_ID="ваш_github_client_id"
export OAUTH_GITHUB_CLIENT_SECRET="ваш_github_client_secret"
# Google
export OAUTH_GOOGLE_CLIENT_ID="ваш_google_client_id"
export OAUTH_GOOGLE_CLIENT_SECRET="ваш_google_client_secret"
# Keycloak (OIDC)
export OAUTH_KEYCLOAK_SERVER_URL="https://keycloak.corp.example.com"
export OAUTH_KEYCLOAK_REALM="codegraph"
export OAUTH_KEYCLOAK_CLIENT_ID="codegraph-app"
export OAUTH_KEYCLOAK_CLIENT_SECRET="ваш_keycloak_client_secret"
Поставщики без CLIENT_ID и CLIENT_SECRET автоматически пропускаются.
Поток авторизации¶
1. Пользователь → GET /api/v1/auth/oauth/{provider}
2. Сервер генерирует CSRF state, сохраняет в памяти
3. Редирект 302 на URL авторизации поставщика
4. Пользователь аутентифицируется на стороне поставщика
5. Поставщик перенаправляет на GET /api/v1/auth/oauth/{provider}/callback?code=...&state=...
6. Сервер проверяет state (CSRF), обменивает code на access token
7. Сервер запрашивает информацию о пользователе через API поставщика
8. Сервер находит или создаёт пользователя в базе данных
9. Сервер возвращает JWT-токены (access + refresh)
Автоматическое создание пользователей¶
При первом входе через OAuth автоматически создаётся пользователь:
| Поле | Источник |
|---|---|
username |
Зависит от поставщика (GitHub: login, Google: префикс email, Keycloak: preferred_username) |
email |
Информация от поставщика |
display_name |
Поле name поставщика |
auth_provider |
oauth |
role |
По умолчанию: ANALYST |
external_id |
Уникальный ID пользователя у поставщика |
Последующие входы находят пользователя по паре (provider, external_id) и используют существующий аккаунт.
LDAP/Active Directory¶
Настройка LDAP¶
# Обязательные
export LDAP_SERVER="ldaps://ldap.corp.example.com"
export LDAP_BASE_DN="dc=corp,dc=example,dc=com"
# Сервисный аккаунт для поиска
export LDAP_BIND_USER="cn=codegraph-svc,ou=service-accounts,dc=corp,dc=example,dc=com"
export LDAP_BIND_PASSWORD="пароль_сервисного_аккаунта"
# Базы поиска
export LDAP_USER_SEARCH_BASE="ou=users,dc=corp,dc=example,dc=com"
export LDAP_GROUP_SEARCH_BASE="ou=groups,dc=corp,dc=example,dc=com"
Полная настройка в config.yaml:
auth:
ldap:
enabled: true
server: "ldaps://ldap.corp.example.com"
port: 636
use_ssl: true
base_dn: "dc=corp,dc=example,dc=com"
user_search_base: "ou=users,dc=corp,dc=example,dc=com"
group_search_base: "ou=groups,dc=corp,dc=example,dc=com"
bind_user: "cn=codegraph-svc,ou=service-accounts,dc=corp,dc=example,dc=com"
bind_password: "${LDAP_BIND_PASSWORD}"
user_object_class: "person"
group_object_class: "group"
username_attribute: "sAMAccountName"
email_attribute: "mail"
group_membership_attribute: "memberOf"
role_mapping:
"cn=codegraph-admins,ou=groups,dc=corp,dc=example,dc=com": "admin"
"cn=codegraph-reviewers,ou=groups,dc=corp,dc=example,dc=com": "reviewer"
"cn=codegraph-analysts,ou=groups,dc=corp,dc=example,dc=com": "analyst"
Маппинг групп на роли¶
Группы LDAP сопоставляются с ролями RBAC CodeGraph через role_mapping. Аутентификатор проверяет группы пользователя в порядке приоритета (admin > reviewer > analyst > viewer). Побеждает первое совпадение.
| Группа LDAP | Роль CodeGraph | Разрешения |
|---|---|---|
codegraph-admins |
ADMIN | Полный доступ (admin:all) |
codegraph-reviewers |
REVIEWER | Проверка кода + разрешения аналитика |
codegraph-analysts |
ANALYST | Выполнение запросов + API-ключи |
| (нет совпадения) | ANALYST | Роль по умолчанию |
Создание пользователей из LDAP¶
При первом входе через LDAP создаётся пользователь:
| Поле | Источник |
|---|---|
username |
LDAP-атрибут sAMAccountName (или настроенный атрибут) |
email |
LDAP-атрибут mail |
display_name |
LDAP-атрибут displayName |
ldap_dn |
Полное различающееся имя (DN) |
auth_provider |
ldap |
role |
Из маппинга групп на роли |
Последующие входы находят пользователя по ldap_dn.
Интеграция с SIEM¶
Все попытки аутентификации (успешные и неуспешные) генерируют SIEM-события, отправляемые в настроенные обработчики (Syslog, CEF, LEEF).
События аутентификации¶
| Тип события | Серьёзность | Триггер |
|---|---|---|
AUTH_SUCCESS |
6 (Информационное) | Успешный вход любым методом |
AUTH_FAILURE |
4 (Предупреждение) | Неуспешный вход — неверные учётные данные, неизвестный пользователь, ошибка поставщика |
Примеры событий¶
Успешный вход через OAuth:
{
"event_type": "auth.success",
"timestamp": "2026-02-26T10:30:00.000Z",
"severity": 6,
"message": "OAuth login: ghuser via github",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"ip_address": "10.0.0.50",
"provider": "github",
"request_id": "req-abc123"
}
Неуспешный вход через LDAP:
{
"event_type": "auth.failure",
"timestamp": "2026-02-26T10:31:00.000Z",
"severity": 4,
"message": "LDAP auth failed: unknown_user",
"ip_address": "10.0.0.51",
"request_id": "req-def456"
}
Неуспешный локальный вход (неверный пароль):
{
"event_type": "auth.failure",
"timestamp": "2026-02-26T10:32:00.000Z",
"severity": 4,
"message": "Login failed: invalid password for analyst01",
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"ip_address": "10.0.0.52",
"request_id": "req-ghi789"
}
Справочник API¶
Конечные точки OAuth¶
| Метод | Путь | Описание |
|---|---|---|
GET |
/api/v1/auth/oauth/providers |
Список всех поставщиков OAuth и их статус |
GET |
/api/v1/auth/oauth/{provider} |
Начать OAuth-поток (перенаправление к поставщику) |
GET |
/api/v1/auth/oauth/{provider}/callback |
Обработка OAuth-колбэка, возврат JWT-токенов |
Ответ списка поставщиков:
[
{"name": "github", "enabled": true, "authorize_url": "https://github.com/login/oauth/authorize?..."},
{"name": "google", "enabled": false, "authorize_url": null},
{"name": "gitlab", "enabled": false, "authorize_url": null},
{"name": "keycloak", "enabled": false, "authorize_url": null}
]
Успешный ответ колбэка:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 1800
}
конечные точки LDAP¶
| Метод | Путь | Описание |
|---|---|---|
POST |
/api/v1/auth/ldap |
Аутентификация через LDAP |
GET |
/api/v1/auth/ldap/status |
Проверка статуса подключения к LDAP |
Запрос аутентификации LDAP:
{
"username": "jdoe",
"password": "корпоративный_пароль"
}
Ответ статуса LDAP (настроен):
{
"enabled": true,
"available": true,
"connected": true,
"server": "ldaps://ldap.corp.example.com"
}
Ответ статуса LDAP (не настроен):
{
"enabled": false,
"available": false,
"message": "LDAP not configured"
}
Запуск и остановка¶
Последовательность запуска¶
При запуске приложения (lifespan()) OAuth и LDAP инициализируются последовательно:
# 1. поставщики OAuth
auth_config = get_auth_config()
oauth_providers = setup_oauth_providers({
"github": auth_config.oauth.github,
"google": auth_config.oauth.google,
"gitlab": auth_config.oauth.gitlab,
"keycloak": auth_config.oauth.keycloak,
})
# Лог: "OAuth providers initialized: 2" или "No OAuth providers configured"
# 2. LDAP-аутентификатор
ldap = setup_ldap_authenticator(auth_config.ldap)
# Лог: "LDAP authenticator initialized: ldaps://..." или "LDAP not configured"
Очистка при остановке¶
При остановке HTTP-клиенты OAuth закрываются корректно:
await get_oauth_manager().close_all()
Грациозная деградация¶
Обе подсистемы необязательны. Если инициализация не удалась (отсутствует библиотека, неверная конфигурация), приложение логирует предупреждение и продолжает работу:
WARNING OAuth initialization skipped: <ошибка>
WARNING LDAP initialization skipped: <ошибка>
Все остальные конечные точки (локальный JWT-логин, API-ключи, запросы, сценарии) остаются полностью функциональными.
Устранение неполадок¶
поставщики OAuth показывают enabled: false¶
Проверьте установку переменных окружения:
echo $OAUTH_GITHUB_CLIENT_ID
echo $OAUTH_GITHUB_CLIENT_SECRET
Оба значения CLIENT_ID и CLIENT_SECRET должны быть непустыми для регистрации поставщика.
OAuth-колбэк возвращает invalid_state_parameter¶
CSRF-токен state хранится в памяти сервера. Эта ошибка возникает если: - Токен state устарел (сервер перезапущен между редиректом и колбэком) - Токен state уже использован (обновление страницы в браузере) - Многоинстансное развёртывание без общего хранилища state (используйте Redis в рабочей среде)
LDAP возвращает 503 ldap_not_configured¶
Переменная окружения LDAP_SERVER не установлена или библиотека ldap3 не установлена:
pip install ldap3>=2.9.1
Тест подключения к LDAP не проходит¶
Проверьте сетевую доступность и учётные данные:
# Тест подключения к LDAP
ldapsearch -H ldaps://ldap.corp.example.com -x -D "cn=codegraph-svc,..." -w ПАРОЛЬ -b "dc=corp,dc=example,dc=com" "(sAMAccountName=testuser)"
SIEM-события не появляются¶
Проверьте, что диспетчер SIEM включён в config.yaml:
siem:
enabled: true
handlers:
- type: syslog
host: "siem.corp.example.com"
port: 514
Подробная настройка — см. Интеграция с SIEM.
В логах запуска предупреждения об инициализации¶
Проверьте логи приложения на конкретные ошибки:
uvicorn src.api.main:app --log-level debug 2>&1 | grep -i "oauth\|ldap"
Связанные документы¶
- RBAC и авторизация — Иерархия ролей и каталог разрешений
- Интеграция с SIEM — Форматы событий безопасности и настройка диспетчера
- Обзор безопасности — Корпоративная безопасность
- Защита от утечек данных — Предотвращение утечки данных
- Руководство по развёртыванию — Развёртывание высокой доступности