Единый вход OIDC
В Gately встроен поставщик удостоверений OpenID Connect (OIDC), через который общие пользователи веб-служб могут входить в Gitea, OpenList, Grafana и другие приложения. По стандартному протоколу OIDC приложение узнаёт, кто вошёл (имя пользователя, email, группы), и заводит для каждого человека собственную учётную запись и права.
Это покрывает функции OIDC в Authelia. Вместе с двухэтапной проверкой TOTP общих пользователей и доменом единого входа одна учётная запись защищает и сайты на шлюзе, и собственный вход подключённых приложений.
Разделение с веб-аутентификацией
| Веб-аутентификация (общие пользователи) | Единый вход OIDC | |
|---|---|---|
| Как работает | Gately задерживает невошедших посетителей на шлюзе и пропускает их после входа | Приложение отправляет пользователя войти в Gately, а затем получает от Gately его личность |
| Различает ли приложение пользователей | Знает только, что запрос пропущен | Да, получает имя пользователя, email и группы |
| Подходит для | Сервисов без собственных учётных записей, панелей администрирования или как дополнительный барьер | Приложений с собственными учётными записями и поддержкой входа через OIDC / OAuth2 |
Оба способа можно использовать одновременно: один и тот же общий пользователь проходит веб-аутентификацию сайта и входит в OIDC-приложения.
Подготовка
- Добавьте пользователей в «Веб-служба → Глобальные настройки → Общие пользователи». OIDC принимает только общих пользователей; собственные пользователи сайта и удостоверения входа через сторонние сервисы для OIDC не подходят.
- При необходимости укажите для каждого пользователя email, отображаемое имя и группы:
- Email: передаётся приложению как утверждение
emailс отметкой «подтверждён»; по нему Gitea и другие приложения создают или связывают учётные записи; - Отображаемое имя: передаётся как утверждение
name; если пусто, используется имя пользователя; - Группы: передаются как утверждение
groups; в приложении их можно сопоставить с администраторами или использовать, чтобы ограничить круг пользователей, которым разрешён вход в приложение.
- Email: передаётся приложению как утверждение
- Подготовьте домен издателя, например
auth.example.com: он должен указывать на хост с Gately, в разделе SSL-сертификаты должен быть сертификат на этот домен, и какой-либо HTTPS-слушатель должен получать запросы на него. Сайт для этого домена создавать не нужно: Gately распознаёт его пути OIDC на всех слушателях. Рекомендуется отдельный домен; остальные пути на нём, как обычно, обрабатываются сайтами.
Если адрес издателя использует https, GET-запросы к путям OIDC по незашифрованному HTTP перенаправляются на HTTPS, а остальные запросы отклоняются, поэтому пароли и токены никогда не передаются открытым текстом. Если перед Gately стоит ещё один обратный прокси, который завершает TLS и пересылает запросы по HTTP, он должен добавлять X-Forwarded-Proto: https; Gately доверяет этому заголовку только от локального хоста и из внутренней сети. Если домен издателя на каком-либо слушателе совпадает с сайтом (включая сайт по умолчанию), белые и чёрные списки IP, подписные списки IP, фильтрация по странам и ограничение частоты этого сайта действуют и на пути OIDC — так можно ограничить страницу входа внутренней сетью.
Включение
В «Веб-служба → Глобальные настройки → Поставщик удостоверений OIDC»:
| Поле | Описание |
|---|---|
| Включить | Если выключено, пути OIDC перестают отвечать; существующие клиенты и ключ подписи сохраняются |
| Адрес издателя | Например https://auth.example.com, только схема, домен и порт. Приложения проверяют, что issuer в документе обнаружения в точности совпадает с настроенным адресом, поэтому укажите адрес, по которому приложения обращаются к Gately, включая нестандартный порт |
При первом сохранении Gately автоматически создаёт 2048-битный ключ подписи RSA. Он хранится в файле конфигурации веб-службы, попадает в резервные копии вместе с конфигурацией и никогда не возвращается ни API, ни интерфейсом.
После включения на домене издателя доступны следующие адреса (в интерфейсе их можно скопировать одним нажатием):
| Назначение | Адрес |
|---|---|
| Документ обнаружения | https://auth.example.com/.well-known/openid-configuration |
| Авторизация | https://auth.example.com/__gately_oidc/authorize |
| Токен | https://auth.example.com/__gately_oidc/token |
| Данные пользователя | https://auth.example.com/__gately_oidc/userinfo |
| Открытые ключи (JWKS) | https://auth.example.com/__gately_oidc/jwks |
| Выход | https://auth.example.com/__gately_oidc/logout |
Большинству приложений нужен только адрес документа обнаружения (Discovery URL, Auto Discovery URL); некоторые просят адрес издателя (Issuer URL), а немногие требуют указать каждую конечную точку отдельно.
Добавление клиентов
Каждому подключённому приложению соответствует клиент:
| Поле | Описание |
|---|---|
| Название | Показывается на странице входа, например «Подтвердите личность, чтобы продолжить вход в Gitea» |
| Client ID | Только буквы, цифры и - . _ ~; указывается в приложении |
| Client Secret | Не менее 16 символов; кнопка «Создать» выдаёт случайный ключ из 43 символов. После сохранения хранится только хеш bcrypt, повторно посмотреть секрет нельзя, поэтому скопируйте его в приложение до сохранения; если он утерян, создайте новый и обновите его в приложении. Можно также сразу указать готовый хеш bcrypt (начинается с $2a$, $2b$ или $2y$) |
| Публичный клиент | Отметьте для клиентов, которые не могут хранить секрет, например одностраничных и мобильных приложений: секрет не используется, PKCE (S256) обязателен, токен обновления не выдаётся |
| URI перенаправления | По одному в строке; посимвольно сравнивается с redirect_uri, которую присылает приложение: схема, порт, путь и параметры запроса должны совпадать |
| Разрешённые пользователи | По одному имени пользователя в строке или group:имя; для входа достаточно совпадения с любой строкой. Пусто — все общие пользователи. Сопоставление идёт по имени пользователя, поэтому после переименования общего пользователя обновите и этот список |
Если адрес перенаправления неизвестен
Сначала укажите любой адрес, сохраните и один раз нажмите вход в приложении. Gately остановится на странице ошибки «URI перенаправления не совпадает», где показан адрес, который приложение прислало на самом деле. Скопируйте его без изменений в URI перенаправления клиента.
Процесс входа
- Пользователь нажимает в приложении кнопку вроде «Войти через Gately», и приложение направляет браузер на адрес авторизации;
- Если пользователь уже вошёл в Gately, он сразу возвращается в приложение; иначе показывается страница входа Gately, а пользователи с включённым TOTP дополнительно вводят одноразовый код;
- Приложение в фоновом режиме обменивает код авторизации и Client Secret на ID Token и Access Token, получает данные пользователя и завершает вход.
Если домен издателя находится внутри домена единого входа (например, домен единого входа example.com, издатель auth.example.com), то после входа пользователя на любой сайт, защищённый общими пользователями, OIDC-приложения больше не просят войти, и наоборот.
Клиентов регистрирует администратор, Gately считает их доверенными приложениями и не показывает страницу подтверждения доступа.
scope и утверждения
| scope | Возвращаемые утверждения |
|---|---|
openid (обязателен) | sub: постоянный ID общего пользователя, создаётся случайно и сохраняется при переименовании; если удалить пользователя и создать нового с тем же именем, он получит новый ID и не унаследует учётную запись прежнего пользователя в приложении |
profile | name (отображаемое имя, если не задано — имя пользователя), preferred_username, nickname (имя пользователя) |
email | email, email_verified (только если указан email) |
groups | groups: список групп |
offline_access | Дополнительно выдаётся токен обновления, только для конфиденциальных клиентов |
ID Token также содержит iss, aud, azp, exp, iat, auth_time, nonce и at_hash. ID Token и Access Token — JWT с подписью RS256. Прочие scope, запрошенные приложением, игнорируются.
Детали протокола: поддерживается только поток с кодом авторизации (response_type=code), результат возвращается в параметрах запроса (response_mode=query); конечная точка токенов принимает способы аутентификации client_secret_basic и client_secret_post, публичные клиенты используют none; PKCE поддерживается только в варианте S256; поддерживается prompt=none, без входа возвращается login_required, без доступа к этому приложению — access_denied; при prompt=login или если с момента входа прошло больше max_age, пользователь должен снова ввести пароль.
Конечная точка выхода принимает id_token_hint, client_id и post_logout_redirect_uri: id_token_hint должен быть ID Token, выданным этим издателем (допускается просроченный), а post_logout_redirect_uri должен быть одним из зарегистрированных для клиента URI перенаправления или иметь общий источник (origin) с одним из них; иначе после выхода пользователь остаётся на странице входа.
Сроки действия и отзыв
- Код авторизации: 2 минуты, используется один раз;
- ID Token, Access Token: 1 час;
- Токен обновления: 30 дней, при обновлении продолжает использоваться прежний токен;
- После смены пароля или TOTP общего пользователя, его переименования, удаления пользователя, исключения его из списка разрешённых пользователей клиента или удаления клиента ещё не обменянные коды авторизации, токены обновления и уже выданные Access Token сразу становятся недействительными (конечная точка данных пользователя отклоняет старые Access Token). Сессиями, уже открытыми внутри приложения, управляет само приложение; при необходимости завершите сессию этого пользователя в приложении;
- После изменения email, отображаемого имени или групп конечная точка данных пользователя сразу возвращает новые значения, а утверждения в ID Token обновляются при следующем входе или обновлении токена; если список разрешённых пользователей даёт доступ по группе, исключение пользователя из группы действует сразу;
- Ключ подписи хранится в
settings.oidc.signingKeyфайла конфигурации веб-службыwebservice.json. Чтобы заменить его, остановите Gately, удалите это поле и запустите снова: будет создан новый ключ, и все выданные токены станут недействительными.
Примеры настройки приложений
В примерах ниже адрес издателя — https://auth.example.com; замените его на свой.
Gitea
Добавьте клиента в Gately: Client ID gitea, создайте Client Secret, в URI перенаправления укажите:
https://git.example.com/user/oauth2/gately/callbackЗдесь gately — название источника аутентификации, которое указывается в Gitea ниже; оба значения должны совпадать.
В Gitea в разделе «Site Administration → Authentication Sources → Add Authentication Source»:
| Поле | Значение |
|---|---|
| Authentication Type | OAuth2 |
| Authentication Name | gately |
| OAuth2 Provider | OpenID Connect |
| Client ID (Key) / Client Secret | Client ID и Client Secret клиента в Gately |
| OpenID Connect Auto Discovery URL | https://auth.example.com/.well-known/openid-configuration |
| Additional Scopes | profile email groups |
| Claim name providing group names for this source. (Optional) | groups (необязательно, используется вместе со следующим полем) |
| Group Claim value for administrator users. (Optional — requires claim name above) | Имя группы, например admins: пользователи этой группы после входа становятся администраторами Gitea (необязательно) |
То же можно сделать из командной строки:
gitea admin auth add-oauth --name gately --provider openidConnect --key gitea --secret '<Client Secret>' --auto-discover-url https://auth.example.com/.well-known/openid-configuration --scopes "openid profile email groups" --group-claim-name groups --admin-group adminsЧтобы учётная запись Gitea создавалась автоматически при первом входе, добавьте в app.ini:
[oauth2_client]
ENABLE_AUTO_REGISTRATION = true
USERNAME = preferred_username
ACCOUNT_LINKING = autoACCOUNT_LINKING = auto автоматически связывает существующую учётную запись Gitea с тем же email с пользователем Gately. Для автоматической регистрации нужен email, поэтому укажите его у общих пользователей.
OpenList
Добавьте клиента в Gately: Client ID openlist, создайте Client Secret, в URI перенаправления укажите две строки (первая — для входа, вторая — для привязки существующей учётной записи в профиле):
https://pan.example.com/api/auth/sso_callback?method=sso_get_token
https://pan.example.com/api/auth/sso_callback?method=sso_get_ssoidВ OpenList в разделе «Manage → Settings → SSO»:
| Параметр | Значение |
|---|---|
SSO login enabled (sso_login_enabled) | Включено |
SSO login platform (sso_login_platform) | OIDC |
| SSO client id / SSO client secret | Client ID и Client Secret клиента в Gately |
SSO endpoint name (sso_endpoint_name) | Адрес издателя https://auth.example.com, без /.well-known/... |
SSO oidc username key (sso_oidc_username_key) | preferred_username. Значение по умолчанию name берёт отображаемое имя |
SSO auto register (sso_auto_register) | Если включено, пользователь OpenList создаётся автоматически при первом входе; если выключено, пользователю нужно сначала войти под учётной записью OpenList и привязать единый вход в профиле |
После сохранения на странице входа OpenList появится кнопка единого входа.
Grafana
Добавьте клиента в Gately: Client ID grafana, создайте Client Secret, в URI перенаправления укажите https://grafana.example.com/login/generic_oauth.
В grafana.ini:
[server]
root_url = https://grafana.example.com/
[auth.generic_oauth]
enabled = true
name = Gately
client_id = grafana
client_secret = <Client Secret>
scopes = openid profile email groups
auth_url = https://auth.example.com/__gately_oidc/authorize
token_url = https://auth.example.com/__gately_oidc/token
api_url = https://auth.example.com/__gately_oidc/userinfo
use_pkce = true
login_attribute_path = preferred_username
name_attribute_path = name
email_attribute_path = email
groups_attribute_path = groups
role_attribute_path = contains(groups[*], 'admins') && 'Admin' || 'Viewer'role_attribute_path делает пользователей группы admins администраторами Grafana, остальные получают доступ только на чтение.
Другие приложения
Подключить можно любое приложение со входом через OIDC или «Generic OAuth2». Обычно настройки такие:
- Если нужен только адрес обнаружения или адрес издателя: укажите
https://auth.example.com/.well-known/openid-configurationилиhttps://auth.example.com; - Если конечные точки задаются по отдельности: укажите адреса авторизации, токена, данных пользователя и открытых ключей по таблице из раздела «Включение» выше;
- Поле имени пользователя —
preferred_username, поле email —email, поле групп —groups; - Адрес перенаправления приводится в документации или на странице настроек приложения; его также можно скопировать со страницы ошибки, как описано в подсказке выше.
Частые вопросы
Приложение сообщает о несовпадении issuer. Адрес издателя должен в точности совпадать с адресом, по которому обращается приложение, включая https и порт. После изменения адреса издателя некоторые приложения нужно перезапустить, чтобы они заново прочитали документ обнаружения.
После входа появляется «URI перенаправления не совпадает». Добавьте адрес со страницы ошибки без изменений в URI перенаправления клиента.
После входа появляется «Нет доступа к этому приложению». Текущего пользователя нет в списке разрешённых пользователей клиента. Измените список или нажмите на странице «Войти под другой учётной записью», чтобы выйти и войти другим общим пользователем; после входа исходная авторизация продолжится.
Приложение сообщает invalid_client. Неверный Client Secret, либо приложение использует публичный клиент как конфиденциальный. Client Secret виден только до сохранения; если он утерян, создайте новый и обновите его в приложении. Неудачная аутентификация на конечной точке токенов учитывается в том же ограничении частоты, что и неудачные входы: после 10 неудачных попыток подряд с одного источника действует пауза 15 минут, а при включённой автоблокировке IP источника ещё и блокируется.
Сервер приложения не может подключиться к издателю. Документ обнаружения, токены и открытые ключи сервер приложения запрашивает напрямую, без участия браузера. Хост или контейнер приложения должен разрешать домен издателя и иметь доступ к соответствующему порту; если приложение работает в Docker, направьте домен на хост с помощью extra_hosts.
Приложение требует form_post или неявный поток. Gately поддерживает только поток с кодом авторизации и возвращает результат в параметрах запроса. Большинство приложений используют этот способ по умолчанию или позволяют переключиться на него в настройках.