mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-14 11:58:02 +00:00
Merge branch 'main' into next-rc
This commit is contained in:
commit
7a552bd495
@ -578,8 +578,7 @@ DefaultInstance:
|
||||
Org:
|
||||
Name: ZITADEL # ZITADEL_DEFAULTINSTANCE_ORG_NAME
|
||||
# In the DefaultInstance.Org.Human section, the initial organization's admin user with the role IAM_OWNER is defined.
|
||||
# ZITADEL either creates a human user or a machine user.
|
||||
# If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user.
|
||||
# If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role.
|
||||
Human:
|
||||
# In case that UserLoginMustBeDomain is false (default) and if you don't overwrite the username with an email,
|
||||
# it will be suffixed by the org domain (org-name + domain from config).
|
||||
@ -599,8 +598,7 @@ DefaultInstance:
|
||||
Verified: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PHONE_VERIFIED
|
||||
Password: # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_PASSWORD
|
||||
# In the DefaultInstance.Org.Machine section, the initial organization's admin user with the role IAM_OWNER is defined.
|
||||
# ZITADEL either creates a human user or a machine user.
|
||||
# If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user.
|
||||
# If DefaultInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role.
|
||||
Machine:
|
||||
Machine:
|
||||
Username: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_MACHINE_USERNAME
|
||||
|
42
cmd/setup/30.go
Normal file
42
cmd/setup/30.go
Normal file
@ -0,0 +1,42 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
type FillFieldsForOrgDomainVerified struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
}
|
||||
|
||||
func (mig *FillFieldsForOrgDomainVerified) Execute(ctx context.Context, _ eventstore.Event) error {
|
||||
instances, err := mig.eventstore.InstanceIDs(
|
||||
ctx,
|
||||
0,
|
||||
true,
|
||||
eventstore.NewSearchQueryBuilder(eventstore.ColumnsInstanceIDs).
|
||||
OrderDesc().
|
||||
AddQuery().
|
||||
AggregateTypes("instance").
|
||||
EventTypes(instance.InstanceAddedEventType).
|
||||
Builder(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, instance := range instances {
|
||||
ctx := authz.WithInstanceID(ctx, instance)
|
||||
if err := projection.OrgDomainVerifiedFields.Trigger(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mig *FillFieldsForOrgDomainVerified) String() string {
|
||||
return "30_fill_fields_for_org_domain_verified"
|
||||
}
|
@ -113,6 +113,7 @@ type Steps struct {
|
||||
s27IDPTemplate6SAMLNameIDFormat *IDPTemplate6SAMLNameIDFormat
|
||||
s28AddFieldTable *AddFieldTable
|
||||
s29FillFieldsForProjectGrant *FillFieldsForProjectGrant
|
||||
s30FillFieldsForOrgDomainVerified *FillFieldsForOrgDomainVerified
|
||||
}
|
||||
|
||||
func MustNewSteps(v *viper.Viper) *Steps {
|
||||
|
@ -158,6 +158,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s27IDPTemplate6SAMLNameIDFormat = &IDPTemplate6SAMLNameIDFormat{dbClient: esPusherDBClient}
|
||||
steps.s28AddFieldTable = &AddFieldTable{dbClient: esPusherDBClient}
|
||||
steps.s29FillFieldsForProjectGrant = &FillFieldsForProjectGrant{eventstore: eventstoreClient}
|
||||
steps.s30FillFieldsForOrgDomainVerified = &FillFieldsForOrgDomainVerified{eventstore: eventstoreClient}
|
||||
|
||||
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
@ -198,6 +199,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s24AddActorToAuthTokens,
|
||||
steps.s26AuthUsers3,
|
||||
steps.s29FillFieldsForProjectGrant,
|
||||
steps.s30FillFieldsForOrgDomainVerified,
|
||||
} {
|
||||
mustExecuteMigration(ctx, eventstoreClient, step, "migration failed")
|
||||
}
|
||||
|
@ -11,8 +11,7 @@ FirstInstance:
|
||||
Org:
|
||||
Name: ZITADEL # ZITADEL_FIRSTINSTANCE_ORG_NAME
|
||||
# In the FirstInstance.Org.Human section, the initial organization's admin user with the role IAM_OWNER is defined.
|
||||
# ZITADEL either creates a human user or a machine user.
|
||||
# If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user.
|
||||
# If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role.
|
||||
Human:
|
||||
# In case UserLoginMustBeDomain is false (default) and you don't overwrite the username with an email,
|
||||
# it will be suffixed by the org domain (org-name + domain from config).
|
||||
@ -34,8 +33,7 @@ FirstInstance:
|
||||
Password: Password1! # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD
|
||||
PasswordChangeRequired: true # ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED
|
||||
# In the FirstInstance.Org.Machine section, the initial organization's admin user with the role IAM_OWNER is defined.
|
||||
# ZITADEL either creates a human user or a machine user.
|
||||
# If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role, not a human user.
|
||||
# If FirstInstance.Org.Machine.Machine is defined, a service user is created with the IAM_OWNER role.
|
||||
Machine:
|
||||
Machine:
|
||||
Username: # ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME
|
||||
|
@ -45,6 +45,7 @@
|
||||
featureData.loginDefaultOrg?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -53,6 +54,7 @@
|
||||
featureData.loginDefaultOrg?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
@ -99,6 +101,7 @@
|
||||
featureData.oidcLegacyIntrospection?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -107,6 +110,7 @@
|
||||
featureData.oidcLegacyIntrospection?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
@ -152,6 +156,7 @@
|
||||
featureData.oidcTokenExchange?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -160,6 +165,7 @@
|
||||
featureData.oidcTokenExchange?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
@ -205,6 +211,7 @@
|
||||
featureData.oidcTriggerIntrospectionProjections?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -213,6 +220,7 @@
|
||||
featureData.oidcTriggerIntrospectionProjections?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
@ -258,6 +266,7 @@
|
||||
featureData.userSchema?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -266,6 +275,7 @@
|
||||
featureData.userSchema?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
@ -311,6 +321,7 @@
|
||||
featureData.actions?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot enabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.ENABLED' | translate }}"
|
||||
></div>
|
||||
<div
|
||||
*ngIf="
|
||||
@ -319,6 +330,7 @@
|
||||
featureData.actions?.source === Source.SOURCE_UNSPECIFIED)
|
||||
"
|
||||
class="current-dot disabled"
|
||||
matTooltip="{{ 'SETTING.FEATURES.INHERITEDINDICATOR_DESCRIPTION.DISABLED' | translate }}"
|
||||
></div>
|
||||
</div>
|
||||
</mat-button-toggle>
|
||||
|
@ -491,6 +491,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.verifiedPhone', value: '{{.VerifiedPhone}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.loginnames', value: '{{.LoginNames}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.changedate', value: '{{.ChangeDate}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.expiry', value: '{{.Expiry}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.domain', value: '{{.Domain}}' },
|
||||
],
|
||||
[MESSAGETYPES.VERIFYEMAILOTP]: [
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.otp', value: '{{.OTP}}' },
|
||||
@ -507,6 +509,8 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.verifiedPhone', value: '{{.VerifiedPhone}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.loginnames', value: '{{.LoginNames}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.changedate', value: '{{.ChangeDate}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.expiry', value: '{{.Expiry}}' },
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.domain', value: '{{.Domain}}' },
|
||||
],
|
||||
[MESSAGETYPES.PASSWORDLESS]: [
|
||||
{ key: 'POLICY.MESSAGE_TEXTS.CHIPS.preferredLoginName', value: '{{.PreferredLoginName}}' },
|
||||
|
@ -1474,6 +1474,10 @@
|
||||
"DISABLED": "Деактивирано"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Тази настройка задава стойността по подразбиране на системата.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "„Активирано“ се наследява",
|
||||
"DISABLED": "„Деактивирано“ се наследява"
|
||||
},
|
||||
"RESET": "Задай всички на наследено"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1679,7 +1683,8 @@
|
||||
"username": "Потребителско име",
|
||||
"tempUsername": "Временно потребителско име",
|
||||
"otp": "Еднократна парола",
|
||||
"verifyUrl": "URL за потвърждаване на еднократна парола"
|
||||
"verifyUrl": "URL за потвърждаване на еднократна парола",
|
||||
"expiry": "Изтичане"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Персонализираните текстове са запазени."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Zakázáno"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Toto nastavení nastaví hodnotu na výchozí hodnotu systému.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "„Povoleno“ je zděděno",
|
||||
"DISABLED": "„Zakázáno“ je zděděno"
|
||||
},
|
||||
"RESET": "Nastavit vše na děděné"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Uživatelské jméno",
|
||||
"tempUsername": "Dočasné uživatelské jméno",
|
||||
"otp": "Jednorázové heslo",
|
||||
"verifyUrl": "Ověřovací URL jednorázového hesla"
|
||||
"verifyUrl": "Ověřovací URL jednorázového hesla",
|
||||
"expiry": "Expirace"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Vlastní texty uloženy."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Deaktiviert"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Diese Einstellung setzt den Wert auf den Standardwert des Systems.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "„Aktiviert“ wird vererbt",
|
||||
"DISABLED": "„Deaktiviert“ wird vererbt"
|
||||
},
|
||||
"RESET": "Alle auf Erben setzen"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Username",
|
||||
"tempUsername": "Temp. Username",
|
||||
"otp": "Einmalpasswort",
|
||||
"verifyUrl": "URL zur Überprüfung des Einmalpassworts"
|
||||
"verifyUrl": "URL zur Überprüfung des Einmalpassworts",
|
||||
"expiry": "Ablauf"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Benutzerdefinierte Texte gespeichert."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Disabled"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "This sets the value to the default value of the system.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Enabled\" is inherited",
|
||||
"DISABLED": "\"Disabled\" is inherited"
|
||||
},
|
||||
"RESET": "Set all to inherit"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Username",
|
||||
"tempUsername": "Temp username",
|
||||
"otp": "One-time password",
|
||||
"verifyUrl": "Verify One-time-password URL"
|
||||
"verifyUrl": "Verify One-time-password URL",
|
||||
"expiry": "Expiry"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Custom Texts saved."
|
||||
|
@ -1476,6 +1476,10 @@
|
||||
"DISABLED": "Deshabilitado"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Esta configuración establece el valor al valor predeterminado del sistema.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Habilitado\" se hereda",
|
||||
"DISABLED": "\"Deshabilitado\" se hereda"
|
||||
},
|
||||
"RESET": "Establecer todo a heredado"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1681,7 +1685,8 @@
|
||||
"username": "Nombre de usuario",
|
||||
"tempUsername": "Nombre de usuario temporal",
|
||||
"otp": "Contraseña de un solo uso",
|
||||
"verifyUrl": "URL para verificar la contraseña de un solo uso"
|
||||
"verifyUrl": "URL para verificar la contraseña de un solo uso",
|
||||
"expiry": "Expiración"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Textos personalizados guardados."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Désactivé"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Ce paramètre définit la valeur par défaut du système.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Activé\" est hérité",
|
||||
"DISABLED": "\"Désactivé\" est hérité"
|
||||
},
|
||||
"RESET": "Réinitialiser tout sur hérité"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Nom d'utilisateur",
|
||||
"tempUsername": "Nom d'utilisateur temporaire",
|
||||
"otp": "Mot de passe à usage unique",
|
||||
"verifyUrl": "URL pour vérifier le mot de passe à usage unique"
|
||||
"verifyUrl": "URL pour vérifier le mot de passe à usage unique",
|
||||
"expiry": "Expiration"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Textes personnalisés enregistrés."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Disabilitato"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Questa impostazione imposta il valore predefinito del sistema.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Abilitato\" viene ereditato",
|
||||
"DISABLED": "\"Disabilitato\" viene ereditato"
|
||||
},
|
||||
"RESET": "Imposta tutto su predefinito"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Nome utente",
|
||||
"tempUsername": "Nome utente temporaneo",
|
||||
"otp": "Password monouso",
|
||||
"verifyUrl": "URL per verificare la password monouso"
|
||||
"verifyUrl": "URL per verificare la password monouso",
|
||||
"expiry": "Scadenza"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Testi personalizzati salvati."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "無効"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "この設定は、値をシステムのデフォルト値に設定します。",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "有効は継承されます",
|
||||
"DISABLED": "無効は継承されます"
|
||||
},
|
||||
"RESET": "すべて継承に設定"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1676,7 +1680,8 @@
|
||||
"username": "ユーザー名",
|
||||
"tempUsername": "一時ユーザー名",
|
||||
"otp": "ワンタイムパスワード",
|
||||
"verifyUrl": "ワンタイムパスワードを確認するURL"
|
||||
"verifyUrl": "ワンタイムパスワードを確認するURL",
|
||||
"expiry": "有効期限"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "カスタムテキストが保存されました。"
|
||||
|
@ -1476,6 +1476,10 @@
|
||||
"DISABLED": "Оневозможено"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Оваа поставка ја постави вредноста на стандардната вредност на системот.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "„Овозможено“ е наследено",
|
||||
"DISABLED": "„Оневозможено“ е наследено"
|
||||
},
|
||||
"RESET": "Поставете ги сите да наследат"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1681,7 +1685,8 @@
|
||||
"username": "Корисничко име",
|
||||
"tempUsername": "Привремено корисничко име",
|
||||
"otp": "Еднократна лозинка",
|
||||
"verifyUrl": "URL за потврдување на еднократна лозинка"
|
||||
"verifyUrl": "URL за потврдување на еднократна лозинка",
|
||||
"expiry": "Истекување"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Прилагодените текстови се зачувани."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "Uitgeschakeld"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Deze instelling stelt de waarde in op de standaardwaarde van het systeem.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Ingeschakeld\" wordt overgenomen",
|
||||
"DISABLED": "\"Uitgeschakeld\" wordt overgenomen"
|
||||
},
|
||||
"RESET": "Alles instellen op overgenomen"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1680,7 +1684,8 @@
|
||||
"username": "Gebruikersnaam",
|
||||
"tempUsername": "Tijdelijke gebruikersnaam",
|
||||
"otp": "Eenmalig wachtwoord",
|
||||
"verifyUrl": "Verifieer Eenmalig-wachtwoord URL"
|
||||
"verifyUrl": "Verifieer Eenmalig-wachtwoord URL",
|
||||
"expiry": "Vervaldatum"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Aangepaste Teksten opgeslagen."
|
||||
|
@ -1474,6 +1474,10 @@
|
||||
"DISABLED": "Wyłączony"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "To ustawienie przypisuje wartość do wartości domyślnej systemu.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "„Włączony” jest dziedziczone",
|
||||
"DISABLED": "„Wyłączony” jest dziedziczone"
|
||||
},
|
||||
"RESET": "Ustaw wszystko na dziedziczone"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1679,7 +1683,8 @@
|
||||
"username": "Nazwa użytkownika",
|
||||
"tempUsername": "Tymczasowa nazwa użytkownika",
|
||||
"otp": "Hasło jednorazowe",
|
||||
"verifyUrl": "URL do weryfikacji hasła jednorazowego"
|
||||
"verifyUrl": "URL do weryfikacji hasła jednorazowego",
|
||||
"expiry": "Wygaśnięcie"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Teksty niestandardowe zapisane."
|
||||
|
@ -1476,6 +1476,10 @@
|
||||
"DISABLED": "Desabilitado"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Essa configuração define o valor para o padrão do sistema.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Habilitado\" é herdado",
|
||||
"DISABLED": "\"Desabilitado\" é herdado"
|
||||
},
|
||||
"RESET": "Definir tudo para herdar"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1681,7 +1685,8 @@
|
||||
"username": "Nome de usuário",
|
||||
"tempUsername": "Nome de usuário temporário",
|
||||
"otp": "Senha de uso único",
|
||||
"verifyUrl": "URL para verificar a senha de uso único"
|
||||
"verifyUrl": "URL para verificar a senha de uso único",
|
||||
"expiry": "Data de expiração"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Textos personalizados salvos."
|
||||
|
@ -1526,6 +1526,10 @@
|
||||
"DISABLED": "Выключено"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Эта настройка устанавливает значение по умолчанию для системы.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "«Включено» наследуется",
|
||||
"DISABLED": "«Выключено» передается по наследству"
|
||||
},
|
||||
"RESET": "Установить все по умолчанию"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1747,7 +1751,8 @@
|
||||
"username": "Имя пользователя",
|
||||
"tempUsername": "Временное имя пользователя",
|
||||
"otp": "Одноразовый пароль",
|
||||
"verifyUrl": "Проверка URL-адреса с одноразовым паролем"
|
||||
"verifyUrl": "Проверка URL-адреса с одноразовым паролем",
|
||||
"expiry": "Срок действия"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Тексты сохранены."
|
||||
|
@ -1479,6 +1479,10 @@
|
||||
"DISABLED": "Inaktiverad"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "Detta ställer in värdet till systemets standardvärde.",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "\"Aktiverad\" ärvs",
|
||||
"DISABLED": "\"Inaktiverad\" ärvs"
|
||||
},
|
||||
"RESET": "Återställ allt till arv"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1684,7 +1688,8 @@
|
||||
"username": "Användarnamn",
|
||||
"tempUsername": "Tillfälligt användarnamn",
|
||||
"otp": "Engångslösenord",
|
||||
"verifyUrl": "Verifiera Engångslösenord URL"
|
||||
"verifyUrl": "Verifiera Engångslösenord URL",
|
||||
"expiry": "Utgångsdatum"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "Anpassade Texter sparade."
|
||||
|
@ -1475,6 +1475,10 @@
|
||||
"DISABLED": "已禁用"
|
||||
},
|
||||
"INHERITED_DESCRIPTION": "此设置将值设置为系统默认值。",
|
||||
"INHERITEDINDICATOR_DESCRIPTION": {
|
||||
"ENABLED": "“已启用” 是继承的",
|
||||
"DISABLED": "“已禁用” 是继承的"
|
||||
},
|
||||
"RESET": "全部设置为继承"
|
||||
},
|
||||
"DIALOG": {
|
||||
@ -1679,7 +1683,8 @@
|
||||
"username": "用户名",
|
||||
"tempUsername": "临时用户名",
|
||||
"otp": "一次性密码",
|
||||
"verifyUrl": "验证一次性密码的URL"
|
||||
"verifyUrl": "验证一次性密码的URL",
|
||||
"expiry": "过期时间"
|
||||
},
|
||||
"TOAST": {
|
||||
"UPDATED": "自定义文本已保存。"
|
||||
|
@ -21,6 +21,7 @@ When you configure your default settings, you can set the following:
|
||||
- [**Login Behavior and Access**](#login-behavior-and-access): Multifactor Authentication Options and Enforcement, Define whether Passwordless authentication methods are allowed or not, Set Login Lifetimes and advanced behavour for the login interface.
|
||||
- [**Identity Providers**](#identity-providers): Define IDPs which are available for all organizations
|
||||
- [**Password Complexity**](#password-complexity): Requirements for Passwords ex. Symbols, Numbers, min length and more.
|
||||
- [**Password Expiry**](#password-expiry): Set an expiry for passwords. After the expiration, a user will be prompted to change their password during the next login.
|
||||
- [**Lockout**](#lockout): Set the maximum attempts a user can try to enter the password or any (T)OTP method. When the number is exceeded, the user gets locked out and has to be unlocked.
|
||||
- [**Domain settings**](#domain-settings): Whether users use their email or the generated username to login. Other Validation, SMTP settings
|
||||
- [**Branding**](#branding): Appearance of the login interface.
|
||||
@ -222,6 +223,24 @@ The following properties can be set:
|
||||
width="600px"
|
||||
/>
|
||||
|
||||
## Password Expiry
|
||||
|
||||
With the password expiry policy you can set an expiration for user password.
|
||||
After the expiration, a user will be prompted to change their password during the next authentication.
|
||||
|
||||
Note, that ZITADEL will not warn or notify the user about the expiry, yet. If you want your users to be notified, you can read this setting and send the notification yourself.
|
||||
|
||||
The following properties can be set:
|
||||
|
||||
- Maximum validity in days
|
||||
- Expiration warning after days
|
||||
|
||||
<img
|
||||
src="/docs/img/guides/console/expiry.png"
|
||||
alt="Password Expiry Policy"
|
||||
width="600px"
|
||||
/>
|
||||
|
||||
## Lockout
|
||||
|
||||
Define when an account should be locked.
|
||||
|
BIN
docs/static/img/guides/console/expiry.png
vendored
Normal file
BIN
docs/static/img/guides/console/expiry.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 88 KiB |
@ -37,7 +37,7 @@ describe('applications', () => {
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.get('[id*=overlay]').should('exist');
|
||||
cy.shouldConfirmSuccess();
|
||||
const expectClientId = new RegExp(`^.*[0-9]+\\@${testProjectName}.*$`);
|
||||
const expectClientId = new RegExp(`^.*[0-9]+.*$`);
|
||||
cy.get('[data-e2e="client-id-copy"]').click();
|
||||
cy.contains('[data-e2e="client-id"]', expectClientId);
|
||||
cy.clipboardMatches(expectClientId);
|
||||
@ -64,7 +64,7 @@ describe('applications', () => {
|
||||
cy.get('[data-e2e="create-button"]').click();
|
||||
cy.get('[id*=overlay]').should('exist');
|
||||
cy.shouldConfirmSuccess();
|
||||
const expectClientId = new RegExp(`^.*[0-9]+\\@${testProjectName}.*$`);
|
||||
const expectClientId = new RegExp(`^.*[0-9]+.*$`);
|
||||
cy.get('[data-e2e="client-id-copy"]').click();
|
||||
cy.contains('[data-e2e="client-id"]', expectClientId);
|
||||
cy.clipboardMatches(expectClientId);
|
||||
|
@ -39,7 +39,10 @@ func (s *Server) RemoveOrg(ctx context.Context, req *admin_pb.RemoveOrgRequest)
|
||||
|
||||
func (s *Server) GetDefaultOrg(ctx context.Context, _ *admin_pb.GetDefaultOrgRequest) (*admin_pb.GetDefaultOrgResponse, error) {
|
||||
org, err := s.query.OrgByID(ctx, true, authz.GetInstance(ctx).DefaultOrganisationID())
|
||||
return &admin_pb.GetDefaultOrgResponse{Org: org_grpc.OrgToPb(org)}, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetDefaultOrgResponse{Org: org_grpc.OrgToPb(org)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetOrgByID(ctx context.Context, req *admin_pb.GetOrgByIDRequest) (*admin_pb.GetOrgByIDResponse, error) {
|
||||
|
@ -113,6 +113,10 @@ func improvedPerformanceTypeToPb(typ feature.ImprovedPerformanceType) feature_pb
|
||||
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_PROJECT_GRANT
|
||||
case feature.ImprovedPerformanceTypeProject:
|
||||
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_PROJECT
|
||||
case feature.ImprovedPerformanceTypeUserGrant:
|
||||
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_USER_GRANT
|
||||
case feature.ImprovedPerformanceTypeOrgDomainVerified:
|
||||
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_DOMAIN_VERIFIED
|
||||
default:
|
||||
return feature_pb.ImprovedPerformance(typ)
|
||||
}
|
||||
@ -141,6 +145,10 @@ func improvedPerformanceToDomain(typ feature_pb.ImprovedPerformance) feature.Imp
|
||||
return feature.ImprovedPerformanceTypeProjectGrant
|
||||
case feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_PROJECT:
|
||||
return feature.ImprovedPerformanceTypeProject
|
||||
case feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_USER_GRANT:
|
||||
return feature.ImprovedPerformanceTypeUserGrant
|
||||
case feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_DOMAIN_VERIFIED:
|
||||
return feature.ImprovedPerformanceTypeOrgDomainVerified
|
||||
default:
|
||||
return feature.ImprovedPerformanceTypeUnknown
|
||||
}
|
||||
|
@ -65,13 +65,16 @@ func (s *Server) UpdateAction(ctx context.Context, req *mgmt_pb.UpdateActionRequ
|
||||
|
||||
func (s *Server) DeactivateAction(ctx context.Context, req *mgmt_pb.DeactivateActionRequest) (*mgmt_pb.DeactivateActionResponse, error) {
|
||||
details, err := s.command.DeactivateAction(ctx, req.Id, authz.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.DeactivateActionResponse{
|
||||
Details: obj_grpc.AddToDetailsPb(
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ReactivateAction(ctx context.Context, req *mgmt_pb.ReactivateActionRequest) (*mgmt_pb.ReactivateActionResponse, error) {
|
||||
|
@ -20,8 +20,10 @@ import (
|
||||
|
||||
client_middleware "github.com/zitadel/zitadel/internal/api/grpc/client/middleware"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/server/middleware"
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -206,7 +208,10 @@ func addInterceptors(
|
||||
// For some non-obvious reason, the exhaustedCookieInterceptor sends the SetCookie header
|
||||
// only if it follows the http_mw.DefaultTelemetryHandler
|
||||
handler = exhaustedCookieInterceptor(handler, accessInterceptor)
|
||||
handler = http_mw.DefaultMetricsHandler(handler)
|
||||
handler = http_mw.MetricsHandler([]metrics.MetricType{
|
||||
metrics.MetricTypeTotalCount,
|
||||
metrics.MetricTypeStatusCode,
|
||||
}, http_utils.Probes...)(handler)
|
||||
return handler
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,9 @@ package middleware
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/metrics"
|
||||
)
|
||||
|
||||
func DefaultMetricsHandler(handler http.Handler) http.Handler {
|
||||
metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount}
|
||||
return MetricsHandler(metricTypes, http_utils.Probes...)(handler)
|
||||
}
|
||||
|
||||
func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethods ...string) func(http.Handler) http.Handler {
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return metrics.NewMetricsHandler(handler, metricTypes, ignoredMethods...)
|
||||
|
@ -513,6 +513,11 @@ func (s *Server) authorizeCallbackHandler(w http.ResponseWriter, r *http.Request
|
||||
return authReq, s.authResponse(authReq, authorizer, w, r)
|
||||
}(r.Context())
|
||||
if err != nil {
|
||||
// we need to make sure there's no empty interface passed
|
||||
if authReq == nil {
|
||||
op.AuthRequestError(w, r, nil, err, authorizer)
|
||||
return
|
||||
}
|
||||
op.AuthRequestError(w, r, authReq, err, authorizer)
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,9 @@ func (s *Server) userInfo(
|
||||
}
|
||||
rawUserInfo = userInfoToOIDC(qu, userInfoAssertion, scope, s.assetAPIPrefix(ctx))
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// copy the userinfo to make sure the assert roles and actions use their own copy (e.g. map)
|
||||
userInfo := &oidc.UserInfo{
|
||||
Subject: rawUserInfo.Subject,
|
||||
|
@ -126,7 +126,8 @@ func (c *Commands) GetActiveIntent(ctx context.Context, intentID string) (*IDPIn
|
||||
return nil, zerrors.ThrowNotFound(nil, "IDP-gy3ctgkqe7", "Errors.Intent.NotStarted")
|
||||
}
|
||||
if intent.State != domain.IDPIntentStateStarted {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "IDP-Sfrgs", "Errors.Intent.NotStarted")
|
||||
// we still need to return the intent to be able to redirect to the failure url
|
||||
return intent, zerrors.ThrowInvalidArgument(nil, "IDP-Sfrgs", "Errors.Intent.NotStarted")
|
||||
}
|
||||
return intent, nil
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ func projectAddedEvents(ctx context.Context, instanceID, orgID, id, owner string
|
||||
events = append(events, apiAppEvents(ctx, orgID, id, "auth-id", "Auth-API")...)
|
||||
|
||||
consoleAppID := "console-id"
|
||||
consoleClientID := "clientID@zitadel"
|
||||
consoleClientID := "clientID"
|
||||
events = append(events, oidcAppEvents(ctx, orgID, id, consoleAppID, "Console", consoleClientID, externalSecure)...)
|
||||
events = append(events,
|
||||
instance.NewIAMConsoleSetEvent(ctx,
|
||||
@ -90,7 +90,7 @@ func apiAppEvents(ctx context.Context, orgID, projectID, id, name string) []even
|
||||
project.NewAPIConfigAddedEvent(ctx,
|
||||
&project.NewAggregate(projectID, orgID).Aggregate,
|
||||
id,
|
||||
"clientID@zitadel",
|
||||
"clientID",
|
||||
"",
|
||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
),
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
@ -390,3 +392,65 @@ func (c *Commands) getOrgDomainWriteModel(ctx context.Context, orgID, domain str
|
||||
}
|
||||
return domainWriteModel, nil
|
||||
}
|
||||
|
||||
type OrgDomainVerified struct {
|
||||
OrgID string
|
||||
Domain string
|
||||
Verified bool
|
||||
}
|
||||
|
||||
func (c *Commands) searchOrgDomainVerifiedByDomain(ctx context.Context, domain string) (_ *OrgDomainVerified, err error) {
|
||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeOrgDomainVerified) {
|
||||
return c.searchOrgDomainVerifiedByDomainOld(ctx, domain)
|
||||
}
|
||||
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
condition := map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeObjectType: org.OrgDomainSearchType,
|
||||
eventstore.FieldTypeObjectID: domain,
|
||||
eventstore.FieldTypeObjectRevision: org.OrgDomainObjectRevision,
|
||||
eventstore.FieldTypeFieldName: org.OrgDomainVerifiedSearchField,
|
||||
}
|
||||
|
||||
results, err := c.eventstore.Search(ctx, condition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(results) == 0 {
|
||||
_ = projection.OrgDomainVerifiedFields.Trigger(ctx)
|
||||
results, err = c.eventstore.Search(ctx, condition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
orgDomain := new(OrgDomainVerified)
|
||||
for _, result := range results {
|
||||
orgDomain.OrgID = result.Aggregate.ID
|
||||
if err = result.Value.Unmarshal(&orgDomain.Verified); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return orgDomain, nil
|
||||
}
|
||||
|
||||
func (c *Commands) searchOrgDomainVerifiedByDomainOld(ctx context.Context, domain string) (_ *OrgDomainVerified, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel := NewOrgDomainVerifiedWriteModel(domain)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &OrgDomainVerified{
|
||||
OrgID: writeModel.ResourceOwner,
|
||||
Domain: writeModel.Domain,
|
||||
Verified: writeModel.Verified,
|
||||
}, nil
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func (c *Commands) AddAPIAppCommand(app *addAPIApp) preparation.Validation {
|
||||
return nil, zerrors.ThrowNotFound(err, "PROJE-Sf2gb", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
app.ClientID, err = domain.NewClientID(c.idGenerator, project.Name)
|
||||
app.ClientID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "V2-f0pgP", "Errors.Internal")
|
||||
}
|
||||
@ -78,19 +78,19 @@ func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
if existingAPI.State != domain.AppStateUnspecified {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-mabu12", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
project, err := c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
|
||||
_, err = c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsa", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID)
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
|
||||
}
|
||||
|
||||
func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string) (_ *domain.APIApp, err error) {
|
||||
if apiApp == nil || apiApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
||||
}
|
||||
project, err := c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
|
||||
_, err = c.getProjectByID(ctx, apiApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsf", "Errors.Project.NotFound")
|
||||
}
|
||||
@ -104,10 +104,10 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID)
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
|
||||
}
|
||||
|
||||
func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner string, project *domain.Project, appID string) (_ *domain.APIApp, err error) {
|
||||
func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner string, appID string) (_ *domain.APIApp, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@ -121,7 +121,7 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
}
|
||||
|
||||
var plain string
|
||||
err = domain.SetNewClientID(apiApp, c.idGenerator, project)
|
||||
err = domain.SetNewClientID(apiApp, c.idGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ func TestAddAPIConfig(t *testing.T) {
|
||||
),
|
||||
project.NewAPIConfigAddedEvent(ctx, &agg.Aggregate,
|
||||
"appID",
|
||||
"clientID@project",
|
||||
"clientID",
|
||||
"",
|
||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
),
|
||||
@ -252,7 +252,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
project.NewAPIConfigAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"client1@project",
|
||||
"client1",
|
||||
"secret",
|
||||
domain.APIAuthMethodTypeBasic),
|
||||
),
|
||||
@ -278,7 +278,61 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
ClientID: "client1@project",
|
||||
ClientID: "client1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||
State: domain.AppStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create api app basic old ID format, ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"project", true, true, true,
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"app",
|
||||
),
|
||||
project.NewAPIConfigAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"client1@project1",
|
||||
"secret",
|
||||
domain.APIAuthMethodTypeBasic),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1@project1"),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
apiApp: &domain.APIApp{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
want: &domain.APIApp{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
ClientID: "client1@project1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||
State: domain.AppStateActive,
|
||||
@ -306,7 +360,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
project.NewAPIConfigAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"client1@project",
|
||||
"client1",
|
||||
"",
|
||||
domain.APIAuthMethodTypePrivateKeyJWT),
|
||||
),
|
||||
@ -332,7 +386,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
ClientID: "client1@project",
|
||||
ClientID: "client1",
|
||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||
State: domain.AppStateActive,
|
||||
},
|
||||
|
@ -68,7 +68,7 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp) preparation.Validation {
|
||||
return nil, zerrors.ThrowNotFound(err, "PROJE-6swVG", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
app.ClientID, err = domain.NewClientID(c.idGenerator, project.Name)
|
||||
app.ClientID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "V2-VMSQ1", "Errors.Internal")
|
||||
}
|
||||
@ -126,19 +126,19 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "PROJECT-lxowmp", "Errors.Project.App.AlreadyExisting")
|
||||
}
|
||||
|
||||
project, err := c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner)
|
||||
_, err = c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID)
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID)
|
||||
}
|
||||
|
||||
func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string) (_ *domain.OIDCApp, err error) {
|
||||
if oidcApp == nil || oidcApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
project, err := c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner)
|
||||
_, err = c.getProjectByID(ctx, oidcApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9ss", "Errors.Project.NotFound")
|
||||
}
|
||||
@ -152,10 +152,10 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID)
|
||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, appID)
|
||||
}
|
||||
|
||||
func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, project *domain.Project, appID string) (_ *domain.OIDCApp, err error) {
|
||||
func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, appID string) (_ *domain.OIDCApp, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
@ -169,7 +169,7 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
}
|
||||
|
||||
var plain string
|
||||
err = domain.SetNewClientID(oidcApp, c.idGenerator, project)
|
||||
err = domain.SetNewClientID(oidcApp, c.idGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
project.NewOIDCConfigAddedEvent(ctx, &agg.Aggregate,
|
||||
domain.OIDCVersionV1,
|
||||
"id",
|
||||
"clientID@project",
|
||||
"clientID",
|
||||
"",
|
||||
[]string{"https://test.ch"},
|
||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
@ -214,6 +214,71 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
}).
|
||||
Filter(),
|
||||
},
|
||||
want: Want{
|
||||
Commands: []eventstore.Command{
|
||||
project.NewApplicationAddedEvent(ctx, &agg.Aggregate,
|
||||
"id",
|
||||
"name",
|
||||
),
|
||||
project.NewOIDCConfigAddedEvent(ctx, &agg.Aggregate,
|
||||
domain.OIDCVersionV1,
|
||||
"id",
|
||||
"clientID",
|
||||
"",
|
||||
nil,
|
||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
domain.OIDCApplicationTypeWeb,
|
||||
domain.OIDCAuthMethodTypeNone,
|
||||
nil,
|
||||
false,
|
||||
domain.OIDCTokenTypeBearer,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
nil,
|
||||
false,
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "correct with old ID format",
|
||||
fields: fields{
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "clientID@project"),
|
||||
},
|
||||
args: args{
|
||||
app: &addOIDCApp{
|
||||
AddApp: AddApp{
|
||||
Aggregate: *agg,
|
||||
ID: "id",
|
||||
Name: "name",
|
||||
},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
Version: domain.OIDCVersionV1,
|
||||
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
},
|
||||
filter: NewMultiFilter().
|
||||
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||
return []eventstore.Event{
|
||||
project.NewProjectAddedEvent(
|
||||
ctx,
|
||||
&agg.Aggregate,
|
||||
"project",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PrivateLabelingSettingUnspecified,
|
||||
),
|
||||
}, nil
|
||||
}).
|
||||
Filter(),
|
||||
},
|
||||
want: Want{
|
||||
Commands: []eventstore.Command{
|
||||
project.NewApplicationAddedEvent(ctx, &agg.Aggregate,
|
||||
@ -288,7 +353,7 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
project.NewOIDCConfigAddedEvent(ctx, &agg.Aggregate,
|
||||
domain.OIDCVersionV1,
|
||||
"id",
|
||||
"clientID@project",
|
||||
"clientID",
|
||||
"secret",
|
||||
nil,
|
||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
@ -434,7 +499,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
domain.OIDCVersionV1,
|
||||
"app1",
|
||||
"client1@project",
|
||||
"client1",
|
||||
"secret",
|
||||
[]string{"https://test.ch"},
|
||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
@ -488,7 +553,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
ClientID: "client1@project",
|
||||
ClientID: "client1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
@ -532,7 +597,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
domain.OIDCVersionV1,
|
||||
"app1",
|
||||
"client1@project",
|
||||
"client1",
|
||||
"secret",
|
||||
[]string{"https://test.ch"},
|
||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
@ -586,7 +651,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
ClientID: "client1@project",
|
||||
ClientID: "client1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
|
@ -259,38 +259,49 @@ func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGra
|
||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeProjectGrant) {
|
||||
return c.checkProjectGrantPreConditionOld(ctx, projectGrant)
|
||||
}
|
||||
existingRoleKeys, err := c.searchProjectGrantState(ctx, projectGrant.AggregateID, projectGrant.GrantedOrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if projectGrant.HasInvalidRoles(existingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) searchProjectGrantState(ctx context.Context, projectID, grantedOrgID string) (existingRoleKeys []string, err error) {
|
||||
results, err := c.eventstore.Search(
|
||||
ctx,
|
||||
// project state query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectGrant.AggregateID,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
},
|
||||
// granted org query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectGrant.GrantedOrgID,
|
||||
eventstore.FieldTypeAggregateID: grantedOrgID,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
},
|
||||
// role query
|
||||
map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: projectGrant.AggregateID,
|
||||
eventstore.FieldTypeAggregateID: projectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
existsProject bool
|
||||
existsGrantedOrg bool
|
||||
existingRoleKeys []string
|
||||
)
|
||||
|
||||
for _, result := range results {
|
||||
@ -299,34 +310,31 @@ func (c *Commands) checkProjectGrantPreCondition(ctx context.Context, projectGra
|
||||
var role string
|
||||
err := result.Value.Unmarshal(&role)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
existingRoleKeys = append(existingRoleKeys, role)
|
||||
case org.OrgSearchType:
|
||||
var state domain.OrgState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
existsGrantedOrg = state.Valid() && state != domain.OrgStateRemoved
|
||||
case project.ProjectSearchType:
|
||||
var state domain.ProjectState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
existsProject = state.Valid() && state != domain.ProjectStateRemoved
|
||||
}
|
||||
}
|
||||
|
||||
if !existsProject {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !existsGrantedOrg {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
if projectGrant.HasInvalidRoles(existingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-6m9gd", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
return existingRoleKeys, nil
|
||||
}
|
||||
|
@ -40,17 +40,8 @@ func (c *Commands) ChangeUsername(ctx context.Context, orgID, userID, userName s
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-38fnu", "Errors.Org.DomainPolicy.NotExisting")
|
||||
}
|
||||
if !domainPolicy.UserLoginMustBeDomain {
|
||||
index := strings.LastIndex(userName, "@")
|
||||
if index > 1 {
|
||||
domainCheck := NewOrgDomainVerifiedWriteModel(userName[index+1:])
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, domainCheck); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domainCheck.Verified && domainCheck.ResourceOwner != orgID {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Di2ei", "Errors.User.DomainNotAllowedAsUsername")
|
||||
}
|
||||
}
|
||||
if err = c.userValidateDomain(ctx, orgID, userName, domainPolicy.UserLoginMustBeDomain); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userAgg := UserAggregateFromWriteModel(&existingUser.WriteModel)
|
||||
|
||||
|
@ -4,8 +4,12 @@ import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/repository/usergrant"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
@ -288,6 +292,140 @@ func (c *Commands) userGrantWriteModelByID(ctx context.Context, userGrantID, res
|
||||
}
|
||||
|
||||
func (c *Commands) checkUserGrantPreCondition(ctx context.Context, usergrant *domain.UserGrant, resourceOwner string) (err error) {
|
||||
if !authz.GetFeatures(ctx).ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeUserGrant) {
|
||||
return c.checkUserGrantPreConditionOld(ctx, usergrant, resourceOwner)
|
||||
}
|
||||
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err := c.checkUserExists(ctx, usergrant.UserID, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
existingRoleKeys, err := c.searchUserGrantPreConditionState(ctx, usergrant, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usergrant.HasInvalidRoles(existingRoleKeys) {
|
||||
return zerrors.ThrowPreconditionFailed(err, "COMMAND-mm9F4", "Errors.Project.Role.NotFound")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// this code needs to be rewritten anyways as soon as we improved the fields handling
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (c *Commands) searchUserGrantPreConditionState(ctx context.Context, userGrant *domain.UserGrant, resourceOwner string) (existingRoleKeys []string, err error) {
|
||||
criteria := []map[eventstore.FieldType]any{
|
||||
// project state query
|
||||
{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: userGrant.ProjectID,
|
||||
eventstore.FieldTypeFieldName: project.ProjectStateSearchField,
|
||||
eventstore.FieldTypeObjectType: project.ProjectSearchType,
|
||||
},
|
||||
// granted org query
|
||||
{
|
||||
eventstore.FieldTypeAggregateType: org.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: resourceOwner,
|
||||
eventstore.FieldTypeFieldName: org.OrgStateSearchField,
|
||||
eventstore.FieldTypeObjectType: org.OrgSearchType,
|
||||
},
|
||||
}
|
||||
if userGrant.ProjectGrantID != "" {
|
||||
criteria = append(criteria, map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: userGrant.ProjectID,
|
||||
eventstore.FieldTypeObjectType: project.ProjectGrantSearchType,
|
||||
eventstore.FieldTypeObjectID: userGrant.ProjectGrantID,
|
||||
})
|
||||
} else {
|
||||
criteria = append(criteria, map[eventstore.FieldType]any{
|
||||
eventstore.FieldTypeAggregateType: project.AggregateType,
|
||||
eventstore.FieldTypeAggregateID: userGrant.ProjectID,
|
||||
eventstore.FieldTypeObjectType: project.ProjectRoleSearchType,
|
||||
eventstore.FieldTypeFieldName: project.ProjectRoleKeySearchField,
|
||||
})
|
||||
}
|
||||
results, err := c.eventstore.Search(ctx, criteria...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
existsProject bool
|
||||
existsGrantedOrg bool
|
||||
existsGrant bool
|
||||
)
|
||||
|
||||
for _, result := range results {
|
||||
switch result.Object.Type {
|
||||
case project.ProjectRoleSearchType:
|
||||
var role string
|
||||
err := result.Value.Unmarshal(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingRoleKeys = append(existingRoleKeys, role)
|
||||
case org.OrgSearchType:
|
||||
var state domain.OrgState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existsGrantedOrg = state.Valid() && state != domain.OrgStateRemoved
|
||||
case project.ProjectSearchType:
|
||||
var state domain.ProjectState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existsProject = state.Valid() && state != domain.ProjectStateRemoved
|
||||
case project.ProjectGrantSearchType:
|
||||
switch result.FieldName {
|
||||
case project.ProjectGrantGrantedOrgIDSearchField:
|
||||
var orgID string
|
||||
err := result.Value.Unmarshal(&orgID)
|
||||
if err != nil || orgID != resourceOwner {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
case project.ProjectGrantStateSearchField:
|
||||
var state domain.ProjectGrantState
|
||||
err := result.Value.Unmarshal(&state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existsGrant = state.Valid() && state != domain.ProjectGrantStateRemoved
|
||||
case project.ProjectGrantRoleKeySearchField:
|
||||
var role string
|
||||
err := result.Value.Unmarshal(&role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingRoleKeys = append(existingRoleKeys, role)
|
||||
case project.ProjectGrantGrantIDSearchField:
|
||||
var grantID string
|
||||
err := result.Value.Unmarshal(&grantID)
|
||||
if err != nil || grantID != userGrant.ProjectGrantID {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-huvKF", "Errors.Project.Grant.NotFound")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !existsProject {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-m9gsd", "Errors.Project.NotFound")
|
||||
}
|
||||
if !existsGrantedOrg {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-3m9gg", "Errors.Org.NotFound")
|
||||
}
|
||||
if userGrant.ProjectGrantID != "" && !existsGrant {
|
||||
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-huvKF", "Errors.Project.Grant.NotFound")
|
||||
}
|
||||
return existingRoleKeys, nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkUserGrantPreConditionOld(ctx context.Context, usergrant *domain.UserGrant, resourceOwner string) (err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
|
@ -362,7 +362,7 @@ func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQue
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) userValidateDomain(ctx context.Context, resourceOwner string, username string, mustBeDomain bool) error {
|
||||
func (c *Commands) userValidateDomain(ctx context.Context, resourceOwner string, username string, mustBeDomain bool) (err error) {
|
||||
if mustBeDomain {
|
||||
return nil
|
||||
}
|
||||
@ -372,12 +372,12 @@ func (c *Commands) userValidateDomain(ctx context.Context, resourceOwner string,
|
||||
return nil
|
||||
}
|
||||
|
||||
domainCheck, err := c.orgDomainVerifiedWriteModel(ctx, username[index+1:])
|
||||
domainCheck, err := c.searchOrgDomainVerifiedByDomain(ctx, username[index+1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if domainCheck.Verified && domainCheck.ResourceOwner != resourceOwner {
|
||||
if domainCheck.Verified && domainCheck.OrgID != resourceOwner {
|
||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-SFd21", "Errors.User.DomainNotAllowedAsUsername")
|
||||
}
|
||||
|
||||
@ -479,7 +479,7 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
|
||||
if orgID == "" {
|
||||
return nil, nil, nil, "", zerrors.ThrowInvalidArgument(nil, "COMMAND-00p2b", "Errors.Org.Empty")
|
||||
}
|
||||
if err := human.Normalize(); err != nil {
|
||||
if err = human.Normalize(); err != nil {
|
||||
return nil, nil, nil, "", err
|
||||
}
|
||||
events, humanWriteModel, err = c.createHuman(ctx, orgID, human, links, passwordless, domainPolicy, pwPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator)
|
||||
@ -497,24 +497,17 @@ func (c *Commands) importHuman(ctx context.Context, orgID string, human *domain.
|
||||
return events, humanWriteModel, passwordlessCodeWriteModel, code, nil
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.Human, links []*domain.UserIDPLink, passwordless bool, domainPolicy *domain.DomainPolicy, pwPolicy *domain.PasswordComplexityPolicy, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator crypto.Generator) (events []eventstore.Command, addedHuman *HumanWriteModel, err error) {
|
||||
if err := human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err = human.CheckDomainPolicy(domainPolicy); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
human.Username = strings.TrimSpace(human.Username)
|
||||
human.EmailAddress = human.EmailAddress.Normalize()
|
||||
if !domainPolicy.UserLoginMustBeDomain {
|
||||
index := strings.LastIndex(human.Username, "@")
|
||||
if index > 1 {
|
||||
domainCheck := NewOrgDomainVerifiedWriteModel(human.Username[index+1:])
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, domainCheck); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if domainCheck.Verified && domainCheck.ResourceOwner != orgID {
|
||||
return nil, nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-SFd21", "Errors.User.DomainNotAllowedAsUsername")
|
||||
}
|
||||
}
|
||||
if err = c.userValidateDomain(ctx, orgID, human.Username, domainPolicy.UserLoginMustBeDomain); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if human.AggregateID == "" {
|
||||
|
@ -434,15 +434,3 @@ func (c *Commands) userHumanWriteModel(ctx context.Context, userID string, profi
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) orgDomainVerifiedWriteModel(ctx context.Context, domain string) (writeModel *OrgDomainVerifiedWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel = NewOrgDomainVerifiedWriteModel(domain)
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModel, nil
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
@ -19,17 +18,8 @@ func (c *Commands) changeUsername(ctx context.Context, cmds []eventstore.Command
|
||||
if err != nil {
|
||||
return cmds, zerrors.ThrowPreconditionFailed(err, "COMMAND-79pv6e1q62", "Errors.Org.DomainPolicy.NotExisting")
|
||||
}
|
||||
if !domainPolicy.UserLoginMustBeDomain {
|
||||
index := strings.LastIndex(userName, "@")
|
||||
if index > 1 {
|
||||
domainCheck := NewOrgDomainVerifiedWriteModel(userName[index+1:])
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, domainCheck); err != nil {
|
||||
return cmds, err
|
||||
}
|
||||
if domainCheck.Verified && domainCheck.ResourceOwner != orgID {
|
||||
return cmds, zerrors.ThrowInvalidArgument(nil, "COMMAND-Di2ei", "Errors.User.DomainNotAllowedAsUsername")
|
||||
}
|
||||
}
|
||||
if err = c.userValidateDomain(ctx, orgID, userName, domainPolicy.UserLoginMustBeDomain); err != nil {
|
||||
return cmds, err
|
||||
}
|
||||
return append(cmds,
|
||||
user.NewUsernameChangedEvent(ctx, &wm.Aggregate().Aggregate, wm.UserName, userName, domainPolicy.UserLoginMustBeDomain),
|
||||
|
@ -1,9 +1,6 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
)
|
||||
|
||||
@ -13,9 +10,9 @@ type oAuthApplication interface {
|
||||
requiresClientSecret() bool
|
||||
}
|
||||
|
||||
// ClientID random_number@projectname (eg. 495894098234@zitadel)
|
||||
func SetNewClientID(a oAuthApplication, idGenerator id.Generator, project *Project) error {
|
||||
clientID, err := NewClientID(idGenerator, project.Name)
|
||||
// ClientID random_number (eg. 495894098234)
|
||||
func SetNewClientID(a oAuthApplication, idGenerator id.Generator) error {
|
||||
clientID, err := idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -24,15 +21,6 @@ func SetNewClientID(a oAuthApplication, idGenerator id.Generator, project *Proje
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewClientID(idGenerator id.Generator, projectName string) (string, error) {
|
||||
rndID, err := idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s@%s", rndID, strings.ReplaceAll(strings.ToLower(projectName), " ", "_")), nil
|
||||
}
|
||||
|
||||
func SetNewClientSecretIfNeeded(a oAuthApplication, generate func() (encodedHash, plain string, err error)) (string, error) {
|
||||
if !a.requiresClientSecret() {
|
||||
return "", nil
|
||||
|
@ -18,8 +18,14 @@ const (
|
||||
ProjectGrantStateActive
|
||||
ProjectGrantStateInactive
|
||||
ProjectGrantStateRemoved
|
||||
|
||||
projectGrantStateMax
|
||||
)
|
||||
|
||||
func (s ProjectGrantState) Valid() bool {
|
||||
return s > ProjectGrantStateUnspecified && s < projectGrantStateMax
|
||||
}
|
||||
|
||||
func (p *ProjectGrant) IsValid() bool {
|
||||
return p.GrantedOrgID != ""
|
||||
}
|
||||
|
@ -149,8 +149,8 @@ func (h *FieldHandler) processEvents(ctx context.Context, config *triggerConfig)
|
||||
|
||||
func (h *FieldHandler) fetchEvents(ctx context.Context, tx *sql.Tx, currentState *state) (_ []eventstore.FillFieldsEvent, additionalIteration bool, err error) {
|
||||
events, err := h.es.Filter(ctx, h.eventQuery(currentState).SetTx(tx))
|
||||
if err != nil {
|
||||
h.log().WithError(err).Debug("filter eventstore failed")
|
||||
if err != nil || len(events) == 0 {
|
||||
h.log().OnError(err).Debug("filter eventstore failed")
|
||||
return nil, false, err
|
||||
}
|
||||
eventAmount := len(events)
|
||||
|
@ -1,5 +1,7 @@
|
||||
package feature
|
||||
|
||||
import "slices"
|
||||
|
||||
//go:generate enumer -type Key -transform snake -trimprefix Key
|
||||
type Key int
|
||||
|
||||
@ -44,13 +46,10 @@ const (
|
||||
ImprovedPerformanceTypeOrgByID
|
||||
ImprovedPerformanceTypeProjectGrant
|
||||
ImprovedPerformanceTypeProject
|
||||
ImprovedPerformanceTypeUserGrant
|
||||
ImprovedPerformanceTypeOrgDomainVerified
|
||||
)
|
||||
|
||||
func (f Features) ShouldUseImprovedPerformance(typ ImprovedPerformanceType) bool {
|
||||
for _, improvedType := range f.ImprovedPerformance {
|
||||
if improvedType == typ {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(f.ImprovedPerformance, typ)
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ var (
|
||||
testdataOidcClientJWT string
|
||||
//go:embed testdata/oidc_client_public.json
|
||||
testdataOidcClientPublic string
|
||||
//go:embed testdata/oidc_client_public_old_id.json
|
||||
testdataOidcClientPublicOldId string
|
||||
//go:embed testdata/oidc_client_secret.json
|
||||
testdataOidcClientSecret string
|
||||
//go:embed testdata/oidc_client_no_settings.json
|
||||
@ -64,7 +66,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
||||
InstanceID: "230690539048009730",
|
||||
AppID: "236647088211886082",
|
||||
State: domain.AppStateActive,
|
||||
ClientID: "236647088211951618@tests",
|
||||
ClientID: "236647088211951618",
|
||||
HashedSecret: "",
|
||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
@ -92,6 +94,38 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
||||
{
|
||||
name: "public client",
|
||||
mock: mockQuery(expQuery, cols, []driver.Value{testdataOidcClientPublic}, "instanceID", "clientID", true),
|
||||
want: &OIDCClient{
|
||||
InstanceID: "230690539048009730",
|
||||
AppID: "236646457053020162",
|
||||
State: domain.AppStateActive,
|
||||
ClientID: "236646457053085698",
|
||||
HashedSecret: "",
|
||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
||||
PostLogoutRedirectURIs: nil,
|
||||
IsDevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: false,
|
||||
IDTokenRoleAssertion: false,
|
||||
IDTokenUserinfoAssertion: false,
|
||||
ClockSkew: 0,
|
||||
AdditionalOrigins: nil,
|
||||
PublicKeys: nil,
|
||||
ProjectID: "236645808328409090",
|
||||
ProjectRoleAssertion: true,
|
||||
ProjectRoleKeys: []string{"role1", "role2"},
|
||||
Settings: &OIDCSettings{
|
||||
AccessTokenLifetime: 43200000000000,
|
||||
IdTokenLifetime: 43200000000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "public client",
|
||||
mock: mockQuery(expQuery, cols, []driver.Value{testdataOidcClientPublicOldId}, "instanceID", "clientID", true),
|
||||
want: &OIDCClient{
|
||||
InstanceID: "230690539048009730",
|
||||
AppID: "236646457053020162",
|
||||
@ -128,7 +162,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
||||
InstanceID: "230690539048009730",
|
||||
AppID: "236646858984783874",
|
||||
State: domain.AppStateActive,
|
||||
ClientID: "236646858984849410@tests",
|
||||
ClientID: "236646858984849410",
|
||||
HashedSecret: "$2a$14$OzZ0XEZZEtD13py/EPba2evsS6WcKZ5orVMj9pWHEGEHmLu2h3PFq",
|
||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||
ResponseTypes: []domain.OIDCResponseType{0},
|
||||
@ -160,7 +194,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
||||
InstanceID: "239520764275982338",
|
||||
AppID: "239520764276441090",
|
||||
State: domain.AppStateActive,
|
||||
ClientID: "239520764779364354@zitadel",
|
||||
ClientID: "239520764779364354",
|
||||
HashedSecret: "",
|
||||
RedirectURIs: []string{
|
||||
"http://test2-qucuh5.localhost:9000/ui/console/auth/callback",
|
||||
|
@ -7,13 +7,32 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
)
|
||||
|
||||
const (
|
||||
fieldsProjectGrant = "project_grant_fields"
|
||||
fieldsOrgDomainVerified = "org_domain_verified_fields"
|
||||
)
|
||||
|
||||
func newFillProjectGrantFields(config handler.Config) *handler.FieldHandler {
|
||||
return handler.NewFieldHandler(
|
||||
&config,
|
||||
"project_grant_fields",
|
||||
fieldsProjectGrant,
|
||||
map[eventstore.AggregateType][]eventstore.EventType{
|
||||
org.AggregateType: nil,
|
||||
project.AggregateType: nil,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func newFillOrgDomainVerifiedFields(config handler.Config) *handler.FieldHandler {
|
||||
return handler.NewFieldHandler(
|
||||
&config,
|
||||
fieldsOrgDomainVerified,
|
||||
map[eventstore.AggregateType][]eventstore.EventType{
|
||||
org.AggregateType: {
|
||||
org.OrgDomainAddedEventType,
|
||||
org.OrgDomainVerifiedEventType,
|
||||
org.OrgDomainRemovedEventType,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -78,7 +78,8 @@ var (
|
||||
ExecutionProjection *handler.Handler
|
||||
UserSchemaProjection *handler.Handler
|
||||
|
||||
ProjectGrantFields *handler.FieldHandler
|
||||
ProjectGrantFields *handler.FieldHandler
|
||||
OrgDomainVerifiedFields *handler.FieldHandler
|
||||
)
|
||||
|
||||
type projection interface {
|
||||
@ -161,7 +162,8 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore,
|
||||
ExecutionProjection = newExecutionProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["executions"]))
|
||||
UserSchemaProjection = newUserSchemaProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["user_schemas"]))
|
||||
|
||||
ProjectGrantFields = newFillProjectGrantFields(applyCustomConfig(projectionConfig, config.Customizations["project_grant_fields"]))
|
||||
ProjectGrantFields = newFillProjectGrantFields(applyCustomConfig(projectionConfig, config.Customizations[fieldsProjectGrant]))
|
||||
OrgDomainVerifiedFields = newFillOrgDomainVerifiedFields(applyCustomConfig(projectionConfig, config.Customizations[fieldsOrgDomainVerified]))
|
||||
|
||||
newProjectionsList()
|
||||
return nil
|
||||
|
2
internal/query/testdata/oidc_client_jwt.json
vendored
2
internal/query/testdata/oidc_client_jwt.json
vendored
@ -2,7 +2,7 @@
|
||||
"instance_id": "230690539048009730",
|
||||
"app_id": "236647088211886082",
|
||||
"state": 1,
|
||||
"client_id": "236647088211951618@tests",
|
||||
"client_id": "236647088211951618",
|
||||
"client_secret": null,
|
||||
"redirect_uris": ["http://localhost:9999/auth/callback"],
|
||||
"response_types": [0],
|
||||
|
@ -2,7 +2,7 @@
|
||||
"instance_id": "239520764275982338",
|
||||
"app_id": "239520764276441090",
|
||||
"state": 1,
|
||||
"client_id": "239520764779364354@zitadel",
|
||||
"client_id": "239520764779364354",
|
||||
"client_secret": null,
|
||||
"redirect_uris": [
|
||||
"http://test2-qucuh5.localhost:9000/ui/console/auth/callback",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"instance_id": "230690539048009730",
|
||||
"app_id": "236646457053020162",
|
||||
"state": 1,
|
||||
"client_id": "236646457053085698@tests",
|
||||
"client_id": "236646457053085698",
|
||||
"client_secret": null,
|
||||
"redirect_uris": ["http://localhost:9999/auth/callback"],
|
||||
"response_types": [0],
|
||||
|
28
internal/query/testdata/oidc_client_public_old_id.json
vendored
Normal file
28
internal/query/testdata/oidc_client_public_old_id.json
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"instance_id": "230690539048009730",
|
||||
"app_id": "236646457053020162",
|
||||
"state": 1,
|
||||
"client_id": "236646457053085698@tests",
|
||||
"client_secret": null,
|
||||
"redirect_uris": ["http://localhost:9999/auth/callback"],
|
||||
"response_types": [0],
|
||||
"grant_types": [0],
|
||||
"application_type": 0,
|
||||
"auth_method_type": 2,
|
||||
"post_logout_redirect_uris": null,
|
||||
"is_dev_mode": true,
|
||||
"access_token_type": 0,
|
||||
"access_token_role_assertion": false,
|
||||
"id_token_role_assertion": false,
|
||||
"id_token_userinfo_assertion": false,
|
||||
"clock_skew": 0,
|
||||
"additional_origins": null,
|
||||
"project_id": "236645808328409090",
|
||||
"project_role_assertion": true,
|
||||
"project_role_keys": ["role1", "role2"],
|
||||
"public_keys": null,
|
||||
"settings": {
|
||||
"access_token_lifetime": 43200000000000,
|
||||
"id_token_lifetime": 43200000000000
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"instance_id": "230690539048009730",
|
||||
"app_id": "236646858984783874",
|
||||
"state": 1,
|
||||
"client_id": "236646858984849410@tests",
|
||||
"client_id": "236646858984849410",
|
||||
"client_secret": "$2a$14$OzZ0XEZZEtD13py/EPba2evsS6WcKZ5orVMj9pWHEGEHmLu2h3PFq",
|
||||
"redirect_uris": ["http://localhost:9999/auth/callback"],
|
||||
"response_types": [0],
|
||||
|
@ -18,6 +18,10 @@ const (
|
||||
OrgDomainVerifiedEventType = domainEventPrefix + "verified"
|
||||
OrgDomainPrimarySetEventType = domainEventPrefix + "primary.set"
|
||||
OrgDomainRemovedEventType = domainEventPrefix + "removed"
|
||||
|
||||
OrgDomainSearchType = "org_domain"
|
||||
OrgDomainVerifiedSearchField = "verified"
|
||||
OrgDomainObjectRevision = uint8(1)
|
||||
)
|
||||
|
||||
func NewAddOrgDomainUniqueConstraint(orgDomain string) *eventstore.UniqueConstraint {
|
||||
@ -47,6 +51,28 @@ func (e *DomainAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *DomainAddedEvent) Fields() []*eventstore.FieldOperation {
|
||||
return []*eventstore.FieldOperation{
|
||||
eventstore.SetField(
|
||||
e.Aggregate(),
|
||||
domainSearchObject(e.Domain),
|
||||
OrgDomainVerifiedSearchField,
|
||||
&eventstore.Value{
|
||||
Value: false,
|
||||
ShouldIndex: false,
|
||||
},
|
||||
|
||||
eventstore.FieldTypeInstanceID,
|
||||
eventstore.FieldTypeResourceOwner,
|
||||
eventstore.FieldTypeAggregateType,
|
||||
eventstore.FieldTypeAggregateID,
|
||||
eventstore.FieldTypeObjectType,
|
||||
eventstore.FieldTypeObjectID,
|
||||
eventstore.FieldTypeFieldName,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDomainAddedEvent(ctx context.Context, aggregate *eventstore.Aggregate, domain string) *DomainAddedEvent {
|
||||
return &DomainAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
@ -167,6 +193,28 @@ func (e *DomainVerifiedEvent) UniqueConstraints() []*eventstore.UniqueConstraint
|
||||
return []*eventstore.UniqueConstraint{NewAddOrgDomainUniqueConstraint(e.Domain)}
|
||||
}
|
||||
|
||||
func (e *DomainVerifiedEvent) Fields() []*eventstore.FieldOperation {
|
||||
return []*eventstore.FieldOperation{
|
||||
eventstore.SetField(
|
||||
e.Aggregate(),
|
||||
domainSearchObject(e.Domain),
|
||||
OrgDomainVerifiedSearchField,
|
||||
&eventstore.Value{
|
||||
Value: true,
|
||||
ShouldIndex: false,
|
||||
},
|
||||
|
||||
eventstore.FieldTypeInstanceID,
|
||||
eventstore.FieldTypeResourceOwner,
|
||||
eventstore.FieldTypeAggregateType,
|
||||
eventstore.FieldTypeAggregateID,
|
||||
eventstore.FieldTypeObjectType,
|
||||
eventstore.FieldTypeObjectID,
|
||||
eventstore.FieldTypeFieldName,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDomainVerifiedEvent(ctx context.Context, aggregate *eventstore.Aggregate, domain string) *DomainVerifiedEvent {
|
||||
return &DomainVerifiedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
@ -245,6 +293,28 @@ func (e *DomainRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint
|
||||
return []*eventstore.UniqueConstraint{NewRemoveOrgDomainUniqueConstraint(e.Domain)}
|
||||
}
|
||||
|
||||
func (e *DomainRemovedEvent) Fields() []*eventstore.FieldOperation {
|
||||
return []*eventstore.FieldOperation{
|
||||
eventstore.SetField(
|
||||
e.Aggregate(),
|
||||
domainSearchObject(e.Domain),
|
||||
OrgDomainVerifiedSearchField,
|
||||
&eventstore.Value{
|
||||
Value: false,
|
||||
ShouldIndex: false,
|
||||
},
|
||||
|
||||
eventstore.FieldTypeInstanceID,
|
||||
eventstore.FieldTypeResourceOwner,
|
||||
eventstore.FieldTypeAggregateType,
|
||||
eventstore.FieldTypeAggregateID,
|
||||
eventstore.FieldTypeObjectType,
|
||||
eventstore.FieldTypeObjectID,
|
||||
eventstore.FieldTypeFieldName,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDomainRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, domain string, verified bool) *DomainRemovedEvent {
|
||||
return &DomainRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
@ -268,3 +338,11 @@ func DomainRemovedEventMapper(event eventstore.Event) (eventstore.Event, error)
|
||||
|
||||
return orgDomainRemoved, nil
|
||||
}
|
||||
|
||||
func domainSearchObject(domain string) eventstore.Object {
|
||||
return eventstore.Object{
|
||||
Type: OrgDomainSearchType,
|
||||
ID: domain,
|
||||
Revision: OrgDomainObjectRevision,
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
UniqueRoleType = "project_role"
|
||||
roleEventTypePrefix = projectEventTypePrefix + "role."
|
||||
RoleAddedType = roleEventTypePrefix + "added"
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.33.0
|
||||
// protoc-gen-go v1.34.2
|
||||
// protoc (unknown)
|
||||
// source: zitadel/protoc_gen_zitadel/v2/options.proto
|
||||
|
||||
@ -250,7 +250,7 @@ func file_zitadel_protoc_gen_zitadel_v2_options_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_zitadel_protoc_gen_zitadel_v2_options_proto_goTypes = []interface{}{
|
||||
var file_zitadel_protoc_gen_zitadel_v2_options_proto_goTypes = []any{
|
||||
(*Options)(nil), // 0: zitadel.protoc_gen_zitadel.v2.Options
|
||||
(*AuthOption)(nil), // 1: zitadel.protoc_gen_zitadel.v2.AuthOption
|
||||
(*CustomHTTPResponse)(nil), // 2: zitadel.protoc_gen_zitadel.v2.CustomHTTPResponse
|
||||
@ -274,7 +274,7 @@ func file_zitadel_protoc_gen_zitadel_v2_options_proto_init() {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*Options); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -286,7 +286,7 @@ func file_zitadel_protoc_gen_zitadel_v2_options_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*AuthOption); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -298,7 +298,7 @@ func file_zitadel_protoc_gen_zitadel_v2_options_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
file_zitadel_protoc_gen_zitadel_v2_options_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||
switch v := v.(*CustomHTTPResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -59,4 +59,10 @@ enum ImprovedPerformance {
|
||||
// correctnes of data.
|
||||
IMPROVED_PERFORMANCE_PROJECT_GRANT = 2;
|
||||
IMPROVED_PERFORMANCE_PROJECT = 3;
|
||||
IMPROVED_PERFORMANCE_USER_GRANT = 4;
|
||||
|
||||
// Improve performance on write side when
|
||||
// users are checked against verified domains
|
||||
// from other organizations.
|
||||
IMPROVED_PERFORMANCE_ORG_DOMAIN_VERIFIED = 5;
|
||||
}
|
Loading…
Reference in New Issue
Block a user