chore(oidc): remove legacy storage methods (#10061)

# Which Problems Are Solved

Stabilize the optimized introspection code and cleanup unused code.

# How the Problems Are Solved

- `oidc_legacy_introspection` feature flag is removed and reserved.
- `OPStorage` which are no longer needed have their bodies removed.
- The method definitions need to remain in place so the interface
remains implemented.
  - A panic is thrown in case any such method is still called

# Additional Changes

- A number of `OPStorage` methods related to token creation were already
unused. These are also cleaned up.

# Additional Context

- Closes #10027 
- #7822

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Tim Möhlmann 2025-06-26 11:08:37 +03:00 committed by GitHub
parent 27f88a6390
commit 1ebbe275b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 143 additions and 1884 deletions

View File

@ -48,7 +48,6 @@ Actions:
want: func(t *testing.T, config *Config) {
assert.Equal(t, config.DefaultInstance.Features, &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
LegacyIntrospection: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(true),
UserSchema: gu.Ptr(true),
})

View File

@ -85,7 +85,6 @@ Actions:
want: func(t *testing.T, config *Config) {
assert.Equal(t, config.DefaultInstance.Features, &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
LegacyIntrospection: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(true),
UserSchema: gu.Ptr(true),
})

View File

@ -33,7 +33,6 @@ const FEATURE_KEYS = [
'enableBackChannelLogout',
// 'improvedPerformance',
'loginDefaultOrg',
'oidcLegacyIntrospection',
'oidcSingleV1SessionTermination',
'oidcTokenExchange',
'oidcTriggerIntrospectionProjections',

View File

@ -1623,8 +1623,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Организация по подразбиране за влизане",
"LOGINDEFAULTORG_DESCRIPTION": "Потребителският интерфейс за влизане ще използва настройките на организацията по подразбиране (а не на инстанцията), ако не е зададен контекст на организация.",
"OIDCLEGACYINTROSPECTION": "Наследено осмисляне OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "На скоро префакторизирахме крайния пункт за осмисляне заради производителностни причини. Тази функция може да се използва за връщане към наследената реализация, ако възникнат неочаквани грешки.",
"OIDCTOKENEXCHANGE": "Обмяна на токени OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Активиране на експерименталния тип на дарение urn:ietf:params:oauth:grant-type:token-exchange за краен пункт на токен OIDC. Обменът на токени може да се използва за заявка на токени с по-малък обхват или за имперсонализиране на други потребители. Вижте политиката за сигурност, за да разрешите имперсонализацията на инстанция.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Тригери за проекции на осмисляне на OIDC",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Výchozí organizace pro přihlášení",
"LOGINDEFAULTORG_DESCRIPTION": "Přihlašovací rozhraní použije nastavení výchozí organizace (a ne z instance), pokud není nastaven žádný kontext organizace.",
"OIDCLEGACYINTROSPECTION": "Dědictví OIDC introspekce",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Nedávno jsme přepracovali bod introspekce z výkonnostních důvodů. Tato funkce lze použít k rollbacku na dědickou implementaci, pokud se objeví neočekávané chyby.",
"OIDCTOKENEXCHANGE": "Výměna tokenů OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Povolit experimentální typ udělení urn:ietf:params:oauth:grant-type:token-exchange pro bod tokenového bodu OIDC. Výměna tokenů lze použít k žádosti o tokeny s menším rozsahem nebo k impersonaci jiných uživatelů. Podívejte se na bezpečnostní politiku, abyste umožnili impersonaci na instanci.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Spouštěče projekcí introspekce OIDC",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standardorganisation für die Anmeldung",
"LOGINDEFAULTORG_DESCRIPTION": "Die Anmelde-Benutzeroberfläche verwendet die Einstellungen der Standardorganisation (und nicht von der Instanz), wenn kein Organisationskontext festgelegt ist.",
"OIDCLEGACYINTROSPECTION": "OIDC Legacy-Introspektion",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Wir haben kürzlich den Introspektionsendpunkt aus Leistungsgründen neu strukturiert. Mit diesem Feature können Sie zur alten Implementierung zurückkehren, falls unerwartete Fehler auftreten.",
"OIDCTOKENEXCHANGE": "OIDC Token-Austausch",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktivieren Sie den experimentellen urn:ietf:params:oauth:grant-type:token-exchange-Grant-Typ für den OIDC-Token-Endpunkt. Der Token-Austausch kann verwendet werden, um Token mit einem geringeren Umfang anzufordern oder andere Benutzer zu impersonieren. Siehe die Sicherheitsrichtlinie, um die Impersonation auf einer Instanz zu erlauben.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC Trigger-Introspektionsprojektionen",

View File

@ -1627,8 +1627,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Login Default Org",
"LOGINDEFAULTORG_DESCRIPTION": "The login UI will use the settings of the default org (and not from the instance) if no organization context is set",
"OIDCLEGACYINTROSPECTION": "OIDC Legacy introspection",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise.",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Enable the experimental urn:ietf:params:oauth:grant-type:token-exchange grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC Trigger introspection Projections",

View File

@ -1625,8 +1625,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organización predeterminada de inicio de sesión",
"LOGINDEFAULTORG_DESCRIPTION": "La interfaz de inicio de sesión utilizará la configuración de la organización predeterminada (y no de la instancia) si no se establece ningún contexto de organización.",
"OIDCLEGACYINTROSPECTION": "Introspección heredada OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Recientemente hemos refactorizado el punto de introspección por razones de rendimiento. Esta función se puede utilizar para volver a la implementación heredada si surgen errores inesperados.",
"OIDCTOKENEXCHANGE": "Intercambio de tokens OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Habilita el tipo de concesión experimental urn:ietf:params:oauth:grant-type:token-exchange para el punto de extremo de token OIDC. El intercambio de tokens se puede utilizar para solicitar tokens con un alcance menor o suplantar a otros usuarios. Consulta la política de seguridad para permitir la suplantación en una instancia.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Desencadenadores de proyecciones de introspección OIDC",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organisation par défaut de connexion",
"LOGINDEFAULTORG_DESCRIPTION": "L'interface de connexion utilisera les paramètres de l'organisation par défaut (et non de l'instance) si aucun contexte d'organisation n'est défini.",
"OIDCLEGACYINTROSPECTION": "Introspection héritée OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Nous avons récemment refondu le point d'introspection pour des raisons de performances. Cette fonctionnalité peut être utilisée pour revenir à l'implémentation héritée en cas de bogues inattendus.",
"OIDCTOKENEXCHANGE": "Échange de jetons OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Activez le type d'octroi expérimental urn:ietf:params:oauth:grant-type:token-exchange pour le point de terminaison de jeton OIDC. L'échange de jetons peut être utilisé pour demander des jetons avec une portée moindre ou pour usurper d'autres utilisateurs. Consultez la politique de sécurité pour autoriser l'usurpation sur une instance.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Déclencheurs de projections d'introspection OIDC",

View File

@ -1622,8 +1622,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Alapértelmezett Org bejelentkezés",
"LOGINDEFAULTORG_DESCRIPTION": "A bejelentkezési felület az alapértelmezett org beállításait fogja használni (és nem az instance-tól), ha nincs megadva szervezeti kontextus",
"OIDCLEGACYINTROSPECTION": "OIDC régi introspekció",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Nemrég refaktoráltuk az introspekciós végpontot a teljesítmény javítása érdekében. Ezt a funkciót használhatod a régi implementációra való visszaállításhoz, ha váratlan hibák lépnének fel.",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Engedélyezd a kísérleti urn:ietf:params:oauth:grant-type:token-exchange támogatását az OIDC token végpont számára. A token csere használható kisebb hatókörű tokenek kérésére vagy más felhasználók megszemélyesítésére. Tekintsd meg a biztonsági irányelvet az impersonáció engedélyezéséhez egy példányon.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC Introspekciós Projekciók Indítása",

View File

@ -1498,8 +1498,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Masuk Organisasi Default",
"LOGINDEFAULTORG_DESCRIPTION": "UI login akan menggunakan pengaturan organisasi default (dan bukan dari instance) jika tidak ada konteks organisasi yang ditetapkan",
"OIDCLEGACYINTROSPECTION": "Introspeksi Warisan OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Kami baru-baru ini memfaktorkan ulang titik akhir introspeksi untuk alasan kinerja. Fitur ini dapat digunakan untuk melakukan rollback ke implementasi lama jika muncul bug yang tidak terduga.",
"OIDCTOKENEXCHANGE": "Pertukaran Token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktifkan jenis pemberian urn:ietf:params:oauth:grant-type:token-exchange eksperimental untuk titik akhir token OIDC. Pertukaran token dapat digunakan untuk meminta token dengan cakupan yang lebih kecil atau menyamar sebagai pengguna lain. Lihat kebijakan keamanan untuk mengizinkan peniruan identitas pada sebuah instans.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC Memicu Proyeksi Introspeksi",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organizzazione predefinita per l'accesso",
"LOGINDEFAULTORG_DESCRIPTION": "L'interfaccia di accesso utilizzerà le impostazioni dell'organizzazione predefinita (e non dell'istanza) se non è impostato alcun contesto organizzativo.",
"OIDCLEGACYINTROSPECTION": "Introspezione legacy OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Abbiamo recentemente ristrutturato il punto di introspezione per motivi di prestazioni. Questa funzionalità può essere utilizzata per tornare alla vecchia implementazione in caso di bug imprevisti.",
"OIDCTOKENEXCHANGE": "Scambio token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Abilita il tipo di concessione sperimentale urn:ietf:params:oauth:grant-type:token-exchange per il punto finale del token OIDC. Lo scambio di token può essere utilizzato per richiedere token con uno scopo inferiore o impersonare altri utenti. Consultare la policy di sicurezza per consentire l'impersonificazione su un'istanza.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Proiezioni trigger OIDC per l'introspezione",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "ログイン時の既定組織",
"LOGINDEFAULTORG_DESCRIPTION": "組織コンテキストが設定されていない場合、ログイン UI は既定の組織の設定を使用します (インスタンスの設定ではなく)",
"OIDCLEGACYINTROSPECTION": "OIDC レガシーイントロスペクション",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "パフォーマンス上の理由から最近イントロスペクション エンドポイントをリファクタリングしました。この機能は、予期しないバグが発生した場合にレガシー実装にロールバックするために使用できます。",
"OIDCTOKENEXCHANGE": "OIDC トークン交換",
"OIDCTOKENEXCHANGE_DESCRIPTION": "OIDC トークン エンドポイント用に実験的な urn:ietf:params:oauth:grant-type:token-exchange 付与タイプを有効にします。トークン交換は、より少ないスコープを持つトークンを要求するか、他のユーザーになりすますために使用できます。インスタンスでのなりすましを許可するには、セキュリティポリシーを参照してください。",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC トリガーイントロスペクションプロジェクション",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "로그인 기본 조직",
"LOGINDEFAULTORG_DESCRIPTION": "조직 컨텍스트가 설정되지 않은 경우 로그인 UI가 기본 조직의 설정을 사용합니다 (인스턴스에서 설정되지 않음).",
"OIDCLEGACYINTROSPECTION": "OIDC 레거시 내부 조사",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "최근 내부 조사 엔드포인트를 성능을 위해 리팩토링했습니다. 예상치 못한 버그가 발생하면 이 기능을 사용하여 레거시 구현으로 롤백할 수 있습니다.",
"OIDCTOKENEXCHANGE": "OIDC 토큰 교환",
"OIDCTOKENEXCHANGE_DESCRIPTION": "OIDC 토큰 엔드포인트의 실험적 urn:ietf:params:oauth:grant-type:token-exchange 허용을 활성화합니다. 토큰 교환을 통해 범위가 좁은 토큰을 요청하거나 다른 사용자를 가장할 수 있습니다. 인스턴스에서 가장을 허용하는 보안 정책을 확인하세요.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC 트리거 내부 조사 프로젝션",

View File

@ -1625,8 +1625,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Најава Стандардна организација",
"LOGINDEFAULTORG_DESCRIPTION": "Интерфејсот за најавување ќе ги користи поставките на стандардната организација (а не од примерот) ако не е поставен контекст на организацијата",
"OIDCLEGACYINTROSPECTION": "Интроспекција на наследството на OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Неодамна ја рефакториравме крајната точка на интроспекција поради перформанси. Оваа функција може да се користи за враќање на наследната имплементација доколку се појават неочекувани грешки.",
"OIDCTOKENEXCHANGE": "Размена на токени OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Овозможете го експерименталниот тип на грант urn:ietf:params:oauth:grant-type:token-exchange за крајната точка на токенот OIDC. Размената на токени може да се користи за барање токени со помал опсег или имитирање на други корисници. Погледнете ја безбедносната политика за да дозволите имитирање на пример.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Проекции за интроспекција на активирањето на OIDC",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standaard inlogorganisatie",
"LOGINDEFAULTORG_DESCRIPTION": "Als er geen organisatiecontext is ingesteld, gebruikt de inlog-UI de instellingen van de standaardorganisatie (en niet van de instantie)",
"OIDCLEGACYINTROSPECTION": "Oude OIDC-introspectie",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "We hebben onlangs het introspectie-endpoint opnieuw gefactoreerd omwille van de prestaties. Deze functie kan worden gebruikt om terug te keren naar de oude implementatie als er onverwachte bugs optreden.",
"OIDCTOKENEXCHANGE": "OIDC-tokenuitwisseling",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Schakel het experimentele type verlening urn:ietf:params:oauth:grant-type:token-exchange in voor het OIDC-tokenendpoint. Tokenuitwisseling kan worden gebruikt om tokens met een kleinere scope op te vragen of om zich voor te doen als andere gebruikers. Raadpleeg het beveiligingsbeleid om impersonation op een instantie toe te staan.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC-triggers voor introspectieprojecties",

View File

@ -1623,8 +1623,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Domyślna Organizacja Logowania",
"LOGINDEFAULTORG_DESCRIPTION": "Jeśli nie ustawiono kontekstu organizacji, interfejs logowania będzie używać ustawień domyślnej organizacji (a nie instancji)",
"OIDCLEGACYINTROSPECTION": "Starsza Introspekcja OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Ostatnio przeprojektowaliśmy punkt końcowy introspekcji ze względów wydajnościowych. Ta funkcja może być używana do cofnięcia do starszej implementacji, jeśli wystąpią nieoczekiwane błędy.",
"OIDCTOKENEXCHANGE": "Wymiana Tokenów OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Włącz eksperymentalny typ grantu urn:ietf:params:oauth:grant-type:token-exchange dla punktu końcowego tokena OIDC. Wymiana tokenów może być używana do żądania tokenów o mniejszym zakresie lub podszywania się za innych użytkowników. Aby zezwolić na podszywanie się na instancji, zapoznaj się z polityką bezpieczeństwa.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Projekcje Introspekcji Wyzwalane przez OIDC",

View File

@ -1625,8 +1625,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organização Padrão de Login",
"LOGINDEFAULTORG_DESCRIPTION": "A interface de login utilizará as configurações da organização padrão (e não da instância) se nenhum contexto de organização estiver definido",
"OIDCLEGACYINTROSPECTION": "Introspecção Legada OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Recentemente refatoramos o endpoint de introspecção por motivos de performance. Esse recurso pode ser usado para reverter para a implementação legada caso surjam bugs inesperados.",
"OIDCTOKENEXCHANGE": "Troca de Token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Habilita o tipo de concessão experimental urn:ietf:params:oauth:grant-type:token-exchange para o endpoint de token OIDC. A troca de token pode ser usada para solicitar tokens com escopo menor ou personificar outros usuários. Consulte a política de segurança para permitir a personificação em uma instância.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Projeções de Introspecção com Gatilho OIDC",

View File

@ -1622,8 +1622,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organizație implicită de conectare",
"LOGINDEFAULTORG_DESCRIPTION": "UI-ul de conectare va utiliza setările organizației implicite (și nu din instanță) dacă nu este setat niciun context de organizație",
"OIDCLEGACYINTROSPECTION": "Introspecție OIDC Legacy",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Am refactorizat recent endpointul de introspecție din motive de performanță. Această caracteristică poate fi utilizată pentru a reveni la implementarea legacy dacă apar erori neașteptate.",
"OIDCTOKENEXCHANGE": "Schimb de token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Activați tipul de grant experimental urn:ietf:params:oauth:grant-type:token-exchange pentru endpointul token OIDC. Schimbul de tokenuri poate fi utilizat pentru a solicita tokenuri cu o rază de acțiune mai mică sau pentru a impersona alți utilizatori. Consultați politica de securitate pentru a permite impersonarea pe o instanță.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Proiecții de introspecție OIDC Trigger",

View File

@ -1677,8 +1677,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Организация по умолчанию для входа",
"LOGINDEFAULTORG_DESCRIPTION": "Если контекст организации не установлен, пользовательский интерфейс входа будет использовать настройки организации по умолчанию (а не экземпляра)",
"OIDCLEGACYINTROSPECTION": "Устаревшая интроспекция OIDC",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Недавно мы переработали конечную точку интроспекции для повышения производительности. Эта функция может использоваться для отката к устаревшей реализации, если возникнут непредвиденные ошибки.",
"OIDCTOKENEXCHANGE": "Обмен токенами OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Включите экспериментальный тип гранта urn:ietf:params:oauth:grant-type:token-exchange для конечной точки токена OIDC. Обмен токенами можно использовать для запроса токенов с меньшей областью действия или для impersonation (выдачи себя за) других пользователей. Информацию о разрешении impersonation на экземпляре см. в политике безопасности.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "Проекции интроспекции с триггером OIDC",

View File

@ -1628,8 +1628,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standardorganisation för inloggning",
"LOGINDEFAULTORG_DESCRIPTION": "Inloggningsgränssnittet kommer att använda inställningarna för standardorganisationen (och inte från instansen) om ingen organisationskontext är inställd",
"OIDCLEGACYINTROSPECTION": "OIDC Legacy introspection",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "Vi har nyligen omarbetat introspektionsändpunkten av prestandaskäl. Denna funktion kan användas för att återgå till den äldre implementationen om oväntade buggar uppstår.",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktivera den experimentella urn:ietf:params:oauth:grant-type:token-exchange grant-typen för OIDC-tokenändpunkten. Tokenutbyte kan användas för att begära tokens med en mindre omfattning eller impersonera andra användare. Se säkerhetspolicyn för att tillåta impersonation på en instans.",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC Trigger introspection Projections",

View File

@ -1624,8 +1624,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "登录默认组织",
"LOGINDEFAULTORG_DESCRIPTION": "如果没有设置组织上下文,登录界面将使用默认组织的设置(而不是实例的设置)",
"OIDCLEGACYINTROSPECTION": "OIDC 传统内省",
"OIDCLEGACYINTROSPECTION_DESCRIPTION": "我们最近出于性能原因重构了内省端点。如果出现意外错误,可以使用此功能回滚到传统实现。",
"OIDCTOKENEXCHANGE": "OIDC 令牌交换",
"OIDCTOKENEXCHANGE_DESCRIPTION": "启用 OIDC 令牌端点的实验性 urn:ietf:params:oauth:grant-type:token-exchange 授权类型。令牌交换可用于请求具有较少范围的令牌或模拟其他用户。请参阅安全策略以允许在实例上模拟。",
"OIDCTRIGGERINTROSPECTIONPROJECTIONS": "OIDC 触发内省投影",

View File

@ -8,7 +8,7 @@ ZITADEL supports the usage of scopes as way of requesting information from the I
## Standard Scopes
| Scopes | Description |
|:---------------|--------------------------------------------------------------------------------|
| :------------- | ------------------------------------------------------------------------------ |
| openid | When using openid connect this is a mandatory scope |
| profile | Optional scope to request the profile of the subject |
| email | Optional scope to request the email of the subject |
@ -30,11 +30,9 @@ In addition to the standard compliant scopes we utilize the following scopes.
| `urn:zitadel:iam:org:projects:roles` | `urn:zitadel:iam:org:projects:roles` | By using this scope a client can request the claim `urn:zitadel:iam:org:project:{projectid}:roles` to be asserted for each requested project. All projects of the token audience, requested by the `urn:zitadel:iam:org:project:id:{projectid}:aud` scopes will be used. |
| `urn:zitadel:iam:org:id:{id}` | `urn:zitadel:iam:org:id:178204173316174381` | When requesting this scope **ZITADEL** will enforce that the user is a member of the selected organization. If the organization does not exist a failure is displayed. It will assert the `urn:zitadel:iam:user:resourceowner` claims. |
| `urn:zitadel:iam:org:domain:primary:{domainname}` | `urn:zitadel:iam:org:domain:primary:acme.ch` | When requesting this scope **ZITADEL** will enforce that the user is a member of the selected organization and the username is suffixed by the provided domain. If the organization does not exist a failure is displayed |
| `urn:zitadel:iam:org:roles:id:{orgID}` | `urn:zitadel:iam:org:roles:id:178204173316174381` | This scope can be used one or more times to limit the granted organization IDs in the returned roles. Unknown organization IDs are ignored. When this scope is not used, all granted organizations are returned inside the roles.[^1] |
| `urn:zitadel:iam:org:roles:id:{orgID}` | `urn:zitadel:iam:org:roles:id:178204173316174381` | This scope can be used one or more times to limit the granted organization IDs in the returned roles. Unknown organization IDs are ignored. When this scope is not used, all granted organizations are returned inside the roles. |
| `urn:zitadel:iam:org:project:id:{projectid}:aud` | `urn:zitadel:iam:org:project:id:69234237810729019:aud` | By adding this scope, the requested projectid will be added to the audience of the access token |
| `urn:zitadel:iam:org:project:id:zitadel:aud` | `urn:zitadel:iam:org:project:id:zitadel:aud` | By adding this scope, the ZITADEL project ID will be added to the audience of the access token |
| `urn:zitadel:iam:user:metadata` | `urn:zitadel:iam:user:metadata` | By adding this scope, the metadata of the user will be included in the token. The values are base64 encoded. |
| `urn:zitadel:iam:user:resourceowner` | `urn:zitadel:iam:user:resourceowner` | By adding this scope: id, name and primary_domain of the resource owner (the users organization) will be included in the token. |
| `urn:zitadel:iam:user:resourceowner` | `urn:zitadel:iam:user:resourceowner` | By adding this scope: id, name and primary_domain of the resource owner (the users organization) will be included in the token. |
| `urn:zitadel:iam:org:idp:id:{idp_id}` | `urn:zitadel:iam:org:idp:id:76625965177954913` | By adding this scope the user will directly be redirected to the identity provider to authenticate. Make sure you also send the primary domain scope if a custom login policy is configured. Otherwise the system will not be able to identify the identity provider. |
[^1]: `urn:zitadel:iam:org:roles:id:{orgID}` is not supported when the `oidcLegacyIntrospection` [feature flag](/docs/apis/resources/feature_service_v2/feature-service-set-instance-features) is enabled.

View File

@ -20,7 +20,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) (*command
return &command.SystemFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
@ -37,7 +36,6 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
@ -57,7 +55,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) (*com
return &command.InstanceFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
@ -77,7 +74,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),

View File

@ -21,7 +21,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetSystemFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -34,7 +33,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
want := &command.SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -64,10 +62,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
LegacyIntrospection: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
},
UserSchema: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
@ -114,10 +108,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Enabled: false,
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
UserSchema: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
@ -160,7 +150,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetInstanceFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -177,7 +166,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -211,10 +199,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
LegacyIntrospection: query.FeatureSource[bool]{
Level: feature.LevelInstance,
Value: true,
},
UserSchema: query.FeatureSource[bool]{
Level: feature.LevelInstance,
Value: true,
@ -269,10 +253,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Enabled: false,
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE,
},
UserSchema: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE,

View File

@ -209,7 +209,6 @@ func TestServer_GetSystemFeatures(t *testing.T) {
require.NoError(t, err)
assertFeatureFlag(t, tt.want.LoginDefaultOrg, got.LoginDefaultOrg)
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
})
}
@ -321,7 +320,7 @@ func TestServer_ResetInstanceFeatures(t *testing.T) {
func TestServer_GetInstanceFeatures(t *testing.T) {
_, err := Client.SetSystemFeatures(SystemCTX, &feature.SetSystemFeaturesRequest{
OidcLegacyIntrospection: gu.Ptr(true),
LoginDefaultOrg: gu.Ptr(true),
})
require.NoError(t, err)
t.Cleanup(func() {
@ -358,17 +357,13 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
},
want: &feature.GetInstanceFeaturesResponse{
LoginDefaultOrg: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
Enabled: true,
Source: feature.Source_SOURCE_SYSTEM,
},
OidcTriggerIntrospectionProjections: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature.FeatureFlag{
Enabled: true,
Source: feature.Source_SOURCE_SYSTEM,
},
UserSchema: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
@ -427,10 +422,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature.FeatureFlag{
Enabled: true,
Source: feature.Source_SOURCE_SYSTEM,
},
UserSchema: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
@ -456,7 +447,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
require.NoError(t, err)
assertFeatureFlag(t, tt.want.LoginDefaultOrg, got.LoginDefaultOrg)
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
})
}

View File

@ -12,7 +12,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
return &command.SystemFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
@ -25,7 +24,6 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
@ -37,7 +35,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
return &command.InstanceFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
TriggerIntrospectionProjections: req.OidcTriggerIntrospectionProjections,
LegacyIntrospection: req.OidcLegacyIntrospection,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
@ -52,7 +49,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
OidcTriggerIntrospectionProjections: featureSourceToFlagPb(&f.TriggerIntrospectionProjections),
OidcLegacyIntrospection: featureSourceToFlagPb(&f.LegacyIntrospection),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),

View File

@ -20,7 +20,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetSystemFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -29,7 +28,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
want := &command.SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -54,10 +52,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
LegacyIntrospection: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
},
UserSchema: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: true,
@ -89,10 +83,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Enabled: false,
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
UserSchema: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
@ -118,7 +108,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetInstanceFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
OidcTriggerIntrospectionProjections: gu.Ptr(false),
OidcLegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -128,7 +117,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: nil,
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
@ -154,10 +142,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
LegacyIntrospection: query.FeatureSource[bool]{
Level: feature.LevelInstance,
Value: true,
},
UserSchema: query.FeatureSource[bool]{
Level: feature.LevelInstance,
Value: true,
@ -193,10 +177,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Enabled: false,
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE,
},
UserSchema: &feature_pb.FeatureFlag{
Enabled: true,
Source: feature_pb.Source_SOURCE_INSTANCE,

View File

@ -194,10 +194,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
UserSchema: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
@ -256,10 +252,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
OidcLegacyIntrospection: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
},
UserSchema: &feature.FeatureFlag{
Enabled: false,
Source: feature.Source_SOURCE_UNSPECIFIED,
@ -285,7 +277,6 @@ func TestServer_GetInstanceFeatures(t *testing.T) {
require.NoError(t, err)
assertFeatureFlag(t, tt.want.LoginDefaultOrg, got.LoginDefaultOrg)
assertFeatureFlag(t, tt.want.OidcTriggerIntrospectionProjections, got.OidcTriggerIntrospectionProjections)
assertFeatureFlag(t, tt.want.OidcLegacyIntrospection, got.OidcLegacyIntrospection)
assertFeatureFlag(t, tt.want.UserSchema, got.UserSchema)
})
}

View File

@ -24,7 +24,6 @@ import (
"github.com/zitadel/zitadel/internal/domain/federatedlogout"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/user/model"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -216,11 +215,11 @@ func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) (err erro
return o.repo.SaveAuthCode(ctx, id, code, userAgentID)
}
func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) (err error) {
func (o *OPStorage) DeleteAuthRequest(context.Context, string) error {
panic(o.panicErr("DeleteAuthRequest"))
}
func (o *OPStorage) CreateAccessToken(ctx context.Context, req op.TokenRequest) (string, time.Time, error) {
func (o *OPStorage) CreateAccessToken(context.Context, op.TokenRequest) (string, time.Time, error) {
panic(o.panicErr("CreateAccessToken"))
}
@ -492,34 +491,6 @@ func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, to
return refreshToken.UserID, refreshToken.ID, nil
}
func (o *OPStorage) assertProjectRoleScopes(ctx context.Context, clientID string, scopes []string) ([]string, error) {
for _, scope := range scopes {
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
return scopes, nil
}
}
project, err := o.query.ProjectByOIDCClientID(ctx, clientID)
if err != nil {
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-w4wIn", "Errors.Internal")
}
if !project.ProjectRoleAssertion {
return scopes, nil
}
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(project.ID)
if err != nil {
return nil, zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
}
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
if err != nil {
return nil, err
}
for _, role := range roles.ProjectRoles {
scopes = append(scopes, ScopeProjectRolePrefix+role.Key)
}
return scopes, nil
}
func (o *OPStorage) assertProjectRoleScopesByProject(ctx context.Context, project *query.Project, scopes []string) ([]string, error) {
for _, scope := range scopes {
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
@ -543,22 +514,6 @@ func (o *OPStorage) assertProjectRoleScopesByProject(ctx context.Context, projec
return scopes, nil
}
func (o *OPStorage) assertClientScopesForPAT(ctx context.Context, token *model.TokenView, clientID, projectID string) error {
token.Audience = append(token.Audience, clientID)
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(projectID)
if err != nil {
return zerrors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
}
roles, err := o.query.SearchProjectRoles(ctx, true, &query.ProjectRoleSearchQueries{Queries: []query.SearchQuery{projectIDQuery}}, nil)
if err != nil {
return err
}
for _, role := range roles.ProjectRoles {
token.Scopes = append(token.Scopes, ScopeProjectRolePrefix+role.Key)
}
return nil
}
func setContextUserSystem(ctx context.Context) context.Context {
data := authz.CtxData{
UserID: "SYSTEM",

View File

@ -2,25 +2,17 @@ package oidc
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"slices"
"strings"
"time"
"github.com/dop251/goja"
"github.com/go-jose/go-jose/v4"
"github.com/zitadel/logging"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
"github.com/zitadel/zitadel/internal/actions"
"github.com/zitadel/zitadel/internal/actions/object"
"github.com/zitadel/zitadel/internal/api/authz"
api_http "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
@ -44,6 +36,9 @@ const (
oidcCtx = "oidc"
)
// GetClientByClientID implements the op.Storage interface to retrieve an OIDC client by its ID.
//
// TODO: Still used for Auth request creation for v1 login.
func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Client, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
@ -57,819 +52,44 @@ func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Cl
return ClientFromBusiness(client, o.defaultLoginURL, o.defaultLoginURLV2), nil
}
func (o *OPStorage) GetKeyByIDAndClientID(ctx context.Context, keyID, userID string) (_ *jose.JSONWebKey, err error) {
return o.GetKeyByIDAndIssuer(ctx, keyID, userID)
func (o *OPStorage) GetKeyByIDAndClientID(context.Context, string, string) (*jose.JSONWebKey, error) {
panic(o.panicErr("GetKeyByIDAndClientID"))
}
func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer string) (_ *jose.JSONWebKey, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
publicKeyData, err := o.query.GetAuthNKeyPublicKeyByIDAndIdentifier(ctx, keyID, issuer)
if err != nil {
return nil, err
}
publicKey, err := crypto.BytesToPublicKey(publicKeyData)
if err != nil {
return nil, err
}
return &jose.JSONWebKey{
KeyID: keyID,
Use: "sig",
Key: publicKey,
}, nil
func (o *OPStorage) ValidateJWTProfileScopes(context.Context, string, []string) ([]string, error) {
panic(o.panicErr("ValidateJWTProfileScopes"))
}
func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes []string) (_ []string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
user, err := o.query.GetUserByID(ctx, true, subject)
if err != nil {
return nil, err
}
return o.checkOrgScopes(ctx, user, scopes)
func (o *OPStorage) AuthorizeClientIDSecret(context.Context, string, string) error {
panic(o.panicErr("AuthorizeClientIDSecret"))
}
func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
ctx = authz.SetCtxData(ctx, authz.CtxData{
UserID: oidcCtx,
OrgID: oidcCtx,
})
app, err := o.query.AppByClientID(ctx, id)
if err != nil {
return err
}
if app.OIDCConfig != nil {
return o.command.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret)
}
return o.command.VerifyAPIClientSecret(ctx, app.ProjectID, app.ID, secret)
func (o *OPStorage) SetUserinfoFromToken(context.Context, *oidc.UserInfo, string, string, string) error {
panic(o.panicErr("SetUserinfoFromToken"))
}
func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo *oidc.UserInfo, tokenID, subject, origin string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
if strings.HasPrefix(tokenID, command.IDPrefixV2) {
token, err := o.query.ActiveAccessTokenByToken(ctx, tokenID)
if err != nil {
return err
}
if err = o.isOriginAllowed(ctx, token.ClientID, origin); err != nil {
return err
}
return o.setUserinfo(ctx, userInfo, token.UserID, token.ClientID, token.Scope, nil)
}
token, err := o.repo.TokenByIDs(ctx, subject, tokenID)
if err != nil {
return zerrors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
if token.ApplicationID != "" {
if err = o.isOriginAllowed(ctx, token.ApplicationID, origin); err != nil {
return err
}
}
return o.setUserinfo(ctx, userInfo, token.UserID, token.ApplicationID, token.Scopes, nil)
func (o *OPStorage) SetUserinfoFromScopes(context.Context, *oidc.UserInfo, string, string, []string) error {
panic(o.panicErr("SetUserinfoFromScopes"))
}
func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo *oidc.UserInfo, userID, applicationID string, scopes []string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
if applicationID != "" {
app, err := o.query.AppByOIDCClientID(ctx, applicationID)
if err != nil {
return err
}
if app.OIDCConfig.AssertIDTokenRole {
scopes, err = o.assertProjectRoleScopes(ctx, applicationID, scopes)
if err != nil {
return zerrors.ThrowPreconditionFailed(err, "OIDC-Dfe2s", "Errors.Internal")
}
}
}
return o.setUserinfo(ctx, userInfo, userID, applicationID, scopes, nil)
func (o *OPStorage) SetUserinfoFromRequest(context.Context, *oidc.UserInfo, op.IDTokenRequest, []string) error {
panic(o.panicErr("SetUserinfoFromRequest"))
}
// SetUserinfoFromRequest extends the SetUserinfoFromScopes during the id_token generation.
// This is required for V2 tokens to be able to set the sessionID (`sid`) claim.
func (o *OPStorage) SetUserinfoFromRequest(ctx context.Context, userinfo *oidc.UserInfo, request op.IDTokenRequest, _ []string) error {
switch t := request.(type) {
case *AuthRequestV2:
userinfo.AppendClaims("sid", t.SessionID)
case *RefreshTokenRequestV2:
userinfo.AppendClaims("sid", t.SessionID)
}
return nil
func (o *OPStorage) SetIntrospectionFromToken(context.Context, *oidc.IntrospectionResponse, string, string, string) error {
panic(o.panicErr("SetIntrospectionFromToken"))
}
func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection *oidc.IntrospectionResponse, tokenID, subject, clientID string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
if strings.HasPrefix(tokenID, command.IDPrefixV2) {
token, err := o.query.ActiveAccessTokenByToken(ctx, tokenID)
if err != nil {
return err
}
projectID, err := o.query.ProjectIDFromClientID(ctx, clientID)
if err != nil {
return zerrors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
return o.introspect(ctx, introspection,
tokenID, token.UserID, token.ClientID, clientID, projectID,
token.Audience, token.Scope,
token.AccessTokenCreation, token.AccessTokenExpiration)
}
token, err := o.repo.TokenByIDs(ctx, subject, tokenID)
if err != nil {
return zerrors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
projectID, err := o.query.ProjectIDFromClientID(ctx, clientID)
if err != nil {
return zerrors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
if token.IsPAT {
err = o.assertClientScopesForPAT(ctx, token, clientID, projectID)
if err != nil {
return zerrors.ThrowPreconditionFailed(err, "OIDC-AGefw", "Errors.Internal")
}
}
return o.introspect(ctx, introspection,
token.ID, token.UserID, token.ApplicationID, clientID, projectID,
token.Audience, token.Scopes,
token.CreationDate, token.Expiration)
func (o *OPStorage) ClientCredentialsTokenRequest(context.Context, string, []string) (op.TokenRequest, error) {
panic(o.panicErr("ClientCredentialsTokenRequest"))
}
func (o *OPStorage) ClientCredentialsTokenRequest(ctx context.Context, clientID string, scope []string) (_ op.TokenRequest, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
user, err := o.query.GetUserByLoginName(ctx, false, clientID)
if err != nil {
return nil, err
}
scope, err = o.checkOrgScopes(ctx, user, scope)
if err != nil {
return nil, err
}
audience := domain.AddAudScopeToAudience(ctx, nil, scope)
return &clientCredentialsRequest{
sub: user.ID,
scopes: scope,
audience: audience,
}, nil
}
// ClientCredentials method is kept to keep the storage interface implemented.
// However, it should never be called as the VerifyClient method on the Server is overridden.
func (o *OPStorage) ClientCredentials(context.Context, string, string) (op.Client, error) {
return nil, zerrors.ThrowInternal(nil, "OIDC-Su8So", "Errors.Internal")
panic(o.panicErr("ClientCredentials"))
}
// isOriginAllowed checks whether a call by the client to the endpoint is allowed from the provided origin
// if no origin is provided, no error will be returned
func (o *OPStorage) isOriginAllowed(ctx context.Context, clientID, origin string) error {
if origin == "" {
return nil
}
app, err := o.query.AppByOIDCClientID(ctx, clientID)
if err != nil {
return err
}
if api_http.IsOriginAllowed(app.OIDCConfig.AllowedOrigins, origin) {
return nil
}
return zerrors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
}
func (o *OPStorage) introspect(
ctx context.Context,
introspection *oidc.IntrospectionResponse,
tokenID, subject, tokenClientID, introspectionClientID, introspectionProjectID string,
audience, scope []string,
tokenCreation, tokenExpiration time.Time,
) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
for _, aud := range audience {
if aud == introspectionClientID || aud == introspectionProjectID {
userInfo := new(oidc.UserInfo)
err = o.setUserinfo(ctx, userInfo, subject, introspectionClientID, scope, []string{introspectionProjectID})
if err != nil {
return err
}
introspection.SetUserInfo(userInfo)
introspection.Scope = scope
introspection.ClientID = tokenClientID
introspection.TokenType = oidc.BearerToken
introspection.Expiration = oidc.FromTime(tokenExpiration)
introspection.IssuedAt = oidc.FromTime(tokenCreation)
introspection.NotBefore = oidc.FromTime(tokenCreation)
introspection.Audience = audience
introspection.Issuer = op.IssuerFromContext(ctx)
introspection.JWTID = tokenID
return nil
}
}
return zerrors.ThrowPermissionDenied(nil, "OIDC-sdg3G", "token is not valid for this client")
}
func (o *OPStorage) checkOrgScopes(ctx context.Context, user *query.User, scopes []string) ([]string, error) {
for i := len(scopes) - 1; i >= 0; i-- {
scope := scopes[i]
if strings.HasPrefix(scope, domain.OrgDomainPrimaryScope) {
var orgID string
org, err := o.query.OrgByPrimaryDomain(ctx, strings.TrimPrefix(scope, domain.OrgDomainPrimaryScope))
if err == nil {
orgID = org.ID
}
if orgID != user.ResourceOwner {
scopes[i] = scopes[len(scopes)-1]
scopes[len(scopes)-1] = ""
scopes = scopes[:len(scopes)-1]
}
}
if strings.HasPrefix(scope, domain.OrgIDScope) {
if strings.TrimPrefix(scope, domain.OrgIDScope) != user.ResourceOwner {
scopes[i] = scopes[len(scopes)-1]
scopes[len(scopes)-1] = ""
scopes = scopes[:len(scopes)-1]
}
}
}
return scopes, nil
}
func (o *OPStorage) setUserinfo(ctx context.Context, userInfo *oidc.UserInfo, userID, applicationID string, scopes []string, roleAudience []string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
user, err := o.query.GetUserByID(ctx, true, userID)
if err != nil {
return err
}
if user.State != domain.UserStateActive {
return zerrors.ThrowUnauthenticated(nil, "OIDC-S3tha", "Errors.Users.NotActive")
}
var allRoles bool
roles := make([]string, 0)
for _, scope := range scopes {
switch scope {
case oidc.ScopeOpenID:
userInfo.Subject = user.ID
case oidc.ScopeEmail:
setUserInfoEmail(userInfo, user)
case oidc.ScopeProfile:
o.setUserInfoProfile(ctx, userInfo, user)
case oidc.ScopePhone:
setUserInfoPhone(userInfo, user)
case oidc.ScopeAddress:
//TODO: handle address for human users as soon as implemented
case ScopeUserMetaData:
if err := o.setUserInfoMetadata(ctx, userInfo, userID); err != nil {
return err
}
case ScopeResourceOwner:
if err := o.setUserInfoResourceOwner(ctx, userInfo, userID); err != nil {
return err
}
case ScopeProjectsRoles:
allRoles = true
default:
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
}
if strings.HasPrefix(scope, domain.OrgDomainPrimaryScope) {
userInfo.AppendClaims(domain.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, domain.OrgDomainPrimaryScope))
}
if strings.HasPrefix(scope, domain.OrgIDScope) {
userInfo.AppendClaims(domain.OrgIDClaim, strings.TrimPrefix(scope, domain.OrgIDScope))
if err := o.setUserInfoResourceOwner(ctx, userInfo, userID); err != nil {
return err
}
}
}
}
// if all roles are requested take the audience for those from the scopes
if allRoles && len(roleAudience) == 0 {
roleAudience = domain.AddAudScopeToAudience(ctx, roleAudience, scopes)
}
userGrants, projectRoles, err := o.assertRoles(ctx, userID, applicationID, roles, roleAudience)
if err != nil {
return err
}
o.setUserInfoRoleClaims(userInfo, projectRoles)
return o.userinfoFlows(ctx, user, userGrants, userInfo)
}
func (o *OPStorage) setUserInfoProfile(ctx context.Context, userInfo *oidc.UserInfo, user *query.User) {
userInfo.PreferredUsername = user.PreferredLoginName
userInfo.UpdatedAt = oidc.FromTime(user.ChangeDate)
if user.Machine != nil {
userInfo.Name = user.Machine.Name
return
}
userInfo.Name = user.Human.DisplayName
userInfo.FamilyName = user.Human.LastName
userInfo.GivenName = user.Human.FirstName
userInfo.Nickname = user.Human.NickName
userInfo.Gender = getGender(user.Human.Gender)
userInfo.Locale = oidc.NewLocale(user.Human.PreferredLanguage)
userInfo.Picture = domain.AvatarURL(o.assetAPIPrefix(ctx), user.ResourceOwner, user.Human.AvatarKey)
}
func setUserInfoEmail(userInfo *oidc.UserInfo, user *query.User) {
if user.Human == nil {
return
}
userInfo.UserInfoEmail = oidc.UserInfoEmail{
Email: string(user.Human.Email),
EmailVerified: oidc.Bool(user.Human.IsEmailVerified)}
}
func setUserInfoPhone(userInfo *oidc.UserInfo, user *query.User) {
if user.Human == nil {
return
}
userInfo.UserInfoPhone = oidc.UserInfoPhone{
PhoneNumber: string(user.Human.Phone),
PhoneNumberVerified: user.Human.IsPhoneVerified,
}
}
func (o *OPStorage) setUserInfoMetadata(ctx context.Context, userInfo *oidc.UserInfo, userID string) error {
userMetaData, err := o.assertUserMetaData(ctx, userID)
if err != nil {
return err
}
if len(userMetaData) > 0 {
userInfo.AppendClaims(ClaimUserMetaData, userMetaData)
}
return nil
}
func (o *OPStorage) setUserInfoResourceOwner(ctx context.Context, userInfo *oidc.UserInfo, userID string) error {
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
if err != nil {
return err
}
for claim, value := range resourceOwnerClaims {
userInfo.AppendClaims(claim, value)
}
return nil
}
func (o *OPStorage) setUserInfoRoleClaims(userInfo *oidc.UserInfo, roles *projectsRoles) {
if roles != nil && len(roles.projects) > 0 {
if roles, ok := roles.projects[roles.requestProjectID]; ok {
userInfo.AppendClaims(ClaimProjectRoles, roles)
}
for projectID, roles := range roles.projects {
userInfo.AppendClaims(fmt.Sprintf(ClaimProjectRolesFormat, projectID), roles)
}
}
}
func (o *OPStorage) userinfoFlows(ctx context.Context, user *query.User, userGrants *query.UserGrants, userInfo *oidc.UserInfo) error {
queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreUserinfoCreation, user.ResourceOwner)
if err != nil {
return err
}
ctxFields := actions.SetContextFields(
actions.SetFields("v1",
actions.SetFields("claims", userinfoClaims(userInfo)),
actions.SetFields("getUser", func(c *actions.FieldConfig) interface{} {
return func(call goja.FunctionCall) goja.Value {
return object.UserFromQuery(c, user)
}
}),
actions.SetFields("user",
actions.SetFields("getMetadata", func(c *actions.FieldConfig) interface{} {
return func(goja.FunctionCall) goja.Value {
resourceOwnerQuery, err := query.NewUserMetadataResourceOwnerSearchQuery(user.ResourceOwner)
if err != nil {
logging.WithError(err).Debug("unable to create search query")
panic(err)
}
metadata, err := o.query.SearchUserMetadata(
ctx,
true,
userInfo.Subject,
&query.UserMetadataSearchQueries{Queries: []query.SearchQuery{resourceOwnerQuery}},
false,
)
if err != nil {
logging.WithError(err).Info("unable to get md in action")
panic(err)
}
return object.UserMetadataListFromQuery(c, metadata)
}
}),
actions.SetFields("grants",
func(c *actions.FieldConfig) interface{} {
return object.UserGrantsFromQuery(ctx, o.query, c, userGrants)
},
),
),
actions.SetFields("org",
actions.SetFields("getMetadata", func(c *actions.FieldConfig) interface{} {
return func(goja.FunctionCall) goja.Value {
return object.GetOrganizationMetadata(ctx, o.query, c, user.ResourceOwner)
}
}),
),
),
)
for _, action := range queriedActions {
actionCtx, cancel := context.WithTimeout(ctx, action.Timeout())
claimLogs := []string{}
apiFields := actions.WithAPIFields(
actions.SetFields("v1",
actions.SetFields("userinfo",
actions.SetFields("setClaim", func(key string, value interface{}) {
if strings.HasPrefix(key, ClaimPrefix) {
return
}
if userInfo.Claims[key] == nil {
userInfo.AppendClaims(key, value)
return
}
claimLogs = append(claimLogs, fmt.Sprintf("key %q already exists", key))
}),
actions.SetFields("appendLogIntoClaims", func(entry string) {
claimLogs = append(claimLogs, entry)
}),
),
actions.SetFields("claims",
actions.SetFields("setClaim", func(key string, value interface{}) {
if strings.HasPrefix(key, ClaimPrefix) {
return
}
if userInfo.Claims[key] == nil {
userInfo.AppendClaims(key, value)
return
}
claimLogs = append(claimLogs, fmt.Sprintf("key %q already exists", key))
}),
actions.SetFields("appendLogIntoClaims", func(entry string) {
claimLogs = append(claimLogs, entry)
}),
),
actions.SetFields("user",
actions.SetFields("setMetadata", func(call goja.FunctionCall) goja.Value {
if len(call.Arguments) != 2 {
panic("exactly 2 (key, value) arguments expected")
}
key := call.Arguments[0].Export().(string)
val := call.Arguments[1].Export()
value, err := json.Marshal(val)
if err != nil {
logging.WithError(err).Debug("unable to marshal")
panic(err)
}
metadata := &domain.Metadata{
Key: key,
Value: value,
}
if _, err = o.command.SetUserMetadata(ctx, metadata, userInfo.Subject, user.ResourceOwner); err != nil {
logging.WithError(err).Info("unable to set md in action")
panic(err)
}
return nil
}),
),
),
)
err = actions.Run(
actionCtx,
ctxFields,
apiFields,
action.Script,
action.Name,
append(actions.ActionToOptions(action), actions.WithHTTP(actionCtx), actions.WithUUID(actionCtx))...,
)
cancel()
if err != nil {
return err
}
if len(claimLogs) > 0 {
userInfo.AppendClaims(fmt.Sprintf(ClaimActionLogFormat, action.Name), claimLogs)
}
}
return nil
}
func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clientID string, scopes []string) (claims map[string]interface{}, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
roles := make([]string, 0)
var allRoles bool
for _, scope := range scopes {
switch scope {
case ScopeUserMetaData:
userMetaData, err := o.assertUserMetaData(ctx, userID)
if err != nil {
return nil, err
}
if len(userMetaData) > 0 {
claims = appendClaim(claims, ClaimUserMetaData, userMetaData)
}
case ScopeResourceOwner:
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
if err != nil {
return nil, err
}
for claim, value := range resourceOwnerClaims {
claims = appendClaim(claims, claim, value)
}
case ScopeProjectsRoles:
allRoles = true
}
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
}
if strings.HasPrefix(scope, domain.OrgDomainPrimaryScope) {
claims = appendClaim(claims, domain.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, domain.OrgDomainPrimaryScope))
}
if strings.HasPrefix(scope, domain.OrgIDScope) {
claims = appendClaim(claims, domain.OrgIDClaim, strings.TrimPrefix(scope, domain.OrgIDScope))
resourceOwnerClaims, err := o.assertUserResourceOwner(ctx, userID)
if err != nil {
return nil, err
}
for claim, value := range resourceOwnerClaims {
claims = appendClaim(claims, claim, value)
}
}
}
// If requested, use the audience as context for the roles,
// otherwise the project itself will be used
var roleAudience []string
if allRoles {
roleAudience = domain.AddAudScopeToAudience(ctx, roleAudience, scopes)
}
userGrants, projectRoles, err := o.assertRoles(ctx, userID, clientID, roles, roleAudience)
if err != nil {
return nil, err
}
if projectRoles != nil && len(projectRoles.projects) > 0 {
if roles, ok := projectRoles.projects[projectRoles.requestProjectID]; ok {
claims = appendClaim(claims, ClaimProjectRoles, roles)
}
for projectID, roles := range projectRoles.projects {
claims = appendClaim(claims, fmt.Sprintf(ClaimProjectRolesFormat, projectID), roles)
}
}
return o.privateClaimsFlows(ctx, userID, userGrants, claims)
}
func (o *OPStorage) privateClaimsFlows(ctx context.Context, userID string, userGrants *query.UserGrants, claims map[string]interface{}) (map[string]interface{}, error) {
user, err := o.query.GetUserByID(ctx, true, userID)
if err != nil {
return nil, err
}
queriedActions, err := o.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeCustomiseToken, domain.TriggerTypePreAccessTokenCreation, user.ResourceOwner)
if err != nil {
return nil, err
}
ctxFields := actions.SetContextFields(
actions.SetFields("v1",
actions.SetFields("claims", func(c *actions.FieldConfig) interface{} {
return c.Runtime.ToValue(claims)
}),
actions.SetFields("getUser", func(c *actions.FieldConfig) interface{} {
return func(call goja.FunctionCall) goja.Value {
return object.UserFromQuery(c, user)
}
}),
actions.SetFields("user",
actions.SetFields("getMetadata", func(c *actions.FieldConfig) interface{} {
return func(goja.FunctionCall) goja.Value {
resourceOwnerQuery, err := query.NewUserMetadataResourceOwnerSearchQuery(user.ResourceOwner)
if err != nil {
logging.WithError(err).Debug("unable to create search query")
panic(err)
}
metadata, err := o.query.SearchUserMetadata(
ctx,
true,
userID,
&query.UserMetadataSearchQueries{Queries: []query.SearchQuery{resourceOwnerQuery}},
false,
)
if err != nil {
logging.WithError(err).Info("unable to get md in action")
panic(err)
}
return object.UserMetadataListFromQuery(c, metadata)
}
}),
actions.SetFields("grants", func(c *actions.FieldConfig) interface{} {
return object.UserGrantsFromQuery(ctx, o.query, c, userGrants)
}),
),
actions.SetFields("org",
actions.SetFields("getMetadata", func(c *actions.FieldConfig) interface{} {
return func(goja.FunctionCall) goja.Value {
return object.GetOrganizationMetadata(ctx, o.query, c, user.ResourceOwner)
}
}),
),
),
)
for _, action := range queriedActions {
claimLogs := []string{}
actionCtx, cancel := context.WithTimeout(ctx, action.Timeout())
apiFields := actions.WithAPIFields(
actions.SetFields("v1",
actions.SetFields("claims",
actions.SetFields("setClaim", func(key string, value interface{}) {
if strings.HasPrefix(key, ClaimPrefix) {
return
}
if _, ok := claims[key]; !ok {
claims = appendClaim(claims, key, value)
return
}
claimLogs = append(claimLogs, fmt.Sprintf("key %q already exists", key))
}),
actions.SetFields("appendLogIntoClaims", func(entry string) {
claimLogs = append(claimLogs, entry)
}),
),
actions.SetFields("user",
actions.SetFields("setMetadata", func(call goja.FunctionCall) goja.Value {
if len(call.Arguments) != 2 {
panic("exactly 2 (key, value) arguments expected")
}
key := call.Arguments[0].Export().(string)
val := call.Arguments[1].Export()
value, err := json.Marshal(val)
if err != nil {
logging.WithError(err).Debug("unable to marshal")
panic(err)
}
metadata := &domain.Metadata{
Key: key,
Value: value,
}
if _, err = o.command.SetUserMetadata(ctx, metadata, userID, user.ResourceOwner); err != nil {
logging.WithError(err).Info("unable to set md in action")
panic(err)
}
return nil
}),
),
),
)
err = actions.Run(
actionCtx,
ctxFields,
apiFields,
action.Script,
action.Name,
append(actions.ActionToOptions(action), actions.WithHTTP(actionCtx), actions.WithUUID(actionCtx))...,
)
cancel()
if err != nil {
return nil, err
}
if len(claimLogs) > 0 {
claims = appendClaim(claims, fmt.Sprintf(ClaimActionLogFormat, action.Name), claimLogs)
claimLogs = nil
}
}
return claims, nil
}
func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID string, requestedRoles, roleAudience []string) (*query.UserGrants, *projectsRoles, error) {
if (applicationID == "" || len(requestedRoles) == 0) && len(roleAudience) == 0 {
return nil, nil, nil
}
projectID, err := o.query.ProjectIDFromClientID(ctx, applicationID)
// applicationID might contain a username (e.g. client credentials) -> ignore the not found
if err != nil && !zerrors.IsNotFound(err) {
return nil, nil, err
}
// ensure the projectID of the requesting is part of the roleAudience
if projectID != "" {
roleAudience = append(roleAudience, projectID)
}
projectQuery, err := query.NewUserGrantProjectIDsSearchQuery(roleAudience)
if err != nil {
return nil, nil, err
}
userIDQuery, err := query.NewUserGrantUserIDSearchQuery(userID)
if err != nil {
return nil, nil, err
}
activeQuery, err := query.NewUserGrantStateQuery(domain.UserGrantStateActive)
if err != nil {
return nil, nil, err
}
grants, err := o.query.UserGrants(ctx, &query.UserGrantsQueries{
Queries: []query.SearchQuery{
projectQuery,
userIDQuery,
activeQuery,
},
}, true)
if err != nil {
return nil, nil, err
}
roles := new(projectsRoles)
// if specific roles where requested, check if they are granted and append them in the roles list
if len(requestedRoles) > 0 {
for _, requestedRole := range requestedRoles {
for _, grant := range grants.UserGrants {
checkGrantedRoles(roles, *grant, requestedRole, grant.ProjectID == projectID)
}
}
return grants, roles, nil
}
// no specific roles were requested, so convert any grants into roles
for _, grant := range grants.UserGrants {
for _, role := range grant.Roles {
roles.Add(grant.ProjectID, role, grant.ResourceOwner, grant.OrgPrimaryDomain, grant.ProjectID == projectID)
}
}
return grants, roles, nil
}
func (o *OPStorage) assertUserMetaData(ctx context.Context, userID string) (map[string]string, error) {
metaData, err := o.query.SearchUserMetadata(ctx, true, userID, &query.UserMetadataSearchQueries{}, false)
if err != nil {
return nil, err
}
userMetaData := make(map[string]string)
for _, md := range metaData.Metadata {
userMetaData[md.Key] = base64.RawURLEncoding.EncodeToString(md.Value)
}
return userMetaData, nil
}
func (o *OPStorage) assertUserResourceOwner(ctx context.Context, userID string) (map[string]string, error) {
user, err := o.query.GetUserByID(ctx, true, userID)
if err != nil {
return nil, err
}
resourceOwner, err := o.query.OrgByID(ctx, true, user.ResourceOwner)
if err != nil {
return nil, err
}
return map[string]string{
ClaimResourceOwnerID: resourceOwner.ID,
ClaimResourceOwnerName: resourceOwner.Name,
ClaimResourceOwnerPrimaryDomain: resourceOwner.Domain,
}, nil
func (o *OPStorage) GetPrivateClaimsFromScopes(context.Context, string, string, []string) (map[string]interface{}, error) {
panic(o.panicErr("GetPrivateClaimsFromScopes"))
}
func checkGrantedRoles(roles *projectsRoles, grant query.UserGrant, requestedRole string, isRequested bool) {
@ -946,14 +166,6 @@ func getGender(gender domain.Gender) oidc.Gender {
return ""
}
func appendClaim(claims map[string]interface{}, claim string, value interface{}) map[string]interface{} {
if claims == nil {
claims = make(map[string]interface{})
}
claims[claim] = value
return claims
}
func userinfoClaims(userInfo *oidc.UserInfo) func(c *actions.FieldConfig) interface{} {
return func(c *actions.FieldConfig) interface{} {
marshalled, err := json.Marshal(userInfo)

View File

@ -14,27 +14,6 @@ import (
"github.com/zitadel/zitadel/internal/zerrors"
)
type clientCredentialsRequest struct {
sub string
audience []string
scopes []string
}
// GetSubject returns the subject for token to be created because of the client credentials request
// the subject will be the id of the service user
func (c *clientCredentialsRequest) GetSubject() string {
return c.sub
}
// GetAudience returns the audience for token to be created because of the client credentials request
func (c *clientCredentialsRequest) GetAudience() []string {
return c.audience
}
func (c *clientCredentialsRequest) GetScopes() []string {
return c.scopes
}
func (s *Server) clientCredentialsAuth(ctx context.Context, clientID, clientSecret string) (op.Client, error) {
user, err := s.query.GetUserByLoginName(ctx, false, clientID)
if zerrors.IsNotFound(err) {

View File

@ -88,6 +88,6 @@ func (o *OPStorage) StoreDeviceAuthorization(ctx context.Context, clientID, devi
return err
}
func (o *OPStorage) GetDeviceAuthorizatonState(ctx context.Context, _, deviceCode string) (state *op.DeviceAuthorizationState, err error) {
return nil, nil
func (o *OPStorage) GetDeviceAuthorizatonState(context.Context, string, string) (*op.DeviceAuthorizationState, error) {
panic(o.panicErr("GetDeviceAuthorizatonState"))
}

View File

@ -52,13 +52,6 @@ func setTokenExchangeFeature(t *testing.T, instance *integration.Instance, value
time.Sleep(time.Second)
}
func resetFeatures(t *testing.T, instance *integration.Instance) {
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
_, err := instance.Client.FeatureV2.ResetInstanceFeatures(iamCTX, &feature.ResetInstanceFeaturesRequest{})
require.NoError(t, err)
time.Sleep(time.Second)
}
func setImpersonationPolicy(t *testing.T, instance *integration.Instance, value bool) {
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)

View File

@ -34,22 +34,11 @@ func TestServer_UserInfo(t *testing.T) {
})
tests := []struct {
name string
legacy bool
trigger bool
webKey bool
}{
{
name: "legacy enabled",
legacy: true,
},
{
name: "legacy disabled, trigger disabled",
legacy: false,
trigger: false,
},
{
name: "legacy disabled, trigger enabled",
legacy: false,
name: "trigger enabled",
trigger: true,
},
@ -59,7 +48,6 @@ func TestServer_UserInfo(t *testing.T) {
// - By calling userinfo with the access token as JWT, the Token Verifier with the public key cache is tested.
{
name: "web keys",
legacy: false,
trigger: false,
webKey: true,
},
@ -68,7 +56,6 @@ func TestServer_UserInfo(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := Instance.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
OidcLegacyIntrospection: &tt.legacy,
OidcTriggerIntrospectionProjections: &tt.trigger,
WebKey: &tt.webKey,
})

View File

@ -25,9 +25,6 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR
}()
features := authz.GetFeatures(ctx)
if features.LegacyIntrospection {
return s.LegacyServer.Introspect(ctx, r)
}
if features.TriggerIntrospectionProjections {
query.TriggerIntrospectionProjections(ctx)
}

View File

@ -3,38 +3,9 @@ package oidc
import (
"context"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/zerrors"
)
func (o *OPStorage) JWTProfileTokenType(ctx context.Context, request op.TokenRequest) (_ op.AccessTokenType, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() {
err = oidcError(err)
span.EndWithError(err)
}()
mapJWTProfileScopesToAudience(ctx, request)
user, err := o.query.GetUserByID(ctx, false, request.GetSubject())
if err != nil {
return 0, err
}
// the user should always be a machine, but let's just be sure
if user.Machine == nil {
return 0, zerrors.ThrowInvalidArgument(nil, "OIDC-jk26S", "invalid client type")
}
return accessTokenTypeToOIDC(user.Machine.AccessTokenType), nil
}
func mapJWTProfileScopesToAudience(ctx context.Context, request op.TokenRequest) {
// the request should always be a JWTTokenRequest, but let's make sure
jwt, ok := request.(*oidc.JWTTokenRequest)
if !ok {
return
}
jwt.Audience = domain.AddAudScopeToAudience(ctx, jwt.Audience, jwt.Scopes)
func (o *OPStorage) JWTProfileTokenType(context.Context, op.TokenRequest) (op.AccessTokenType, error) {
panic(o.panicErr("JWTProfileTokenType"))
}

View File

@ -35,9 +35,6 @@ func (s *Server) UserInfo(ctx context.Context, r *op.Request[oidc.UserInfoReques
}()
features := authz.GetFeatures(ctx)
if features.LegacyIntrospection {
return s.LegacyServer.UserInfo(ctx, r)
}
if features.TriggerIntrospectionProjections {
query.TriggerOIDCUserInfoProjections(ctx)
}

View File

@ -18,7 +18,6 @@ import (
type InstanceFeatures struct {
LoginDefaultOrg *bool
TriggerIntrospectionProjections *bool
LegacyIntrospection *bool
UserSchema *bool
TokenExchange *bool
ImprovedPerformance []feature.ImprovedPerformanceType
@ -35,7 +34,6 @@ type InstanceFeatures struct {
func (m *InstanceFeatures) isEmpty() bool {
return m.LoginDefaultOrg == nil &&
m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
// nil check to allow unset improvements

View File

@ -68,7 +68,6 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceResetEventType,
feature_v2.InstanceLoginDefaultOrgEventType,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType,
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceImprovedPerformanceEventType,
@ -98,9 +97,6 @@ func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value an
case feature.KeyTriggerIntrospectionProjections:
v := value.(bool)
features.TriggerIntrospectionProjections = &v
case feature.KeyLegacyIntrospection:
v := value.(bool)
features.LegacyIntrospection = &v
case feature.KeyTokenExchange:
v := value.(bool)
features.TokenExchange = &v
@ -141,7 +137,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan
cmds := make([]eventstore.Command, 0, len(feature.KeyValues())-1)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LoginDefaultOrg, f.LoginDefaultOrg, feature_v2.InstanceLoginDefaultOrgEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TriggerIntrospectionProjections, f.TriggerIntrospectionProjections, feature_v2.InstanceTriggerIntrospectionProjectionsEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.InstanceLegacyIntrospectionEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.InstanceImprovedPerformanceEventType)

View File

@ -113,24 +113,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ResourceOwner: "instance1",
},
},
{
name: "set LegacyIntrospection",
eventstore: expectEventstore(
expectFilter(),
expectPush(
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, true,
),
),
),
args: args{ctx, &InstanceFeatures{
LegacyIntrospection: gu.Ptr(true),
}},
want: &domain.ObjectDetails{
ResourceOwner: "instance1",
},
},
{
name: "set UserSchema",
eventstore: expectEventstore(
@ -156,12 +138,12 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
expectPushFailed(io.ErrClosedPipe,
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, true,
feature_v2.InstanceConsoleUseV2UserApi, true,
),
),
),
args: args{ctx, &InstanceFeatures{
LegacyIntrospection: gu.Ptr(true),
ConsoleUseV2UserApi: gu.Ptr(true),
}},
wantErr: io.ErrClosedPipe,
},
@ -178,10 +160,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType, false,
),
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, true,
),
feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, true,
@ -195,7 +173,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
args: args{ctx, &InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
}},
@ -224,10 +201,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceLoginDefaultOrgEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, true,
)),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType, false,
@ -247,7 +220,6 @@ func TestCommands_SetInstanceFeatures(t *testing.T) {
args: args{ctx, &InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(false),
}},
want: &domain.ObjectDetails{

View File

@ -226,37 +226,6 @@ func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, ap
return result, err
}
func (c *Commands) VerifyAPIClientSecret(ctx context.Context, projectID, appID, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
app, err := c.getAPIAppWriteModel(ctx, projectID, appID, "")
if err != nil {
return err
}
if !app.State.Exists() {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-DFnbf", "Errors.Project.App.NotExisting")
}
if !app.IsAPI() {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Bf3fw", "Errors.Project.App.IsNotAPI")
}
if app.HashedSecret == "" {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D3t5g", "Errors.Project.App.APIConfigInvalid")
}
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
updated, err := c.secretHasher.Verify(app.HashedSecret, secret)
spanPasswordComparison.EndWithError(err)
if err != nil {
return zerrors.ThrowInvalidArgument(err, "COMMAND-SADfg", "Errors.Project.App.ClientSecretInvalid")
}
if updated != "" {
c.apiUpdateSecret(ctx, projectAgg, app.AppID, updated)
}
return nil
}
func (c *Commands) APIUpdateSecret(ctx context.Context, appID, projectID, resourceOwner, updated string) {
agg := project_repo.NewAggregate(projectID, resourceOwner)
c.apiUpdateSecret(ctx, &agg.Aggregate, appID, updated)

View File

@ -2,16 +2,11 @@ package command
import (
"context"
"io"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/passwap"
"github.com/zitadel/passwap/bcrypt"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
@ -771,99 +766,3 @@ func newAPIAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner
)
return event
}
func TestCommands_VerifyAPIClientSecret(t *testing.T) {
hasher := &crypto.Hasher{
Swapper: passwap.NewSwapper(bcrypt.New(bcrypt.MinCost)),
}
hashedSecret, err := hasher.Hash("secret")
require.NoError(t, err)
agg := project.NewAggregate("projectID", "orgID")
tests := []struct {
name string
secret string
eventstore func(*testing.T) *eventstore.Eventstore
wantErr error
}{
{
name: "filter error",
eventstore: expectEventstore(
expectFilterError(io.ErrClosedPipe),
),
wantErr: io.ErrClosedPipe,
},
{
name: "app not exists",
eventstore: expectEventstore(
expectFilter(),
),
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-DFnbf", "Errors.Project.App.NotExisting"),
},
{
name: "wrong app type",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
),
),
wantErr: zerrors.ThrowInvalidArgument(nil, "COMMAND-Bf3fw", "Errors.Project.App.IsNotAPI"),
},
{
name: "no secret set",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", "", domain.APIAuthMethodTypePrivateKeyJWT),
),
),
),
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D3t5g", "Errors.Project.App.APIConfigInvalid"),
},
{
name: "check succeeded",
secret: "secret",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", hashedSecret, domain.APIAuthMethodTypePrivateKeyJWT),
),
),
),
},
{
name: "check failed",
secret: "wrong!",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", hashedSecret, domain.APIAuthMethodTypePrivateKeyJWT),
),
),
),
wantErr: zerrors.ThrowInvalidArgument(err, "COMMAND-SADfg", "Errors.Project.App.ClientSecretInvalid"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.eventstore(t),
secretHasher: hasher,
}
err := c.VerifyAPIClientSecret(context.Background(), "projectID", "appID", tt.secret)
c.jobs.Wait()
require.ErrorIs(t, err, tt.wantErr)
})
}
}

View File

@ -322,37 +322,6 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a
return result, err
}
func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
app, err := c.getOIDCAppWriteModel(ctx, projectID, appID, "")
if err != nil {
return err
}
if !app.State.Exists() {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D8hba", "Errors.Project.App.NotExisting")
}
if !app.IsOIDC() {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC")
}
if app.HashedSecret == "" {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid")
}
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
updated, err := c.secretHasher.Verify(app.HashedSecret, secret)
spanPasswordComparison.EndWithError(err)
if err != nil {
return zerrors.ThrowInvalidArgument(err, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid")
}
if updated != "" {
c.oidcUpdateSecret(ctx, projectAgg, appID, updated)
}
return nil
}
func (c *Commands) OIDCUpdateSecret(ctx context.Context, appID, projectID, resourceOwner, updated string) {
agg := project_repo.NewAggregate(projectID, resourceOwner)
c.oidcUpdateSecret(ctx, &agg.Aggregate, appID, updated)

View File

@ -2,18 +2,13 @@ package command
import (
"context"
"io"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/passwap"
"github.com/zitadel/passwap/bcrypt"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
@ -1307,168 +1302,3 @@ func newOIDCAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner
)
return event
}
func TestCommands_VerifyOIDCClientSecret(t *testing.T) {
hasher := &crypto.Hasher{
Swapper: passwap.NewSwapper(bcrypt.New(bcrypt.MinCost)),
}
hashedSecret, err := hasher.Hash("secret")
require.NoError(t, err)
agg := project.NewAggregate("projectID", "orgID")
tests := []struct {
name string
secret string
eventstore func(*testing.T) *eventstore.Eventstore
wantErr error
}{
{
name: "filter error",
eventstore: expectEventstore(
expectFilterError(io.ErrClosedPipe),
),
wantErr: io.ErrClosedPipe,
},
{
name: "app not exists",
eventstore: expectEventstore(
expectFilter(),
),
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D8hba", "Errors.Project.App.NotExisting"),
},
{
name: "wrong app type",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
),
),
wantErr: zerrors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC"),
},
{
name: "no secret set",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewOIDCConfigAddedEvent(context.Background(),
&agg.Aggregate,
domain.OIDCVersionV1,
"appID",
"client1@project",
"",
[]string{"https://test.ch"},
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
domain.OIDCApplicationTypeWeb,
domain.OIDCAuthMethodTypePost,
[]string{"https://test.ch/logout"},
true,
domain.OIDCTokenTypeBearer,
true,
true,
true,
time.Second*1,
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
),
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid"),
},
{
name: "check succeeded",
secret: "secret",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewOIDCConfigAddedEvent(context.Background(),
&agg.Aggregate,
domain.OIDCVersionV1,
"appID",
"client1@project",
hashedSecret,
[]string{"https://test.ch"},
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
domain.OIDCApplicationTypeWeb,
domain.OIDCAuthMethodTypePost,
[]string{"https://test.ch/logout"},
true,
domain.OIDCTokenTypeBearer,
true,
true,
true,
time.Second*1,
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
),
},
{
name: "check failed",
secret: "wrong!",
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
),
eventFromEventPusher(
project.NewOIDCConfigAddedEvent(context.Background(),
&agg.Aggregate,
domain.OIDCVersionV1,
"appID",
"client1@project",
hashedSecret,
[]string{"https://test.ch"},
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
domain.OIDCApplicationTypeWeb,
domain.OIDCAuthMethodTypePost,
[]string{"https://test.ch/logout"},
true,
domain.OIDCTokenTypeBearer,
true,
true,
true,
time.Second*1,
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
),
wantErr: zerrors.ThrowInvalidArgument(err, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.eventstore(t),
secretHasher: hasher,
}
err := c.VerifyOIDCClientSecret(context.Background(), "projectID", "appID", tt.secret)
c.jobs.Wait()
require.ErrorIs(t, err, tt.wantErr)
})
}
}

View File

@ -12,7 +12,6 @@ import (
type SystemFeatures struct {
LoginDefaultOrg *bool
TriggerIntrospectionProjections *bool
LegacyIntrospection *bool
TokenExchange *bool
UserSchema *bool
ImprovedPerformance []feature.ImprovedPerformanceType
@ -26,7 +25,6 @@ type SystemFeatures struct {
func (m *SystemFeatures) isEmpty() bool {
return m.LoginDefaultOrg == nil &&
m.TriggerIntrospectionProjections == nil &&
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
// nil check to allow unset improvements

View File

@ -61,7 +61,6 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemResetEventType,
feature_v2.SystemLoginDefaultOrgEventType,
feature_v2.SystemTriggerIntrospectionProjectionsEventType,
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemImprovedPerformanceEventType,
@ -88,9 +87,6 @@ func reduceSystemFeature(features *SystemFeatures, key feature.Key, value any) {
case feature.KeyTriggerIntrospectionProjections:
v := value.(bool)
features.TriggerIntrospectionProjections = &v
case feature.KeyLegacyIntrospection:
v := value.(bool)
features.LegacyIntrospection = &v
case feature.KeyUserSchema:
v := value.(bool)
features.UserSchema = &v
@ -121,7 +117,6 @@ func (wm *SystemFeaturesWriteModel) setCommands(ctx context.Context, f *SystemFe
cmds := make([]eventstore.Command, 0, len(feature.KeyValues())-1)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LoginDefaultOrg, f.LoginDefaultOrg, feature_v2.SystemLoginDefaultOrgEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TriggerIntrospectionProjections, f.TriggerIntrospectionProjections, feature_v2.SystemTriggerIntrospectionProjectionsEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LegacyIntrospection, f.LegacyIntrospection, feature_v2.SystemLegacyIntrospectionEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.SystemTokenExchangeEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.SystemImprovedPerformanceEventType)

View File

@ -81,24 +81,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
ResourceOwner: "SYSTEM",
},
},
{
name: "set LegacyIntrospection",
eventstore: expectEventstore(
expectFilter(),
expectPush(
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, true,
),
),
),
args: args{context.Background(), &SystemFeatures{
LegacyIntrospection: gu.Ptr(true),
}},
want: &domain.ObjectDetails{
ResourceOwner: "SYSTEM",
},
},
{
name: "set UserSchema",
eventstore: expectEventstore(
@ -124,12 +106,12 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
expectPushFailed(io.ErrClosedPipe,
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, true,
feature_v2.SystemEnableBackChannelLogout, true,
),
),
),
args: args{context.Background(), &SystemFeatures{
LegacyIntrospection: gu.Ptr(true),
EnableBackChannelLogout: gu.Ptr(true),
}},
wantErr: io.ErrClosedPipe,
},
@ -146,10 +128,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemTriggerIntrospectionProjectionsEventType, false,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, true,
),
feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, true,
@ -163,7 +141,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
args: args{context.Background(), &SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
}},
@ -192,10 +169,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemLoginDefaultOrgEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent[bool](
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, true,
)),
),
expectPush(
feature_v2.NewSetEvent[bool](
@ -219,7 +192,6 @@ func TestCommands_SetSystemFeatures(t *testing.T) {
args: args{context.Background(), &SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
TriggerIntrospectionProjections: gu.Ptr(false),
LegacyIntrospection: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(false),
}},

View File

@ -9,22 +9,22 @@ import (
type Key int
const (
KeyUnspecified Key = iota
KeyLoginDefaultOrg
KeyTriggerIntrospectionProjections
KeyLegacyIntrospection
KeyUserSchema
KeyTokenExchange
KeyActionsDeprecated
KeyImprovedPerformance
KeyWebKey
KeyDebugOIDCParentError
KeyOIDCSingleV1SessionTermination
KeyDisableUserTokenEvent
KeyEnableBackChannelLogout
KeyLoginV2
KeyPermissionCheckV2
KeyConsoleUseV2UserApi
// Reserved: 3, 6
KeyUnspecified Key = 0
KeyLoginDefaultOrg Key = 1
KeyTriggerIntrospectionProjections Key = 2
KeyUserSchema Key = 4
KeyTokenExchange Key = 5
KeyImprovedPerformance Key = 7
KeyWebKey Key = 8
KeyDebugOIDCParentError Key = 9
KeyOIDCSingleV1SessionTermination Key = 10
KeyDisableUserTokenEvent Key = 11
KeyEnableBackChannelLogout Key = 12
KeyLoginV2 Key = 13
KeyPermissionCheckV2 Key = 14
KeyConsoleUseV2UserApi Key = 15
)
//go:generate enumer -type Level -transform snake -trimprefix Level
@ -43,7 +43,6 @@ const (
type Features struct {
LoginDefaultOrg bool `json:"login_default_org,omitempty"`
TriggerIntrospectionProjections bool `json:"trigger_introspection_projections,omitempty"`
LegacyIntrospection bool `json:"legacy_introspection,omitempty"`
UserSchema bool `json:"user_schema,omitempty"`
TokenExchange bool `json:"token_exchange,omitempty"`
ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"`

View File

@ -12,7 +12,6 @@ func TestKey(t *testing.T) {
"unspecified",
"login_default_org",
"trigger_introspection_projections",
"legacy_introspection",
}
for _, want := range tests {
t.Run(want, func(t *testing.T) {

View File

@ -7,17 +7,34 @@ import (
"strings"
)
const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions_deprecatedimproved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
const (
_KeyName_0 = "unspecifiedlogin_default_orgtrigger_introspection_projections"
_KeyLowerName_0 = "unspecifiedlogin_default_orgtrigger_introspection_projections"
_KeyName_1 = "user_schematoken_exchange"
_KeyLowerName_1 = "user_schematoken_exchange"
_KeyName_2 = "improved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
_KeyLowerName_2 = "improved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
)
var _KeyIndex = [...]uint16{0, 11, 28, 61, 81, 92, 106, 124, 144, 151, 174, 208, 232, 258, 266, 285, 308}
const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions_deprecatedimproved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
var (
_KeyIndex_0 = [...]uint8{0, 11, 28, 61}
_KeyIndex_1 = [...]uint8{0, 11, 25}
_KeyIndex_2 = [...]uint8{0, 20, 27, 50, 84, 108, 134, 142, 161, 184}
)
func (i Key) String() string {
if i < 0 || i >= Key(len(_KeyIndex)-1) {
switch {
case 0 <= i && i <= 2:
return _KeyName_0[_KeyIndex_0[i]:_KeyIndex_0[i+1]]
case 4 <= i && i <= 5:
i -= 4
return _KeyName_1[_KeyIndex_1[i]:_KeyIndex_1[i+1]]
case 7 <= i && i <= 15:
i -= 7
return _KeyName_2[_KeyIndex_2[i]:_KeyIndex_2[i+1]]
default:
return fmt.Sprintf("Key(%d)", i)
}
return _KeyName[_KeyIndex[i]:_KeyIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
@ -27,10 +44,8 @@ func _KeyNoOp() {
_ = x[KeyUnspecified-(0)]
_ = x[KeyLoginDefaultOrg-(1)]
_ = x[KeyTriggerIntrospectionProjections-(2)]
_ = x[KeyLegacyIntrospection-(3)]
_ = x[KeyUserSchema-(4)]
_ = x[KeyTokenExchange-(5)]
_ = x[KeyActionsDeprecated-(6)]
_ = x[KeyImprovedPerformance-(7)]
_ = x[KeyWebKey-(8)]
_ = x[KeyDebugOIDCParentError-(9)]
@ -42,60 +57,54 @@ func _KeyNoOp() {
_ = x[KeyConsoleUseV2UserApi-(15)]
}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActionsDeprecated, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyUserSchema, KeyTokenExchange, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
var _KeyNameToValueMap = map[string]Key{
_KeyName[0:11]: KeyUnspecified,
_KeyLowerName[0:11]: KeyUnspecified,
_KeyName[11:28]: KeyLoginDefaultOrg,
_KeyLowerName[11:28]: KeyLoginDefaultOrg,
_KeyName[28:61]: KeyTriggerIntrospectionProjections,
_KeyLowerName[28:61]: KeyTriggerIntrospectionProjections,
_KeyName[61:81]: KeyLegacyIntrospection,
_KeyLowerName[61:81]: KeyLegacyIntrospection,
_KeyName[81:92]: KeyUserSchema,
_KeyLowerName[81:92]: KeyUserSchema,
_KeyName[92:106]: KeyTokenExchange,
_KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[106:124]: KeyActionsDeprecated,
_KeyLowerName[106:124]: KeyActionsDeprecated,
_KeyName[124:144]: KeyImprovedPerformance,
_KeyLowerName[124:144]: KeyImprovedPerformance,
_KeyName[144:151]: KeyWebKey,
_KeyLowerName[144:151]: KeyWebKey,
_KeyName[151:174]: KeyDebugOIDCParentError,
_KeyLowerName[151:174]: KeyDebugOIDCParentError,
_KeyName[174:208]: KeyOIDCSingleV1SessionTermination,
_KeyLowerName[174:208]: KeyOIDCSingleV1SessionTermination,
_KeyName[208:232]: KeyDisableUserTokenEvent,
_KeyLowerName[208:232]: KeyDisableUserTokenEvent,
_KeyName[232:258]: KeyEnableBackChannelLogout,
_KeyLowerName[232:258]: KeyEnableBackChannelLogout,
_KeyName[258:266]: KeyLoginV2,
_KeyLowerName[258:266]: KeyLoginV2,
_KeyName[266:285]: KeyPermissionCheckV2,
_KeyLowerName[266:285]: KeyPermissionCheckV2,
_KeyName[285:308]: KeyConsoleUseV2UserApi,
_KeyLowerName[285:308]: KeyConsoleUseV2UserApi,
_KeyName_0[0:11]: KeyUnspecified,
_KeyLowerName_0[0:11]: KeyUnspecified,
_KeyName_0[11:28]: KeyLoginDefaultOrg,
_KeyLowerName_0[11:28]: KeyLoginDefaultOrg,
_KeyName_0[28:61]: KeyTriggerIntrospectionProjections,
_KeyLowerName_0[28:61]: KeyTriggerIntrospectionProjections,
_KeyName_1[0:11]: KeyUserSchema,
_KeyLowerName_1[0:11]: KeyUserSchema,
_KeyName_1[11:25]: KeyTokenExchange,
_KeyLowerName_1[11:25]: KeyTokenExchange,
_KeyName_2[0:20]: KeyImprovedPerformance,
_KeyLowerName_2[0:20]: KeyImprovedPerformance,
_KeyName_2[20:27]: KeyWebKey,
_KeyLowerName_2[20:27]: KeyWebKey,
_KeyName_2[27:50]: KeyDebugOIDCParentError,
_KeyLowerName_2[27:50]: KeyDebugOIDCParentError,
_KeyName_2[50:84]: KeyOIDCSingleV1SessionTermination,
_KeyLowerName_2[50:84]: KeyOIDCSingleV1SessionTermination,
_KeyName_2[84:108]: KeyDisableUserTokenEvent,
_KeyLowerName_2[84:108]: KeyDisableUserTokenEvent,
_KeyName_2[108:134]: KeyEnableBackChannelLogout,
_KeyLowerName_2[108:134]: KeyEnableBackChannelLogout,
_KeyName_2[134:142]: KeyLoginV2,
_KeyLowerName_2[134:142]: KeyLoginV2,
_KeyName_2[142:161]: KeyPermissionCheckV2,
_KeyLowerName_2[142:161]: KeyPermissionCheckV2,
_KeyName_2[161:184]: KeyConsoleUseV2UserApi,
_KeyLowerName_2[161:184]: KeyConsoleUseV2UserApi,
}
var _KeyNames = []string{
_KeyName[0:11],
_KeyName[11:28],
_KeyName[28:61],
_KeyName[61:81],
_KeyName[81:92],
_KeyName[92:106],
_KeyName[106:124],
_KeyName[124:144],
_KeyName[144:151],
_KeyName[151:174],
_KeyName[174:208],
_KeyName[208:232],
_KeyName[232:258],
_KeyName[258:266],
_KeyName[266:285],
_KeyName[285:308],
_KeyName_0[0:11],
_KeyName_0[11:28],
_KeyName_0[28:61],
_KeyName_1[0:11],
_KeyName_1[11:25],
_KeyName_2[0:20],
_KeyName_2[20:27],
_KeyName_2[27:50],
_KeyName_2[50:84],
_KeyName_2[84:108],
_KeyName_2[108:134],
_KeyName_2[134:142],
_KeyName_2[142:161],
_KeyName_2[161:184],
}
// KeyString retrieves an enum value from the enum constants string name.

View File

@ -455,27 +455,6 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string) (id s
return id, err
}
func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string) (project *Project, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareProjectByOIDCAppQuery()
eq := sq.Eq{
AppOIDCConfigColumnClientID.identifier(): id,
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-XhJi4", "Errors.Query.SQLStatement")
}
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
project, err = scan(row)
return err
}, query, args...)
return project, err
}
func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@ -497,35 +476,6 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string) (app *
return app, err
}
func (q *Queries) AppByClientID(ctx context.Context, clientID string) (app *App, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareAppQuery(true)
eq := sq.Eq{
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
AppColumnState.identifier(): domain.AppStateActive,
ProjectColumnState.identifier(): domain.ProjectStateActive,
OrgColumnState.identifier(): domain.OrgStateActive,
}
query, args, err := stmt.Where(sq.And{
eq,
sq.Or{
sq.Eq{AppOIDCConfigColumnClientID.identifier(): clientID},
sq.Eq{AppAPIConfigColumnClientID.identifier(): clientID},
},
}).ToSql()
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-Dfge2", "Errors.Query.SQLStatement")
}
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
app, err = scan(row)
return err
}, query, args...)
return app, err
}
func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries, withOwnerRemoved bool) (apps *Apps, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@ -867,48 +817,6 @@ func prepareProjectIDByAppQuery() (sq.SelectBuilder, func(*sql.Row) (projectID s
}
}
func prepareProjectByOIDCAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, error)) {
return sq.Select(
ProjectColumnID.identifier(),
ProjectColumnCreationDate.identifier(),
ProjectColumnChangeDate.identifier(),
ProjectColumnResourceOwner.identifier(),
ProjectColumnState.identifier(),
ProjectColumnSequence.identifier(),
ProjectColumnName.identifier(),
ProjectColumnProjectRoleAssertion.identifier(),
ProjectColumnProjectRoleCheck.identifier(),
ProjectColumnHasProjectCheck.identifier(),
ProjectColumnPrivateLabelingSetting.identifier(),
).From(projectsTable.identifier()).
Join(join(AppColumnProjectID, ProjectColumnID)).
Join(join(AppOIDCConfigColumnAppID, AppColumnID)).
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) (*Project, error) {
p := new(Project)
err := row.Scan(
&p.ID,
&p.CreationDate,
&p.ChangeDate,
&p.ResourceOwner,
&p.State,
&p.Sequence,
&p.Name,
&p.ProjectRoleAssertion,
&p.ProjectRoleCheck,
&p.HasProjectCheck,
&p.PrivateLabelingSetting,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, zerrors.ThrowNotFound(err, "QUERY-yxTMh", "Errors.Project.NotFound")
}
return nil, zerrors.ThrowInternal(err, "QUERY-dj2FF", "Errors.Internal")
}
return p, nil
}
}
func prepareProjectByAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, error)) {
return sq.Select(
ProjectColumnID.identifier(),

View File

@ -254,34 +254,6 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i
return key, err
}
func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id string, identifier string) (key []byte, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
stmt, scan := prepareAuthNKeyPublicKeyQuery()
eq := sq.And{
sq.Eq{
AuthNKeyColumnID.identifier(): id,
AuthNKeyColumnIdentifier.identifier(): identifier,
AuthNKeyColumnEnabled.identifier(): true,
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
},
sq.Gt{
AuthNKeyColumnExpiration.identifier(): time.Now(),
},
}
query, args, err := stmt.Where(eq).ToSql()
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-DAb32", "Errors.Query.SQLStatement")
}
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
key, err = scan(row)
return err
}, query, args...)
return key, err
}
func NewAuthNKeyResourceOwnerQuery(id string) (SearchQuery, error) {
return NewTextQuery(AuthNKeyColumnResourceOwner, id, TextEquals)
}
@ -429,26 +401,6 @@ func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, er
}
}
func prepareAuthNKeyPublicKeyQuery() (sq.SelectBuilder, func(row *sql.Row) ([]byte, error)) {
return sq.Select(
AuthNKeyColumnPublicKey.identifier(),
).From(authNKeyTable.identifier()).
PlaceholderFormat(sq.Dollar),
func(row *sql.Row) ([]byte, error) {
var publicKey []byte
err := row.Scan(
&publicKey,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, zerrors.ThrowNotFound(err, "QUERY-SDf32", "Errors.AuthNKey.NotFound")
}
return nil, zerrors.ThrowInternal(err, "QUERY-Bfs2a", "Errors.Internal")
}
return publicKey, nil
}
}
func prepareAuthNKeysDataQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeysData, error)) {
return sq.Select(
AuthNKeyColumnID.identifier(),

View File

@ -423,55 +423,6 @@ func Test_AuthNKeyPrepares(t *testing.T) {
},
object: (*AuthNKey)(nil),
},
{
name: "prepareAuthNKeyPublicKeyQuery no result",
prepare: prepareAuthNKeyPublicKeyQuery,
want: want{
sqlExpectations: mockQueriesScanErr(
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
nil,
nil,
),
err: func(err error) (error, bool) {
if !zerrors.IsNotFound(err) {
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
}
return nil, true
},
},
object: ([]byte)(nil),
},
{
name: "prepareAuthNKeyPublicKeyQuery found",
prepare: prepareAuthNKeyPublicKeyQuery,
want: want{
sqlExpectations: mockQuery(
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
prepareAuthNKeyPublicKeyCols,
[]driver.Value{
[]byte("publicKey"),
},
),
},
object: []byte("publicKey"),
},
{
name: "prepareAuthNKeyPublicKeyQuery sql err",
prepare: prepareAuthNKeyPublicKeyQuery,
want: want{
sqlExpectations: mockQueryErr(
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
sql.ErrConnDone,
),
err: func(err error) (error, bool) {
if !errors.Is(err, sql.ErrConnDone) {
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
}
return nil, true
},
},
object: ([]byte)(nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -11,7 +11,6 @@ type InstanceFeatures struct {
Details *domain.ObjectDetails
LoginDefaultOrg FeatureSource[bool]
TriggerIntrospectionProjections FeatureSource[bool]
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]

View File

@ -64,7 +64,6 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceResetEventType,
feature_v2.InstanceLoginDefaultOrgEventType,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType,
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceImprovedPerformanceEventType,
@ -94,7 +93,6 @@ func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
}
m.instance.LoginDefaultOrg = m.system.LoginDefaultOrg
m.instance.TriggerIntrospectionProjections = m.system.TriggerIntrospectionProjections
m.instance.LegacyIntrospection = m.system.LegacyIntrospection
m.instance.UserSchema = m.system.UserSchema
m.instance.TokenExchange = m.system.TokenExchange
m.instance.ImprovedPerformance = m.system.ImprovedPerformance
@ -111,15 +109,12 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
return err
}
switch key {
case feature.KeyUnspecified,
feature.KeyActionsDeprecated:
case feature.KeyUnspecified:
return nil
case feature.KeyLoginDefaultOrg:
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyTriggerIntrospectionProjections:
features.TriggerIntrospectionProjections.set(level, event.Value)
case feature.KeyLegacyIntrospection:
features.LegacyIntrospection.set(level, event.Value)
case feature.KeyUserSchema:
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:

View File

@ -75,10 +75,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelUnspecified,
Value: false,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
},
},
{
@ -97,10 +93,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
@ -120,10 +112,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelInstance,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelInstance,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelInstance,
Value: false,
@ -146,10 +134,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
@ -177,10 +161,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelInstance,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
@ -199,10 +179,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
ctx, aggregate,
feature_v2.InstanceTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
ctx, aggregate,
feature_v2.InstanceUserSchemaEventType, false,
@ -230,10 +206,6 @@ func TestQueries_GetInstanceFeatures(t *testing.T) {
Level: feature.LevelInstance,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,

View File

@ -68,10 +68,6 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.InstanceTriggerIntrospectionProjectionsEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceLegacyIntrospectionEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceUserSchemaEventType,
Reduce: reduceInstanceSetFeature[bool],

View File

@ -26,7 +26,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
args: args{
event: getEvent(
testEvent(
feature_v2.InstanceLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.AggregateType,
[]byte(`{"value": true}`),
), eventstore.GenericEventMapper[feature_v2.SetEvent[bool]]),
@ -41,7 +41,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
expectedStmt: "INSERT INTO projections.instance_features2 (instance_id, key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (instance_id, key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.instance_features2.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"agg-id",
"legacy_introspection",
"user_schema",
anyArg{},
anyArg{},
uint64(15),

View File

@ -60,10 +60,6 @@ func (*systemFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.SystemTriggerIntrospectionProjectionsEventType,
Reduce: reduceSystemSetFeature[bool],
},
{
Event: feature_v2.SystemLegacyIntrospectionEventType,
Reduce: reduceSystemSetFeature[bool],
},
{
Event: feature_v2.SystemUserSchemaEventType,
Reduce: reduceSystemSetFeature[bool],

View File

@ -24,7 +24,7 @@ func TestSystemFeaturesProjection_reduces(t *testing.T) {
args: args{
event: getEvent(
testEvent(
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.AggregateType,
[]byte(`{"value": true}`),
), eventstore.GenericEventMapper[feature_v2.SetEvent[bool]]),
@ -38,7 +38,7 @@ func TestSystemFeaturesProjection_reduces(t *testing.T) {
{
expectedStmt: "INSERT INTO projections.system_features (key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.system_features.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"legacy_introspection",
"user_schema",
anyArg{},
anyArg{},
uint64(15),

View File

@ -22,7 +22,6 @@ type SystemFeatures struct {
LoginDefaultOrg FeatureSource[bool]
TriggerIntrospectionProjections FeatureSource[bool]
LegacyIntrospection FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]

View File

@ -57,7 +57,6 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemResetEventType,
feature_v2.SystemLoginDefaultOrgEventType,
feature_v2.SystemTriggerIntrospectionProjectionsEventType,
feature_v2.SystemLegacyIntrospectionEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemImprovedPerformanceEventType,
@ -81,15 +80,12 @@ func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.S
return err
}
switch key {
case feature.KeyUnspecified,
feature.KeyActionsDeprecated:
case feature.KeyUnspecified:
return nil
case feature.KeyLoginDefaultOrg:
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyTriggerIntrospectionProjections:
features.TriggerIntrospectionProjections.set(level, event.Value)
case feature.KeyLegacyIntrospection:
features.LegacyIntrospection.set(level, event.Value)
case feature.KeyUserSchema:
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:

View File

@ -53,10 +53,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
@ -75,10 +71,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
@ -97,10 +89,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
@ -127,10 +115,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
@ -149,10 +133,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
context.Background(), aggregate,
feature_v2.SystemTriggerIntrospectionProjectionsEventType, true,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemLegacyIntrospectionEventType, false,
)),
eventFromEventPusher(feature_v2.NewSetEvent(
context.Background(), aggregate,
feature_v2.SystemUserSchemaEventType, false,
@ -179,10 +159,6 @@ func TestQueries_GetSystemFeatures(t *testing.T) {
Level: feature.LevelSystem,
Value: true,
},
LegacyIntrospection: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,
},
UserSchema: FeatureSource[bool]{
Level: feature.LevelUnspecified,
Value: false,

View File

@ -78,14 +78,6 @@ func NewUserGrantProjectIDSearchQuery(id string) (SearchQuery, error) {
return NewTextQuery(UserGrantProjectID, id, TextEquals)
}
func NewUserGrantProjectIDsSearchQuery(ids []string) (SearchQuery, error) {
list := make([]interface{}, len(ids))
for i, value := range ids {
list[i] = value
}
return NewListQuery(UserGrantProjectID, list, ListIn)
}
func NewUserGrantProjectOwnerSearchQuery(id string) (SearchQuery, error) {
return NewTextQuery(ProjectColumnResourceOwner, id, TextEquals)
}

View File

@ -9,7 +9,6 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, SystemResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SystemLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
@ -22,7 +21,6 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, InstanceResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLegacyIntrospectionEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])

View File

@ -14,7 +14,6 @@ var (
SystemResetEventType = resetEventTypeFromFeature(feature.LevelSystem)
SystemLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyLoginDefaultOrg)
SystemTriggerIntrospectionProjectionsEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTriggerIntrospectionProjections)
SystemLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyLegacyIntrospection)
SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema)
SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange)
SystemImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyImprovedPerformance)
@ -27,7 +26,6 @@ var (
InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance)
InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg)
InstanceTriggerIntrospectionProjectionsEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTriggerIntrospectionProjections)
InstanceLegacyIntrospectionEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLegacyIntrospection)
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance)

View File

@ -11,8 +11,8 @@ import "zitadel/feature/v2/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2;feature";
message SetInstanceFeaturesRequest{
reserved 6;
reserved "actions";
reserved 3, 6;
reserved "oidc_legacy_introspection", "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -25,12 +25,6 @@ message SetInstanceFeaturesRequest{
description: "Enable projection triggers during an introspection request. This can act as workaround if there are noticeable consistency issues in the introspection response but can have an impact on performance. We are planning to remove triggers for introspection requests in the future. Please raise an issue if you needed to enable this feature.";
}
];
optional bool oidc_legacy_introspection = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
optional bool user_schema = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -131,8 +125,8 @@ message GetInstanceFeaturesRequest {
}
message GetInstanceFeaturesResponse {
reserved 7;
reserved "actions";
reserved 4, 7;
reserved "oidc_legacy_introspection", "actions";
zitadel.object.v2.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -148,13 +142,6 @@ message GetInstanceFeaturesResponse {
}
];
FeatureFlag oidc_legacy_introspection = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
FeatureFlag user_schema = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";

View File

@ -11,8 +11,8 @@ import "zitadel/feature/v2/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2;feature";
message SetSystemFeaturesRequest{
reserved 6;
reserved "actions";
reserved 3, 6;
reserved "oidc_legacy_introspection", "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -27,13 +27,6 @@ message SetSystemFeaturesRequest{
}
];
optional bool oidc_legacy_introspection = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
optional bool user_schema = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -105,8 +98,8 @@ message ResetSystemFeaturesResponse {
message GetSystemFeaturesRequest {}
message GetSystemFeaturesResponse {
reserved 7;
reserved "actions";
reserved 4, 7;
reserved "oidc_legacy_introspection", "actions";
zitadel.object.v2.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -122,13 +115,6 @@ message GetSystemFeaturesResponse {
}
];
FeatureFlag oidc_legacy_introspection = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
FeatureFlag user_schema = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";

View File

@ -11,8 +11,8 @@ import "zitadel/feature/v2beta/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta;feature";
message SetInstanceFeaturesRequest{
reserved 6;
reserved "actions";
reserved 3, 6;
reserved "oidc_legacy_introspection", "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -25,12 +25,6 @@ message SetInstanceFeaturesRequest{
description: "Enable projection triggers during an introspection request. This can act as workaround if there are noticeable consistency issues in the introspection response but can have an impact on performance. We are planning to remove triggers for introspection requests in the future. Please raise an issue if you needed to enable this feature.";
}
];
optional bool oidc_legacy_introspection = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
optional bool user_schema = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -97,8 +91,8 @@ message GetInstanceFeaturesRequest {
}
message GetInstanceFeaturesResponse {
reserved 7;
reserved "actions";
reserved 4, 7;
reserved "oidc_legacy_introspection", "actions";
zitadel.object.v2beta.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -114,13 +108,6 @@ message GetInstanceFeaturesResponse {
}
];
FeatureFlag oidc_legacy_introspection = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
FeatureFlag user_schema = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";

View File

@ -11,8 +11,8 @@ import "zitadel/feature/v2beta/feature.proto";
option go_package = "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta;feature";
message SetSystemFeaturesRequest{
reserved 6;
reserved "actions";
reserved 3, 6;
reserved "oidc_legacy_introspection", "actions";
optional bool login_default_org = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -27,13 +27,6 @@ message SetSystemFeaturesRequest{
}
];
optional bool oidc_legacy_introspection = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
optional bool user_schema = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
@ -78,8 +71,8 @@ message ResetSystemFeaturesResponse {
message GetSystemFeaturesRequest {}
message GetSystemFeaturesResponse {
reserved 7;
reserved "actions";
reserved 4, 7;
reserved "oidc_legacy_introspection", "actions";
zitadel.object.v2beta.Details details = 1;
FeatureFlag login_default_org = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
@ -95,13 +88,6 @@ message GetSystemFeaturesResponse {
}
];
FeatureFlag oidc_legacy_introspection = 4 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "We have recently refactored the introspection endpoint for performance reasons. This feature can be used to rollback to the legacy implementation if unexpected bugs arise. Please raise an issue if you needed to enable this feature.";
}
];
FeatureFlag user_schema = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";