fix: tos on external registration (#2164)

* faet: add tos checkbox to external login

* fix: add tos to external not found option

* fix: add tos to external not found option

* fix: show register external user overview

* fix: no init user mail on external register

* fix: custom login text

* add missing custom text tests on org

* add missing custom text tests on iam

* fix: custom login text external registration overview tests

* fix: back button on registration overview

* fix: add texts, change register form

* fix: external not found html

* fix: remove form validation

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2021-08-11 13:50:03 +02:00 committed by GitHub
parent 87fa6e58fb
commit b104011418
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 3412 additions and 164 deletions

View File

@ -2437,6 +2437,7 @@ This is an empty request
| passwordless_prompt_text | zitadel.text.v1.PasswordlessPromptScreenText | - | | | passwordless_prompt_text | zitadel.text.v1.PasswordlessPromptScreenText | - | |
| passwordless_registration_text | zitadel.text.v1.PasswordlessRegistrationScreenText | - | | | passwordless_registration_text | zitadel.text.v1.PasswordlessRegistrationScreenText | - | |
| passwordless_registration_done_text | zitadel.text.v1.PasswordlessRegistrationDoneScreenText | - | | | passwordless_registration_done_text | zitadel.text.v1.PasswordlessRegistrationDoneScreenText | - | |
| external_registration_user_overview_text | zitadel.text.v1.ExternalRegistrationUserOverviewScreenText | - | |

View File

@ -6756,6 +6756,7 @@ This is an empty request
| passwordless_prompt_text | zitadel.text.v1.PasswordlessPromptScreenText | - | | | passwordless_prompt_text | zitadel.text.v1.PasswordlessPromptScreenText | - | |
| passwordless_registration_text | zitadel.text.v1.PasswordlessRegistrationScreenText | - | | | passwordless_registration_text | zitadel.text.v1.PasswordlessRegistrationScreenText | - | |
| passwordless_registration_done_text | zitadel.text.v1.PasswordlessRegistrationDoneScreenText | - | | | passwordless_registration_done_text | zitadel.text.v1.PasswordlessRegistrationDoneScreenText | - | |
| external_registration_user_overview_text | zitadel.text.v1.ExternalRegistrationUserOverviewScreenText | - | |

View File

@ -131,6 +131,7 @@ func SetLoginTextToDomain(req *admin_pb.SetCustomLoginTextsRequest) *domain.Cust
result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText) result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText)
result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText) result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText)
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText) result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
result.ExternalRegistrationUserOverview = text.ExternalRegistrationUserOverviewScreenTextPbToDomain(req.ExternalRegistrationUserOverviewText)
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText) result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText) result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText)
result.ExternalNotFoundOption = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText) result.ExternalNotFoundOption = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText)

View File

@ -129,6 +129,7 @@ func SetLoginCustomTextToDomain(req *mgmt_pb.SetCustomLoginTextsRequest) *domain
result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText) result.PasswordResetDone = text.PasswordResetDoneScreenTextPbToDomain(req.PasswordResetDoneText)
result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText) result.RegisterOption = text.RegistrationOptionScreenTextPbToDomain(req.RegistrationOptionText)
result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText) result.RegistrationUser = text.RegistrationUserScreenTextPbToDomain(req.RegistrationUserText)
result.ExternalRegistrationUserOverview = text.ExternalRegistrationUserOverviewScreenTextPbToDomain(req.ExternalRegistrationUserOverviewText)
result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText) result.RegistrationOrg = text.RegistrationOrgScreenTextPbToDomain(req.RegistrationOrgText)
result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText) result.LinkingUsersDone = text.LinkingUserDoneScreenTextPbToDomain(req.LinkingUserDoneText)
result.ExternalNotFoundOption = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText) result.ExternalNotFoundOption = text.ExternalUserNotFoundScreenTextPbToDomain(req.ExternalUserNotFoundText)

View File

@ -32,39 +32,40 @@ func CustomLoginTextToPb(text *domain.CustomLoginText) *text_pb.LoginCustomText
text.ChangeDate, text.ChangeDate,
text.AggregateID, text.AggregateID,
), ),
SelectAccountText: SelectAccountScreenToPb(text.SelectAccount), SelectAccountText: SelectAccountScreenToPb(text.SelectAccount),
LoginText: LoginScreenTextToPb(text.Login), LoginText: LoginScreenTextToPb(text.Login),
PasswordText: PasswordScreenTextToPb(text.Password), PasswordText: PasswordScreenTextToPb(text.Password),
UsernameChangeText: UsernameChangeScreenTextToPb(text.UsernameChange), UsernameChangeText: UsernameChangeScreenTextToPb(text.UsernameChange),
UsernameChangeDoneText: UsernameChangeDoneScreenTextToPb(text.UsernameChangeDone), UsernameChangeDoneText: UsernameChangeDoneScreenTextToPb(text.UsernameChangeDone),
InitPasswordText: InitPasswordScreenTextToPb(text.InitPassword), InitPasswordText: InitPasswordScreenTextToPb(text.InitPassword),
InitPasswordDoneText: InitPasswordDoneScreenTextToPb(text.InitPasswordDone), InitPasswordDoneText: InitPasswordDoneScreenTextToPb(text.InitPasswordDone),
EmailVerificationText: EmailVerificationScreenTextToPb(text.EmailVerification), EmailVerificationText: EmailVerificationScreenTextToPb(text.EmailVerification),
EmailVerificationDoneText: EmailVerificationDoneScreenTextToPb(text.EmailVerificationDone), EmailVerificationDoneText: EmailVerificationDoneScreenTextToPb(text.EmailVerificationDone),
InitializeUserText: InitializeUserScreenTextToPb(text.InitUser), InitializeUserText: InitializeUserScreenTextToPb(text.InitUser),
InitializeDoneText: InitializeUserDoneScreenTextToPb(text.InitUserDone), InitializeDoneText: InitializeUserDoneScreenTextToPb(text.InitUserDone),
InitMfaPromptText: InitMFAPromptScreenTextToPb(text.InitMFAPrompt), InitMfaPromptText: InitMFAPromptScreenTextToPb(text.InitMFAPrompt),
InitMfaOtpText: InitMFAOTPScreenTextToPb(text.InitMFAOTP), InitMfaOtpText: InitMFAOTPScreenTextToPb(text.InitMFAOTP),
InitMfaU2FText: InitMFAU2FScreenTextToPb(text.InitMFAU2F), InitMfaU2FText: InitMFAU2FScreenTextToPb(text.InitMFAU2F),
InitMfaDoneText: InitMFADoneScreenTextToPb(text.InitMFADone), InitMfaDoneText: InitMFADoneScreenTextToPb(text.InitMFADone),
MfaProvidersText: MFAProvidersTextToPb(text.MFAProvider), MfaProvidersText: MFAProvidersTextToPb(text.MFAProvider),
VerifyMfaOtpText: VerifyMFAOTPScreenTextToPb(text.VerifyMFAOTP), VerifyMfaOtpText: VerifyMFAOTPScreenTextToPb(text.VerifyMFAOTP),
VerifyMfaU2FText: VerifyMFAU2FScreenTextToPb(text.VerifyMFAU2F), VerifyMfaU2FText: VerifyMFAU2FScreenTextToPb(text.VerifyMFAU2F),
PasswordlessText: PasswordlessScreenTextToPb(text.Passwordless), PasswordlessText: PasswordlessScreenTextToPb(text.Passwordless),
PasswordlessPromptText: PasswordlessPromptScreenTextToPb(text.PasswordlessPrompt), PasswordlessPromptText: PasswordlessPromptScreenTextToPb(text.PasswordlessPrompt),
PasswordlessRegistrationText: PasswordlessRegistrationScreenTextToPb(text.PasswordlessRegistration), PasswordlessRegistrationText: PasswordlessRegistrationScreenTextToPb(text.PasswordlessRegistration),
PasswordlessRegistrationDoneText: PasswordlessRegistrationDoneScreenTextToPb(text.PasswordlessRegistrationDone), PasswordlessRegistrationDoneText: PasswordlessRegistrationDoneScreenTextToPb(text.PasswordlessRegistrationDone),
PasswordChangeText: PasswordChangeScreenTextToPb(text.PasswordChange), PasswordChangeText: PasswordChangeScreenTextToPb(text.PasswordChange),
PasswordChangeDoneText: PasswordChangeDoneScreenTextToPb(text.PasswordChangeDone), PasswordChangeDoneText: PasswordChangeDoneScreenTextToPb(text.PasswordChangeDone),
PasswordResetDoneText: PasswordResetDoneScreenTextToPb(text.PasswordResetDone), PasswordResetDoneText: PasswordResetDoneScreenTextToPb(text.PasswordResetDone),
RegistrationOptionText: RegistrationOptionScreenTextToPb(text.RegisterOption), RegistrationOptionText: RegistrationOptionScreenTextToPb(text.RegisterOption),
RegistrationUserText: RegistrationUserScreenTextToPb(text.RegistrationUser), RegistrationUserText: RegistrationUserScreenTextToPb(text.RegistrationUser),
RegistrationOrgText: RegistrationOrgScreenTextToPb(text.RegistrationOrg), ExternalRegistrationUserOverviewText: ExternalRegistrationUserOverviewScreenTextToPb(text.ExternalRegistrationUserOverview),
LinkingUserDoneText: LinkingUserDoneScreenTextToPb(text.LinkingUsersDone), RegistrationOrgText: RegistrationOrgScreenTextToPb(text.RegistrationOrg),
ExternalUserNotFoundText: ExternalUserNotFoundScreenTextToPb(text.ExternalNotFoundOption), LinkingUserDoneText: LinkingUserDoneScreenTextToPb(text.LinkingUsersDone),
SuccessLoginText: SuccessLoginScreenTextToPb(text.LoginSuccess), ExternalUserNotFoundText: ExternalUserNotFoundScreenTextToPb(text.ExternalNotFoundOption),
LogoutText: LogoutDoneScreenTextToPb(text.LogoutDone), SuccessLoginText: SuccessLoginScreenTextToPb(text.LoginSuccess),
FooterText: FooterTextToPb(text.Footer), LogoutText: LogoutDoneScreenTextToPb(text.LogoutDone),
FooterText: FooterTextToPb(text.Footer),
} }
} }
@ -299,9 +300,10 @@ func PasswordlessRegistrationScreenTextToPb(text domain.PasswordlessRegistration
func PasswordlessRegistrationDoneScreenTextToPb(text domain.PasswordlessRegistrationDoneScreenText) *text_pb.PasswordlessRegistrationDoneScreenText { func PasswordlessRegistrationDoneScreenTextToPb(text domain.PasswordlessRegistrationDoneScreenText) *text_pb.PasswordlessRegistrationDoneScreenText {
return &text_pb.PasswordlessRegistrationDoneScreenText{ return &text_pb.PasswordlessRegistrationDoneScreenText{
Title: text.Title, Title: text.Title,
Description: text.Description, Description: text.Description,
NextButtonText: text.NextButtonText, NextButtonText: text.NextButtonText,
CancelButtonText: text.CancelButtonText,
} }
} }
@ -365,6 +367,27 @@ func RegistrationUserScreenTextToPb(text domain.RegistrationUserScreenText) *tex
} }
} }
func ExternalRegistrationUserOverviewScreenTextToPb(text domain.ExternalRegistrationUserOverviewScreenText) *text_pb.ExternalRegistrationUserOverviewScreenText {
return &text_pb.ExternalRegistrationUserOverviewScreenText{
Title: text.Title,
Description: text.Description,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
NicknameLabel: text.NicknameLabel,
LanguageLabel: text.LanguageLabel,
PhoneLabel: text.PhoneLabel,
TosAndPrivacyLabel: text.TOSAndPrivacyLabel,
TosConfirm: text.TOSConfirm,
TosLinkText: text.TOSLinkText,
TosConfirmAnd: text.TOSConfirmAnd,
PrivacyLinkText: text.PrivacyLinkText,
NextButtonText: text.NextButtonText,
BackButtonText: text.BackButtonText,
}
}
func RegistrationOrgScreenTextToPb(text domain.RegistrationOrgScreenText) *text_pb.RegistrationOrgScreenText { func RegistrationOrgScreenTextToPb(text domain.RegistrationOrgScreenText) *text_pb.RegistrationOrgScreenText {
return &text_pb.RegistrationOrgScreenText{ return &text_pb.RegistrationOrgScreenText{
Title: text.Title, Title: text.Title,
@ -400,6 +423,11 @@ func ExternalUserNotFoundScreenTextToPb(text domain.ExternalUserNotFoundScreenTe
Description: text.Description, Description: text.Description,
LinkButtonText: text.LinkButtonText, LinkButtonText: text.LinkButtonText,
AutoRegisterButtonText: text.AutoRegisterButtonText, AutoRegisterButtonText: text.AutoRegisterButtonText,
TosAndPrivacyLabel: text.TOSAndPrivacyLabel,
TosConfirm: text.TOSConfirm,
TosLinkText: text.PrivacyLinkText,
TosConfirmAnd: text.TOSConfirmAnd,
PrivacyLinkText: text.PrivacyLinkText,
} }
} }
@ -807,6 +835,30 @@ func RegistrationUserScreenTextPbToDomain(text *text_pb.RegistrationUserScreenTe
} }
} }
func ExternalRegistrationUserOverviewScreenTextPbToDomain(text *text_pb.ExternalRegistrationUserOverviewScreenText) domain.ExternalRegistrationUserOverviewScreenText {
if text == nil {
return domain.ExternalRegistrationUserOverviewScreenText{}
}
return domain.ExternalRegistrationUserOverviewScreenText{
Title: text.Title,
Description: text.Description,
EmailLabel: text.EmailLabel,
UsernameLabel: text.UsernameLabel,
FirstnameLabel: text.FirstnameLabel,
LastnameLabel: text.LastnameLabel,
NicknameLabel: text.NicknameLabel,
LanguageLabel: text.LanguageLabel,
PhoneLabel: text.PhoneLabel,
TOSAndPrivacyLabel: text.TosAndPrivacyLabel,
TOSConfirm: text.TosConfirm,
TOSLinkText: text.TosLinkText,
TOSConfirmAnd: text.TosConfirmAnd,
PrivacyLinkText: text.PrivacyLinkText,
NextButtonText: text.NextButtonText,
BackButtonText: text.BackButtonText,
}
}
func RegistrationOrgScreenTextPbToDomain(text *text_pb.RegistrationOrgScreenText) domain.RegistrationOrgScreenText { func RegistrationOrgScreenTextPbToDomain(text *text_pb.RegistrationOrgScreenText) domain.RegistrationOrgScreenText {
if text == nil { if text == nil {
return domain.RegistrationOrgScreenText{} return domain.RegistrationOrgScreenText{}
@ -851,6 +903,11 @@ func ExternalUserNotFoundScreenTextPbToDomain(text *text_pb.ExternalUserNotFound
Description: text.Description, Description: text.Description,
LinkButtonText: text.LinkButtonText, LinkButtonText: text.LinkButtonText,
AutoRegisterButtonText: text.AutoRegisterButtonText, AutoRegisterButtonText: text.AutoRegisterButtonText,
TOSAndPrivacyLabel: text.TosAndPrivacyLabel,
TOSConfirm: text.TosConfirm,
TOSLinkText: text.PrivacyLinkText,
TOSConfirmAnd: text.TosConfirmAnd,
PrivacyLinkText: text.PrivacyLinkText,
} }
} }

View File

@ -15,6 +15,7 @@ type AuthRequestRepository interface {
CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error
CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser, info *domain.BrowserInfo) error CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser, info *domain.BrowserInfo) error
SetExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser) error
SelectUser(ctx context.Context, id, userID, userAgentID string) error SelectUser(ctx context.Context, id, userID, userAgentID string) error
SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error
VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) error VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) error

View File

@ -233,6 +233,21 @@ func (repo *AuthRequestRepo) CheckExternalUserLogin(ctx context.Context, authReq
return repo.AuthRequests.UpdateAuthRequest(ctx, request) return repo.AuthRequests.UpdateAuthRequest(ctx, request)
} }
func (repo *AuthRequestRepo) SetExternalUserLogin(ctx context.Context, authReqID, userAgentID string, externalUser *domain.ExternalUser) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
if err != nil {
return err
}
err = repo.setLinkingUser(ctx, request, externalUser)
if err != nil {
return err
}
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
}
func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error { func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error {
request.LinkingUsers = append(request.LinkingUsers, externalUser) request.LinkingUsers = append(request.LinkingUsers, externalUser)
return repo.AuthRequests.UpdateAuthRequest(ctx, request) return repo.AuthRequests.UpdateAuthRequest(ctx, request)

View File

@ -40,6 +40,7 @@ func (c *Commands) createAllLoginTextEvents(ctx context.Context, agg *eventstore
events = append(events, c.createPasswordResetDoneEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createPasswordResetDoneEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationOptionEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createRegistrationOptionEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationUserEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createRegistrationUserEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createExternalRegistrationUserOverviewEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createRegistrationOrgEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createRegistrationOrgEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createLinkingUserEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createLinkingUserEvents(ctx, agg, existingText, text, defaultText)...)
events = append(events, c.createExternalUserNotFoundEvents(ctx, agg, existingText, text, defaultText)...) events = append(events, c.createExternalUserNotFoundEvents(ctx, agg, existingText, text, defaultText)...)
@ -664,6 +665,10 @@ func (c *Commands) createPasswordlessRegistrationDoneEvents(ctx context.Context,
if event != nil { if event != nil {
events = append(events, event) events = append(events, event)
} }
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText, existingText.PasswordlessRegistrationDoneCancelButtonText, text.PasswordlessRegistrationDone.CancelButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events return events
} }
@ -832,6 +837,75 @@ func (c *Commands) createRegistrationUserEvents(ctx context.Context, agg *events
return events return events
} }
func (c *Commands) createExternalRegistrationUserOverviewEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTitle, existingText.ExternalRegistrationUserOverviewTitle, text.ExternalRegistrationUserOverview.Title, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewDescription, existingText.ExternalRegistrationUserOverviewDescription, text.ExternalRegistrationUserOverview.Description, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewEmailLabel, existingText.ExternalRegistrationUserOverviewEmailLabel, text.ExternalRegistrationUserOverview.EmailLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewUsernameLabel, existingText.ExternalRegistrationUserOverviewUsernameLabel, text.ExternalRegistrationUserOverview.UsernameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewFirstnameLabel, existingText.ExternalRegistrationUserOverviewFirstnameLabel, text.ExternalRegistrationUserOverview.FirstnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLastnameLabel, existingText.ExternalRegistrationUserOverviewLastnameLabel, text.ExternalRegistrationUserOverview.LastnameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNicknameLabel, existingText.ExternalRegistrationUserOverviewNicknameLabel, text.ExternalRegistrationUserOverview.NicknameLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewLanguageLabel, existingText.ExternalRegistrationUserOverviewLanguageLabel, text.ExternalRegistrationUserOverview.LanguageLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPhoneLabel, existingText.ExternalRegistrationUserOverviewPhoneLabel, text.ExternalRegistrationUserOverview.PhoneLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel, existingText.ExternalRegistrationUserOverviewTOSAndPrivacyLabel, text.ExternalRegistrationUserOverview.TOSAndPrivacyLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSConfirm, existingText.ExternalRegistrationUserOverviewTOSConfirm, text.ExternalRegistrationUserOverview.TOSConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSLinkText, existingText.ExternalRegistrationUserOverviewTOSLinkText, text.ExternalRegistrationUserOverview.TOSLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewTOSConfirmAnd, existingText.ExternalRegistrationUserOverviewTOSConfirmAnd, text.ExternalRegistrationUserOverview.TOSConfirmAnd, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewPrivacyLinkText, existingText.ExternalRegistrationUserOverviewPrivacyLinkText, text.ExternalRegistrationUserOverview.PrivacyLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewBackButtonText, existingText.ExternalRegistrationUserOverviewBackButtonText, text.ExternalRegistrationUserOverview.BackButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalRegistrationUserOverviewNextButtonText, existingText.ExternalRegistrationUserOverviewNextButtonText, text.ExternalRegistrationUserOverview.NextButtonText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events
}
func (c *Commands) createRegistrationOrgEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher { func (c *Commands) createRegistrationOrgEvents(ctx context.Context, agg *eventstore.Aggregate, existingText *CustomLoginTextReadModel, text *domain.CustomLoginText, defaultText bool) []eventstore.EventPusher {
events := make([]eventstore.EventPusher, 0) events := make([]eventstore.EventPusher, 0)
event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTitle, existingText.RegisterOrgTitle, text.RegistrationOrg.Title, text.Language, defaultText) event := c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyRegisterOrgTitle, existingText.RegisterOrgTitle, text.RegistrationOrg.Title, text.Language, defaultText)
@ -936,6 +1010,26 @@ func (c *Commands) createExternalUserNotFoundEvents(ctx context.Context, agg *ev
if event != nil { if event != nil {
events = append(events, event) events = append(events, event)
} }
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel, existingText.ExternalUserNotFoundTOSAndPrivacyLabel, text.ExternalNotFoundOption.TOSAndPrivacyLabel, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSConfirm, existingText.ExternalUserNotFoundTOSConfirm, text.ExternalNotFoundOption.TOSConfirm, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSLinkText, existingText.ExternalUserNotFoundTOSLinkText, text.ExternalNotFoundOption.TOSLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundTOSConfirmAnd, existingText.ExternalUserNotFoundTOSConfirmAnd, text.ExternalNotFoundOption.TOSConfirmAnd, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
event = c.createCustomLoginTextEvent(ctx, agg, domain.LoginKeyExternalNotFoundPrivacyLinkText, existingText.ExternalUserNotFoundPrivacyLinkText, text.ExternalNotFoundOption.PrivacyLinkText, text.Language, defaultText)
if event != nil {
events = append(events, event)
}
return events return events
} }

View File

@ -161,9 +161,10 @@ type CustomLoginTextReadModel struct {
PasswordlessRegistrationNotSupported string PasswordlessRegistrationNotSupported string
PasswordlessRegistrationErrorRetry string PasswordlessRegistrationErrorRetry string
PasswordlessRegistrationDoneTitle string PasswordlessRegistrationDoneTitle string
PasswordlessRegistrationDoneDescription string PasswordlessRegistrationDoneDescription string
PasswordlessRegistrationDoneNextButtonText string PasswordlessRegistrationDoneNextButtonText string
PasswordlessRegistrationDoneCancelButtonText string
PasswordChangeTitle string PasswordChangeTitle string
PasswordChangeDescription string PasswordChangeDescription string
@ -207,6 +208,25 @@ type CustomLoginTextReadModel struct {
RegistrationUserNextButtonText string RegistrationUserNextButtonText string
RegistrationUserBackButtonText string RegistrationUserBackButtonText string
ExternalRegistrationUserOverviewTitle string
ExternalRegistrationUserOverviewDescription string
ExternalRegistrationUserOverviewEmailLabel string
ExternalRegistrationUserOverviewUsernameLabel string
ExternalRegistrationUserOverviewFirstnameLabel string
ExternalRegistrationUserOverviewLastnameLabel string
ExternalRegistrationUserOverviewNicknameLabel string
ExternalRegistrationUserOverviewLanguageLabel string
ExternalRegistrationUserOverviewPhoneLabel string
ExternalRegistrationUserOverviewTOSAndPrivacyLabel string
ExternalRegistrationUserOverviewTOSConfirm string
ExternalRegistrationUserOverviewTOSLink string
ExternalRegistrationUserOverviewTOSLinkText string
ExternalRegistrationUserOverviewTOSConfirmAnd string
ExternalRegistrationUserOverviewPrivacyLink string
ExternalRegistrationUserOverviewPrivacyLinkText string
ExternalRegistrationUserOverviewBackButtonText string
ExternalRegistrationUserOverviewNextButtonText string
RegisterOrgTitle string RegisterOrgTitle string
RegisterOrgDescription string RegisterOrgDescription string
RegisterOrgOrgNameLabel string RegisterOrgOrgNameLabel string
@ -232,6 +252,11 @@ type CustomLoginTextReadModel struct {
ExternalUserNotFoundDescription string ExternalUserNotFoundDescription string
ExternalUserNotFoundLinkButtonText string ExternalUserNotFoundLinkButtonText string
ExternalUserNotFoundAutoRegisterButtonText string ExternalUserNotFoundAutoRegisterButtonText string
ExternalUserNotFoundTOSAndPrivacyLabel string
ExternalUserNotFoundTOSConfirm string
ExternalUserNotFoundTOSLinkText string
ExternalUserNotFoundTOSConfirmAnd string
ExternalUserNotFoundPrivacyLinkText string
SuccessLoginTitle string SuccessLoginTitle string
SuccessLoginAutoRedirectDescription string SuccessLoginAutoRedirectDescription string
@ -364,6 +389,10 @@ func (wm *CustomLoginTextReadModel) Reduce() error {
wm.handleRegistrationUserScreenSetEvent(e) wm.handleRegistrationUserScreenSetEvent(e)
continue continue
} }
if strings.HasPrefix(e.Key, domain.LoginKeyExternalRegistrationUserOverview) {
wm.handleExternalRegistrationUserOverviewScreenSetEvent(e)
continue
}
if strings.HasPrefix(e.Key, domain.LoginKeyRegistrationOrg) { if strings.HasPrefix(e.Key, domain.LoginKeyRegistrationOrg) {
wm.handleRegistrationOrgScreenSetEvent(e) wm.handleRegistrationOrgScreenSetEvent(e)
continue continue
@ -500,6 +529,10 @@ func (wm *CustomLoginTextReadModel) Reduce() error {
wm.handleRegistrationUserScreenRemoveEvent(e) wm.handleRegistrationUserScreenRemoveEvent(e)
continue continue
} }
if strings.HasPrefix(e.Key, domain.LoginKeyExternalRegistrationUserOverview) {
wm.handleExternalRegistrationUserOverviewScreenRemoveEvent(e)
continue
}
if strings.HasPrefix(e.Key, domain.LoginKeyRegistrationOrg) { if strings.HasPrefix(e.Key, domain.LoginKeyRegistrationOrg) {
wm.handleRegistrationOrgScreenRemoveEvent(e) wm.handleRegistrationOrgScreenRemoveEvent(e)
continue continue
@ -1652,6 +1685,10 @@ func (wm *CustomLoginTextReadModel) handlePasswordlessRegistrationDoneScreenSetE
wm.PasswordlessRegistrationDoneNextButtonText = e.Text wm.PasswordlessRegistrationDoneNextButtonText = e.Text
return return
} }
if e.Key == domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText {
wm.PasswordlessRegistrationDoneCancelButtonText = e.Text
return
}
} }
func (wm *CustomLoginTextReadModel) handlePasswordlessRegistrationDoneScreenRemoveEvent(e *policy.CustomTextRemovedEvent) { func (wm *CustomLoginTextReadModel) handlePasswordlessRegistrationDoneScreenRemoveEvent(e *policy.CustomTextRemovedEvent) {
@ -1667,6 +1704,10 @@ func (wm *CustomLoginTextReadModel) handlePasswordlessRegistrationDoneScreenRemo
wm.PasswordlessRegistrationDoneNextButtonText = "" wm.PasswordlessRegistrationDoneNextButtonText = ""
return return
} }
if e.Key == domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText {
wm.PasswordlessRegistrationDoneCancelButtonText = ""
return
}
} }
func (wm *CustomLoginTextReadModel) handlePasswordChangeScreenSetEvent(e *policy.CustomTextSetEvent) { func (wm *CustomLoginTextReadModel) handlePasswordChangeScreenSetEvent(e *policy.CustomTextSetEvent) {
@ -1904,6 +1945,73 @@ func (wm *CustomLoginTextReadModel) handleRegistrationUserScreenSetEvent(e *poli
} }
} }
func (wm *CustomLoginTextReadModel) handleExternalRegistrationUserOverviewScreenSetEvent(e *policy.CustomTextSetEvent) {
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTitle {
wm.ExternalRegistrationUserOverviewTitle = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewDescription {
wm.ExternalRegistrationUserOverviewDescription = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewEmailLabel {
wm.ExternalRegistrationUserOverviewEmailLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewUsernameLabel {
wm.ExternalRegistrationUserOverviewUsernameLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewFirstnameLabel {
wm.ExternalRegistrationUserOverviewFirstnameLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewLastnameLabel {
wm.ExternalRegistrationUserOverviewLastnameLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewNicknameLabel {
wm.ExternalRegistrationUserOverviewNicknameLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewLanguageLabel {
wm.ExternalRegistrationUserOverviewLanguageLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewPhoneLabel {
wm.ExternalRegistrationUserOverviewPhoneLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel {
wm.ExternalRegistrationUserOverviewTOSAndPrivacyLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSConfirm {
wm.ExternalRegistrationUserOverviewTOSConfirm = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSLinkText {
wm.ExternalRegistrationUserOverviewTOSLinkText = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSConfirmAnd {
wm.ExternalRegistrationUserOverviewTOSConfirmAnd = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewPrivacyLinkText {
wm.ExternalRegistrationUserOverviewPrivacyLinkText = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewBackButtonText {
wm.ExternalRegistrationUserOverviewBackButtonText = e.Text
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewNextButtonText {
wm.ExternalRegistrationUserOverviewNextButtonText = e.Text
return
}
}
func (wm *CustomLoginTextReadModel) handleRegistrationUserScreenRemoveEvent(e *policy.CustomTextRemovedEvent) { func (wm *CustomLoginTextReadModel) handleRegistrationUserScreenRemoveEvent(e *policy.CustomTextRemovedEvent) {
if e.Key == domain.LoginKeyRegistrationUserTitle { if e.Key == domain.LoginKeyRegistrationUserTitle {
wm.RegistrationUserTitle = "" wm.RegistrationUserTitle = ""
@ -1979,6 +2087,73 @@ func (wm *CustomLoginTextReadModel) handleRegistrationUserScreenRemoveEvent(e *p
} }
} }
func (wm *CustomLoginTextReadModel) handleExternalRegistrationUserOverviewScreenRemoveEvent(e *policy.CustomTextRemovedEvent) {
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTitle {
wm.ExternalRegistrationUserOverviewTitle = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewDescription {
wm.ExternalRegistrationUserOverviewDescription = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewEmailLabel {
wm.ExternalRegistrationUserOverviewEmailLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewUsernameLabel {
wm.ExternalRegistrationUserOverviewUsernameLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewFirstnameLabel {
wm.ExternalRegistrationUserOverviewFirstnameLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewLastnameLabel {
wm.ExternalRegistrationUserOverviewLastnameLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewNicknameLabel {
wm.ExternalRegistrationUserOverviewNicknameLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewLanguageLabel {
wm.ExternalRegistrationUserOverviewLanguageLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewPhoneLabel {
wm.ExternalRegistrationUserOverviewPhoneLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel {
wm.ExternalRegistrationUserOverviewTOSAndPrivacyLabel = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSConfirm {
wm.ExternalRegistrationUserOverviewTOSConfirm = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSLinkText {
wm.ExternalRegistrationUserOverviewTOSLinkText = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewTOSConfirmAnd {
wm.ExternalRegistrationUserOverviewTOSConfirmAnd = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewPrivacyLinkText {
wm.ExternalRegistrationUserOverviewPrivacyLinkText = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewBackButtonText {
wm.ExternalRegistrationUserOverviewBackButtonText = ""
return
}
if e.Key == domain.LoginKeyExternalRegistrationUserOverviewNextButtonText {
wm.ExternalRegistrationUserOverviewNextButtonText = ""
return
}
}
func (wm *CustomLoginTextReadModel) handleRegistrationOrgScreenSetEvent(e *policy.CustomTextSetEvent) { func (wm *CustomLoginTextReadModel) handleRegistrationOrgScreenSetEvent(e *policy.CustomTextSetEvent) {
if e.Key == domain.LoginKeyRegisterOrgTitle { if e.Key == domain.LoginKeyRegisterOrgTitle {
wm.RegisterOrgTitle = e.Text wm.RegisterOrgTitle = e.Text
@ -2160,6 +2335,26 @@ func (wm *CustomLoginTextReadModel) handleExternalUserNotFoundScreenSetEvent(e *
wm.ExternalUserNotFoundAutoRegisterButtonText = e.Text wm.ExternalUserNotFoundAutoRegisterButtonText = e.Text
return return
} }
if e.Key == domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel {
wm.ExternalUserNotFoundTOSAndPrivacyLabel = e.Text
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSConfirm {
wm.ExternalUserNotFoundTOSConfirm = e.Text
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSLinkText {
wm.ExternalUserNotFoundTOSLinkText = e.Text
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSConfirmAnd {
wm.ExternalUserNotFoundTOSConfirmAnd = e.Text
return
}
if e.Key == domain.LoginKeyExternalNotFoundPrivacyLinkText {
wm.ExternalUserNotFoundPrivacyLinkText = e.Text
return
}
} }
func (wm *CustomLoginTextReadModel) handleExternalUserNotFoundScreenRemoveEvent(e *policy.CustomTextRemovedEvent) { func (wm *CustomLoginTextReadModel) handleExternalUserNotFoundScreenRemoveEvent(e *policy.CustomTextRemovedEvent) {
@ -2179,6 +2374,26 @@ func (wm *CustomLoginTextReadModel) handleExternalUserNotFoundScreenRemoveEvent(
wm.ExternalUserNotFoundAutoRegisterButtonText = "" wm.ExternalUserNotFoundAutoRegisterButtonText = ""
return return
} }
if e.Key == domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel {
wm.ExternalUserNotFoundTOSAndPrivacyLabel = ""
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSLinkText {
wm.ExternalUserNotFoundTOSLinkText = ""
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSConfirm {
wm.ExternalUserNotFoundTOSConfirm = ""
return
}
if e.Key == domain.LoginKeyExternalNotFoundTOSConfirmAnd {
wm.ExternalUserNotFoundTOSConfirmAnd = ""
return
}
if e.Key == domain.LoginKeyExternalNotFoundPrivacyLinkText {
wm.ExternalUserNotFoundPrivacyLinkText = ""
return
}
} }
func (wm *CustomLoginTextReadModel) handleSuccessLoginScreenSetEvent(e *policy.CustomTextSetEvent) { func (wm *CustomLoginTextReadModel) handleSuccessLoginScreenSetEvent(e *policy.CustomTextSetEvent) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -206,7 +206,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
events = append(events, event) events = append(events, event)
} }
if human.IsInitialState(passwordless) { if human.IsInitialState(passwordless, externalIDP != nil) {
initCode, err := domain.NewInitUserCode(c.initializeUserCode) initCode, err := domain.NewInitUserCode(c.initializeUserCode)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err

View File

@ -175,10 +175,11 @@ const (
LoginKeyPasswordlessRegistrationNotSupported = LoginKeyPasswordlessRegistration + "NotSupported" LoginKeyPasswordlessRegistrationNotSupported = LoginKeyPasswordlessRegistration + "NotSupported"
LoginKeyPasswordlessRegistrationErrorRetry = LoginKeyPasswordlessRegistration + "ErrorRetry" LoginKeyPasswordlessRegistrationErrorRetry = LoginKeyPasswordlessRegistration + "ErrorRetry"
LoginKeyPasswordlessRegistrationDone = "PasswordlessRegistrationDone." LoginKeyPasswordlessRegistrationDone = "PasswordlessRegistrationDone."
LoginKeyPasswordlessRegistrationDoneTitle = LoginKeyPasswordlessRegistrationDone + "Title" LoginKeyPasswordlessRegistrationDoneTitle = LoginKeyPasswordlessRegistrationDone + "Title"
LoginKeyPasswordlessRegistrationDoneDescription = LoginKeyPasswordlessRegistrationDone + "Description" LoginKeyPasswordlessRegistrationDoneDescription = LoginKeyPasswordlessRegistrationDone + "Description"
LoginKeyPasswordlessRegistrationDoneNextButtonText = LoginKeyPasswordlessRegistrationDone + "NextButtonText" LoginKeyPasswordlessRegistrationDoneNextButtonText = LoginKeyPasswordlessRegistrationDone + "NextButtonText"
LoginKeyPasswordlessRegistrationDoneCancelButtonText = LoginKeyPasswordlessRegistrationDone + "CancelButtonText"
LoginKeyPasswordChange = "PasswordChange." LoginKeyPasswordChange = "PasswordChange."
LoginKeyPasswordChangeTitle = LoginKeyPasswordChange + "Title" LoginKeyPasswordChangeTitle = LoginKeyPasswordChange + "Title"
@ -225,6 +226,24 @@ const (
LoginKeyRegistrationUserNextButtonText = LoginKeyRegistrationUser + "NextButtonText" LoginKeyRegistrationUserNextButtonText = LoginKeyRegistrationUser + "NextButtonText"
LoginKeyRegistrationUserBackButtonText = LoginKeyRegistrationUser + "BackButtonText" LoginKeyRegistrationUserBackButtonText = LoginKeyRegistrationUser + "BackButtonText"
LoginKeyExternalRegistrationUserOverview = "ExternalRegistrationUserOverview."
LoginKeyExternalRegistrationUserOverviewTitle = LoginKeyExternalRegistrationUserOverview + "Title"
LoginKeyExternalRegistrationUserOverviewDescription = LoginKeyExternalRegistrationUserOverview + "Description"
LoginKeyExternalRegistrationUserOverviewEmailLabel = LoginKeyExternalRegistrationUserOverview + "EmailLabel"
LoginKeyExternalRegistrationUserOverviewUsernameLabel = LoginKeyExternalRegistrationUserOverview + "UsernameLabel"
LoginKeyExternalRegistrationUserOverviewFirstnameLabel = LoginKeyExternalRegistrationUserOverview + "FirstnameLabel"
LoginKeyExternalRegistrationUserOverviewLastnameLabel = LoginKeyExternalRegistrationUserOverview + "LastnameLabel"
LoginKeyExternalRegistrationUserOverviewNicknameLabel = LoginKeyExternalRegistrationUserOverview + "NicknameLabel"
LoginKeyExternalRegistrationUserOverviewPhoneLabel = LoginKeyExternalRegistrationUserOverview + "PhoneLabel"
LoginKeyExternalRegistrationUserOverviewLanguageLabel = LoginKeyExternalRegistrationUserOverview + "LanguageLabel"
LoginKeyExternalRegistrationUserOverviewTOSAndPrivacyLabel = LoginKeyExternalRegistrationUserOverview + "TosAndPrivacyLabel"
LoginKeyExternalRegistrationUserOverviewTOSConfirm = LoginKeyExternalRegistrationUserOverview + "TosConfirm"
LoginKeyExternalRegistrationUserOverviewTOSLinkText = LoginKeyExternalRegistrationUserOverview + "TosLinkText"
LoginKeyExternalRegistrationUserOverviewTOSConfirmAnd = LoginKeyExternalRegistrationUserOverview + "TosConfirmAnd"
LoginKeyExternalRegistrationUserOverviewPrivacyLinkText = LoginKeyExternalRegistrationUserOverview + "PrivacyLinkText"
LoginKeyExternalRegistrationUserOverviewBackButtonText = LoginKeyExternalRegistrationUserOverview + "BackButtonText"
LoginKeyExternalRegistrationUserOverviewNextButtonText = LoginKeyExternalRegistrationUserOverview + "NextButtonText"
LoginKeyRegistrationOrg = "RegistrationOrg." LoginKeyRegistrationOrg = "RegistrationOrg."
LoginKeyRegisterOrgTitle = LoginKeyRegistrationOrg + "Title" LoginKeyRegisterOrgTitle = LoginKeyRegistrationOrg + "Title"
LoginKeyRegisterOrgDescription = LoginKeyRegistrationOrg + "Description" LoginKeyRegisterOrgDescription = LoginKeyRegistrationOrg + "Description"
@ -253,6 +272,11 @@ const (
LoginKeyExternalNotFoundDescription = LoginKeyExternalNotFound + "Description" LoginKeyExternalNotFoundDescription = LoginKeyExternalNotFound + "Description"
LoginKeyExternalNotFoundLinkButtonText = LoginKeyExternalNotFound + "LinkButtonText" LoginKeyExternalNotFoundLinkButtonText = LoginKeyExternalNotFound + "LinkButtonText"
LoginKeyExternalNotFoundAutoRegisterButtonText = LoginKeyExternalNotFound + "AutoRegisterButtonText" LoginKeyExternalNotFoundAutoRegisterButtonText = LoginKeyExternalNotFound + "AutoRegisterButtonText"
LoginKeyExternalNotFoundTOSAndPrivacyLabel = LoginKeyExternalNotFound + "TosAndPrivacyLabel"
LoginKeyExternalNotFoundTOSConfirm = LoginKeyExternalNotFound + "TosConfirm"
LoginKeyExternalNotFoundTOSLinkText = LoginKeyExternalNotFound + "TosLinkText"
LoginKeyExternalNotFoundTOSConfirmAnd = LoginKeyExternalNotFound + "TosConfirmAnd"
LoginKeyExternalNotFoundPrivacyLinkText = LoginKeyExternalNotFound + "PrivacyLinkText"
LoginKeySuccessLogin = "LoginSuccess." LoginKeySuccessLogin = "LoginSuccess."
LoginKeySuccessLoginTitle = LoginKeySuccessLogin + "Title" LoginKeySuccessLoginTitle = LoginKeySuccessLogin + "Title"
@ -279,39 +303,40 @@ type CustomLoginText struct {
Default bool Default bool
Language language.Tag Language language.Tag
SelectAccount SelectAccountScreenText SelectAccount SelectAccountScreenText
Login LoginScreenText Login LoginScreenText
Password PasswordScreenText Password PasswordScreenText
UsernameChange UsernameChangeScreenText UsernameChange UsernameChangeScreenText
UsernameChangeDone UsernameChangeDoneScreenText UsernameChangeDone UsernameChangeDoneScreenText
InitPassword InitPasswordScreenText InitPassword InitPasswordScreenText
InitPasswordDone InitPasswordDoneScreenText InitPasswordDone InitPasswordDoneScreenText
EmailVerification EmailVerificationScreenText EmailVerification EmailVerificationScreenText
EmailVerificationDone EmailVerificationDoneScreenText EmailVerificationDone EmailVerificationDoneScreenText
InitUser InitializeUserScreenText InitUser InitializeUserScreenText
InitUserDone InitializeUserDoneScreenText InitUserDone InitializeUserDoneScreenText
InitMFAPrompt InitMFAPromptScreenText InitMFAPrompt InitMFAPromptScreenText
InitMFAOTP InitMFAOTPScreenText InitMFAOTP InitMFAOTPScreenText
InitMFAU2F InitMFAU2FScreenText InitMFAU2F InitMFAU2FScreenText
InitMFADone InitMFADoneScreenText InitMFADone InitMFADoneScreenText
MFAProvider MFAProvidersText MFAProvider MFAProvidersText
VerifyMFAOTP VerifyMFAOTPScreenText VerifyMFAOTP VerifyMFAOTPScreenText
VerifyMFAU2F VerifyMFAU2FScreenText VerifyMFAU2F VerifyMFAU2FScreenText
Passwordless PasswordlessScreenText Passwordless PasswordlessScreenText
PasswordlessPrompt PasswordlessPromptScreenText PasswordlessPrompt PasswordlessPromptScreenText
PasswordlessRegistration PasswordlessRegistrationScreenText PasswordlessRegistration PasswordlessRegistrationScreenText
PasswordlessRegistrationDone PasswordlessRegistrationDoneScreenText PasswordlessRegistrationDone PasswordlessRegistrationDoneScreenText
PasswordChange PasswordChangeScreenText PasswordChange PasswordChangeScreenText
PasswordChangeDone PasswordChangeDoneScreenText PasswordChangeDone PasswordChangeDoneScreenText
PasswordResetDone PasswordResetDoneScreenText PasswordResetDone PasswordResetDoneScreenText
RegisterOption RegistrationOptionScreenText RegisterOption RegistrationOptionScreenText
RegistrationUser RegistrationUserScreenText RegistrationUser RegistrationUserScreenText
RegistrationOrg RegistrationOrgScreenText ExternalRegistrationUserOverview ExternalRegistrationUserOverviewScreenText
LinkingUsersDone LinkingUserDoneScreenText RegistrationOrg RegistrationOrgScreenText
ExternalNotFoundOption ExternalUserNotFoundScreenText LinkingUsersDone LinkingUserDoneScreenText
LoginSuccess SuccessLoginScreenText ExternalNotFoundOption ExternalUserNotFoundScreenText
LogoutDone LogoutDoneScreenText LoginSuccess SuccessLoginScreenText
Footer FooterText LogoutDone LogoutDoneScreenText
Footer FooterText
} }
func (m *CustomLoginText) IsValid() bool { func (m *CustomLoginText) IsValid() bool {
@ -537,6 +562,25 @@ type RegistrationUserScreenText struct {
BackButtonText string BackButtonText string
} }
type ExternalRegistrationUserOverviewScreenText struct {
Title string
Description string
EmailLabel string
UsernameLabel string
FirstnameLabel string
LastnameLabel string
NicknameLabel string
LanguageLabel string
PhoneLabel string
TOSAndPrivacyLabel string
TOSConfirm string
TOSLinkText string
TOSConfirmAnd string
PrivacyLinkText string
BackButtonText string
NextButtonText string
}
type RegistrationOrgScreenText struct { type RegistrationOrgScreenText struct {
Title string Title string
Description string Description string
@ -567,6 +611,11 @@ type ExternalUserNotFoundScreenText struct {
Description string Description string
LinkButtonText string LinkButtonText string
AutoRegisterButtonText string AutoRegisterButtonText string
TOSAndPrivacyLabel string
TOSConfirm string
TOSLinkText string
TOSConfirmAnd string
PrivacyLinkText string
} }
type SuccessLoginScreenText struct { type SuccessLoginScreenText struct {
@ -608,7 +657,8 @@ type PasswordlessRegistrationScreenText struct {
} }
type PasswordlessRegistrationDoneScreenText struct { type PasswordlessRegistrationDoneScreenText struct {
Title string Title string
Description string Description string
NextButtonText string NextButtonText string
CancelButtonText string
} }

View File

@ -18,7 +18,6 @@ type Human struct {
*Email *Email
*Phone *Phone
*Address *Address
ExternalIDPs []*ExternalIDP
} }
func (h Human) GetUsername() string { func (h Human) GetUsername() string {
@ -79,8 +78,8 @@ func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, passwor
return nil return nil
} }
func (u *Human) IsInitialState(passwordless bool) bool { func (u *Human) IsInitialState(passwordless, externalIDPs bool) bool {
return u.Email == nil || !u.IsEmailVerified || (u.ExternalIDPs == nil || len(u.ExternalIDPs) == 0) && !passwordless && (u.Password == nil || u.SecretString == "") return u.Email == nil || !u.IsEmailVerified || !externalIDPs && !passwordless && (u.Password == nil || u.SecretString == "")
} }
func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) { func NewInitUserCode(generator crypto.Generator) (*InitUserCode, error) {

View File

@ -700,6 +700,9 @@ func passwordlessRegistrationDoneKeyToDomain(text *CustomTextView, result *domai
if text.Key == domain.LoginKeyPasswordlessRegistrationDoneNextButtonText { if text.Key == domain.LoginKeyPasswordlessRegistrationDoneNextButtonText {
result.PasswordlessRegistrationDone.NextButtonText = text.Text result.PasswordlessRegistrationDone.NextButtonText = text.Text
} }
if text.Key == domain.LoginKeyPasswordlessRegistrationDoneCancelButtonText {
result.PasswordlessRegistrationDone.CancelButtonText = text.Text
}
} }
func passwordChangeKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) { func passwordChangeKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {
@ -898,6 +901,21 @@ func externalUserNotFoundKeyToDomain(text *CustomTextView, result *domain.Custom
if text.Key == domain.LoginKeyExternalNotFoundAutoRegisterButtonText { if text.Key == domain.LoginKeyExternalNotFoundAutoRegisterButtonText {
result.ExternalNotFoundOption.AutoRegisterButtonText = text.Text result.ExternalNotFoundOption.AutoRegisterButtonText = text.Text
} }
if text.Key == domain.LoginKeyExternalNotFoundTOSAndPrivacyLabel {
result.ExternalNotFoundOption.TOSAndPrivacyLabel = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundTOSConfirm {
result.ExternalNotFoundOption.TOSConfirm = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundTOSLinkText {
result.ExternalNotFoundOption.TOSLinkText = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundTOSConfirmAnd {
result.ExternalNotFoundOption.TOSConfirmAnd = text.Text
}
if text.Key == domain.LoginKeyExternalNotFoundPrivacyLinkText {
result.ExternalNotFoundOption.PrivacyLinkText = text.Text
}
} }
func successLoginKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) { func successLoginKeyToDomain(text *CustomTextView, result *domain.CustomLoginText) {

View File

@ -1,6 +1,10 @@
package handler package handler
import ( import (
"net/http"
"strings"
"time"
"github.com/caos/oidc/pkg/client/rp" "github.com/caos/oidc/pkg/client/rp"
"github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/oidc"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -11,9 +15,6 @@ import (
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
caos_errors "github.com/caos/zitadel/internal/errors" caos_errors "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model" iam_model "github.com/caos/zitadel/internal/iam/model"
"net/http"
"strings"
"time"
) )
const ( const (
@ -34,6 +35,7 @@ type externalNotFoundOptionFormData struct {
Link bool `schema:"link"` Link bool `schema:"link"`
AutoRegister bool `schema:"autoregister"` AutoRegister bool `schema:"autoregister"`
ResetLinking bool `schema:"resetlinking"` ResetLinking bool `schema:"resetlinking"`
TermsConfirm bool `schema:"terms-confirm"`
} }
type externalNotFoundOptionData struct { type externalNotFoundOptionData struct {

View File

@ -6,6 +6,7 @@ import (
"github.com/caos/oidc/pkg/client/rp" "github.com/caos/oidc/pkg/client/rp"
"github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/oidc"
"golang.org/x/text/language"
http_mw "github.com/caos/zitadel/internal/api/http/middleware" http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
@ -13,6 +14,42 @@ import (
iam_model "github.com/caos/zitadel/internal/iam/model" iam_model "github.com/caos/zitadel/internal/iam/model"
) )
const (
tmplExternalRegisterOverview = "externalregisteroverview"
)
type externalRegisterFormData struct {
ExternalIDPConfigID string `schema:"external-idp-config-id"`
ExternalIDPExtUserID string `schema:"external-idp-ext-user-id"`
ExternalIDPDisplayName string `schema:"external-idp-display-name"`
ExternalEmail string `schema:"external-email"`
ExternalEmailVerified bool `schema:"external-email-verified"`
Email string `schema:"email"`
Username string `schema:"username"`
Firstname string `schema:"firstname"`
Lastname string `schema:"lastname"`
Nickname string `schema:"nickname"`
ExternalPhone string `schema:"external-phone"`
ExternalPhoneVerified bool `schema:"external-phone-verified"`
Phone string `schema:"phone"`
Language string `schema:"language"`
TermsConfirm bool `schema:"terms-confirm"`
}
type externalRegisterData struct {
baseData
externalRegisterFormData
ExternalIDPID string
ExternalIDPUserID string
ExternalIDPUserDisplayName string
ShowUsername bool
OrgRegister bool
ExternalEmail string
ExternalEmailVerified bool
ExternalPhone string
ExternalPhoneVerified bool
}
func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) { func (l *Login) handleExternalRegister(w http.ResponseWriter, r *http.Request) {
data := new(externalIDPData) data := new(externalIDPData)
authReq, err := l.getAuthRequestAndParseData(r, data) authReq, err := l.getAuthRequestAndParseData(r, data)
@ -76,18 +113,77 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
return return
} }
resourceOwner := iam.GlobalOrgID resourceOwner := iam.GlobalOrgID
memberRoles := []string{domain.RoleOrgProjectCreator}
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
memberRoles = nil
resourceOwner = authReq.RequestedOrgID
}
orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner) orgIamPolicy, err := l.getOrgIamPolicy(r, resourceOwner)
if err != nil { if err != nil {
l.renderRegisterOption(w, r, authReq, err) l.renderRegisterOption(w, r, authReq, err)
return return
} }
user, externalIDP := l.mapTokenToLoginHumanAndExternalIDP(orgIamPolicy, tokens, idpConfig) user, externalIDP := l.mapTokenToLoginHumanAndExternalIDP(orgIamPolicy, tokens, idpConfig)
l.renderExternalRegisterOverview(w, r, authReq, orgIamPolicy, user, externalIDP, nil)
}
func (l *Login) renderExternalRegisterOverview(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *iam_model.OrgIAMPolicyView, human *domain.Human, idp *domain.ExternalIDP, err error) {
var errID, errMessage string
if err != nil {
errID, errMessage = l.getErrorMessage(r, err)
}
data := externalRegisterData{
baseData: l.getBaseData(r, authReq, "ExternalRegisterOverview", errID, errMessage),
externalRegisterFormData: externalRegisterFormData{
Email: human.EmailAddress,
Username: human.PreferredLoginName,
Firstname: human.FirstName,
Lastname: human.LastName,
Nickname: human.NickName,
Language: human.PreferredLanguage.String(),
},
ExternalIDPID: idp.IDPConfigID,
ExternalIDPUserID: idp.ExternalUserID,
ExternalIDPUserDisplayName: idp.DisplayName,
ExternalEmail: human.EmailAddress,
ExternalEmailVerified: human.IsEmailVerified,
ShowUsername: orgIAMPolicy.UserLoginMustBeDomain,
OrgRegister: orgIAMPolicy.UserLoginMustBeDomain,
}
if human.Phone != nil {
data.Phone = human.PhoneNumber
data.ExternalPhone = human.PhoneNumber
data.ExternalPhoneVerified = human.IsPhoneVerified
}
translator := l.getTranslator(authReq)
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplExternalRegisterOverview], data, nil)
}
func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Request) {
data := new(externalRegisterFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return
}
iam, err := l.authRepo.GetIAM(r.Context())
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
resourceOwner := iam.GlobalOrgID
memberRoles := []string{domain.RoleOrgProjectCreator}
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
memberRoles = nil
resourceOwner = authReq.RequestedOrgID
}
externalIDP, err := l.getExternalIDP(data)
if externalIDP == nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
user, err := l.mapExternalRegisterDataToUser(r, data)
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
_, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, memberRoles) _, err = l.command.RegisterHuman(setContext(r.Context(), resourceOwner), resourceOwner, user, externalIDP, memberRoles)
if err != nil { if err != nil {
l.renderRegisterOption(w, r, authReq, err) l.renderRegisterOption(w, r, authReq, err)
@ -140,6 +236,9 @@ func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *iam_model.OrgIA
displayName = tokens.IDTokenClaims.GetEmail() displayName = tokens.IDTokenClaims.GetEmail()
} }
} }
if displayName == "" {
displayName = tokens.IDTokenClaims.GetEmail()
}
externalIDP := &domain.ExternalIDP{ externalIDP := &domain.ExternalIDP{
IDPConfigID: idpConfig.IDPConfigID, IDPConfigID: idpConfig.IDPConfigID,
@ -148,3 +247,43 @@ func (l *Login) mapTokenToLoginHumanAndExternalIDP(orgIamPolicy *iam_model.OrgIA
} }
return human, externalIDP return human, externalIDP
} }
func (l *Login) mapExternalRegisterDataToUser(r *http.Request, data *externalRegisterFormData) (*domain.Human, error) {
human := &domain.Human{
Username: data.Username,
Profile: &domain.Profile{
FirstName: data.Firstname,
LastName: data.Lastname,
PreferredLanguage: language.Make(data.Language),
NickName: data.Nickname,
},
Email: &domain.Email{
EmailAddress: data.Email,
},
}
if data.ExternalEmail != data.Email {
human.IsEmailVerified = false
} else {
human.IsEmailVerified = data.ExternalEmailVerified
}
if data.ExternalPhone == "" {
return human, nil
}
human.Phone = &domain.Phone{
PhoneNumber: data.Phone,
}
if data.ExternalPhone != data.Phone {
human.IsPhoneVerified = false
} else {
human.IsPhoneVerified = data.ExternalPhoneVerified
}
return human, nil
}
func (l *Login) getExternalIDP(data *externalRegisterFormData) (*domain.ExternalIDP, error) {
return &domain.ExternalIDP{
IDPConfigID: data.ExternalIDPConfigID,
ExternalUserID: data.ExternalIDPExtUserID,
DisplayName: data.ExternalIDPDisplayName,
}, nil
}

View File

@ -62,6 +62,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
tmplChangePasswordDone: "change_password_done.html", tmplChangePasswordDone: "change_password_done.html",
tmplRegisterOption: "register_option.html", tmplRegisterOption: "register_option.html",
tmplRegister: "register.html", tmplRegister: "register.html",
tmplExternalRegisterOverview: "external_register_overview.html",
tmplLogoutDone: "logout_done.html", tmplLogoutDone: "logout_done.html",
tmplRegisterOrg: "register_org.html", tmplRegisterOrg: "register_org.html",
tmplChangeUsername: "change_username.html", tmplChangeUsername: "change_username.html",
@ -181,6 +182,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
"orgRegistrationUrl": func() string { "orgRegistrationUrl": func() string {
return path.Join(r.pathPrefix, EndpointRegisterOrg) return path.Join(r.pathPrefix, EndpointRegisterOrg)
}, },
"externalRegistrationUrl": func() string {
return path.Join(r.pathPrefix, EndpointExternalRegister)
},
"changeUsernameUrl": func() string { "changeUsernameUrl": func() string {
return path.Join(r.pathPrefix, EndpointChangeUsername) return path.Join(r.pathPrefix, EndpointChangeUsername)
}, },

View File

@ -82,6 +82,7 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
router.HandleFunc(EndpointRegister, login.handleRegister).Methods(http.MethodGet) router.HandleFunc(EndpointRegister, login.handleRegister).Methods(http.MethodGet)
router.HandleFunc(EndpointRegister, login.handleRegisterCheck).Methods(http.MethodPost) router.HandleFunc(EndpointRegister, login.handleRegisterCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointExternalRegister, login.handleExternalRegister).Methods(http.MethodGet) router.HandleFunc(EndpointExternalRegister, login.handleExternalRegister).Methods(http.MethodGet)
router.HandleFunc(EndpointExternalRegister, login.handleExternalRegisterCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointExternalRegisterCallback, login.handleExternalRegisterCallback).Methods(http.MethodGet) router.HandleFunc(EndpointExternalRegisterCallback, login.handleExternalRegisterCallback).Methods(http.MethodGet)
router.HandleFunc(EndpointLogoutDone, login.handleLogoutDone).Methods(http.MethodGet) router.HandleFunc(EndpointLogoutDone, login.handleLogoutDone).Methods(http.MethodGet)
router.HandleFunc(EndpointDynamicResources, login.handleDynamicResources).Methods(http.MethodGet) router.HandleFunc(EndpointDynamicResources, login.handleDynamicResources).Methods(http.MethodGet)

View File

@ -221,6 +221,26 @@ RegistrationUser:
BackButtonText: zurück BackButtonText: zurück
NextButtonText: weiter NextButtonText: weiter
ExternalRegistrationUserOverview:
Title: Externer Benutzer Registration
Description: Deine Benutzerangaben werden vom ausgewählten Provider übernommen. Du kannst sie hier ändern und ergänzen, bevor dein Benutzer angelegt wird.
EmailLabel: E-Mail
UsernameLabel: Benutzername
FirstnameLabel: Vorname
LastnameLabel: Nachname
NicknameLabel: Nachname
PhoneLabel: Telefonnummer
LanguageLabel: Sprache
German: Deutsch
English: English
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
TosConfirm: Ich akzeptiere die
TosLinkText: AGBs
TosConfirmAnd: und die
PrivacyLinkText: Datenschutzerklärung
BackButtonText: zurück
NextButtonText: speichern
RegistrationOrg: RegistrationOrg:
Title: Organisations Registration Title: Organisations Registration
Description: Gib deinen Organisationsnamen und deine Benutzerangaben an. Description: Gib deinen Organisationsnamen und deine Benutzerangaben an.
@ -260,6 +280,11 @@ ExternalNotFoundOption:
Description: Externer Benutzer konnte nicht gefunden werden. Willst du deinen Benutzer mit einem bestehenden verlinken oder diesen als neuen Benutzer registrieren. Description: Externer Benutzer konnte nicht gefunden werden. Willst du deinen Benutzer mit einem bestehenden verlinken oder diesen als neuen Benutzer registrieren.
LinkButtonText: Verlinken LinkButtonText: Verlinken
AutoRegisterButtonText: Automatisches registrieren AutoRegisterButtonText: Automatisches registrieren
TosAndPrivacyLabel: Allgemeine Geschäftsbedingungen und Datenschutz
TosConfirm: Ich akzeptiere die
TosLinkText: AGBs
TosConfirmAnd: und die
PrivacyLinkText: Datenschutzerklärung
Footer: Footer:
PoweredBy: Powered By PoweredBy: Powered By
@ -305,6 +330,8 @@ Errors:
GeneratorAlgNotSupported: Generator Algorithums wird nicht unterstützt GeneratorAlgNotSupported: Generator Algorithums wird nicht unterstützt
EmailVerify: EmailVerify:
UserIDEmpty: UserID ist leer UserIDEmpty: UserID ist leer
ExternalData:
CouldNotRead: Externe Daten konnten nicht korrekt gelesen werden
MFA: MFA:
NoProviders: Es stehen keine Multifaktorprovider zur Verfügung NoProviders: Es stehen keine Multifaktorprovider zur Verfügung
OTP: OTP:
@ -318,6 +345,9 @@ Errors:
ExternalIDP: ExternalIDP:
IDPTypeNotImplemented: IDP Typ ist nicht implementiert IDPTypeNotImplemented: IDP Typ ist nicht implementiert
NotAllowed: Externer Login Provider ist nicht erlaubt NotAllowed: Externer Login Provider ist nicht erlaubt
IDPConfigIDEmpty: Identity Provider ID ist leer
ExternalUserIDEmpty: Externe User ID ist leer
UserDisplayNameEmpty: Benutzer Anzeige Name ist leer
GrantRequired: Der Login an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte melde dich bei deinem Administrator. GrantRequired: Der Login an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte melde dich bei deinem Administrator.
IdentityProvider: IdentityProvider:
InvalidConfig: Identitäts Provider Konfiguration ist ungültig InvalidConfig: Identitäts Provider Konfiguration ist ungültig

View File

@ -221,6 +221,27 @@ RegistrationUser:
BackButtonText: back BackButtonText: back
NextButtonText: next NextButtonText: next
ExternalRegistrationUserOverview:
Title: External User Registration
Description: We have taken your user details from the selected provider. You can now change or complete them.
EmailLabel: E-Mail
UsernameLabel: Username
FirstnameLabel: Firstname
LastnameLabel: Lastname
NicknameLabel: Nickname
PhoneLabel: Phonenumber
LanguageLabel: Language
German: Deutsch
English: English
TosAndPrivacyLabel: Terms and conditions
TosConfirm: I accept the
TosLinkText: TOS
TosConfirmAnd: and the
PrivacyLinkText: privacy policy
ExternalLogin: or register with an external user
BackButtonText: back
NextButtonText: save
RegistrationOrg: RegistrationOrg:
Title: Organisation Registration Title: Organisation Registration
Description: Enter your organisationname and userdata. Description: Enter your organisationname and userdata.
@ -260,6 +281,11 @@ ExternalNotFoundOption:
Description: External user not found. Do you want to link your user or auto register a new one. Description: External user not found. Do you want to link your user or auto register a new one.
LinkButtonText: Link LinkButtonText: Link
AutoRegisterButtonText: Auto register AutoRegisterButtonText: Auto register
TosAndPrivacyLabel: Terms and conditions
TosConfirm: I accept the
TosLinkText: TOS
TosConfirmAnd: and the
PrivacyLinkText: privacy policy
Footer: Footer:
PoweredBy: Powered By PoweredBy: Powered By
@ -305,6 +331,8 @@ Errors:
GeneratorAlgNotSupported: Unsupported generator algorithm GeneratorAlgNotSupported: Unsupported generator algorithm
EmailVerify: EmailVerify:
UserIDEmpty: UserID is empty UserIDEmpty: UserID is empty
ExternalData:
CouldNotRead: External data could not be read correctly
MFA: MFA:
NoProviders: No available multifactor providers NoProviders: No available multifactor providers
OTP: OTP:
@ -318,6 +346,9 @@ Errors:
ExternalIDP: ExternalIDP:
IDPTypeNotImplemented: IDP Type is not implemented IDPTypeNotImplemented: IDP Type is not implemented
NotAllowed: External Login Provider not allowed NotAllowed: External Login Provider not allowed
IDPConfigIDEmpty: Identity Provider ID is empty
ExternalUserIDEmpty: External User ID is empty
UserDisplayNameEmpty: User Display Name is empty
GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator. GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator.
IdentityProvider: IdentityProvider:
InvalidConfig: Identity Provider configuration is invalid InvalidConfig: Identity Provider configuration is invalid

View File

@ -0,0 +1,5 @@
let button1 = document.getElementById("link-button");
disableSubmit(undefined, button1);
let button2 = document.getElementById("auto-register-button");
disableSubmit(undefined, button2);

View File

@ -3,32 +3,65 @@
<div class="lgn-head"> <div class="lgn-head">
<h1>{{t "ExternalNotFoundOption.Title"}}</h1> <h1>{{t "ExternalNotFoundOption.Title"}}</h1>
<p>{{t "ExternalNotFoundOption.Description"}}</p> <p>{{t "ExternalNotFoundOption.Description"}}</p>
</div> </div>
<form action="{{ externalNotFoundOptionUrl }}" method="POST"> <form action="{{ externalNotFoundOptionUrl }}" method="POST">
{{ .CSRF }} {{ .CSRF }}
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" /> <input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<div class="lgn-register">
{{ if or .TOSLink .PrivacyLink }}
<div class="lgn-field">
<label class="lgn-label">{{t "ExternalNotFoundOption.TosAndPrivacyLabel"}}</label>
<div class="lgn-checkbox">
<input type="checkbox" id="register-term-confirmation"
name="register-term-confirmation" required>
<label for="register-term-confirmation">
{{t "ExternalNotFoundOption.TosConfirm"}}
{{ if .TOSLink }}
<a class="tos-link" target="_blank" href="{{ .TOSLink }}" rel="noopener noreferrer">
{{t "ExternalNotFoundOption.TosLinkText"}}
</a>
{{end}}
{{ if and .TOSLink .PrivacyLink }}
{{t "ExternalNotFoundOption.TosConfirmAnd"}}
{{ end }}
{{ if .PrivacyLink }}
<a class="tos-link" target="_blank" href="{{ .PrivacyLink}}" rel="noopener noreferrer">
{{t "ExternalNotFoundOption.PrivacyLinkText"}}
</a>
{{end}}
</label>
</div>
</div>
{{ end }}
</div>
{{template "error-message" .}}
<div class="lgn-actions"> <div class="lgn-actions">
<button class="lgn-icon-button lgn-left-action" name="resetlinking" value="true" <button class="lgn-icon-button lgn-left-action" name="resetlinking" value="true"
formnovalidate> formnovalidate>
<i class="lgn-icon-arrow-left-solid"></i> <i class="lgn-icon-arrow-left-solid"></i>
</button> </button>
<button class="lgn-raised-button lgn-primary" name="link" value="true" <button class="lgn-raised-button lgn-primary" name="link" value="true">
formnovalidate>{{t "ExternalNotFoundOption.LinkButtonText"}}</button> {{t "ExternalNotFoundOption.LinkButtonText"}}
<span class="fill-space"></span> </button>
<button class="lgn-raised-button lgn-primary" name="autoregister" value="true" <span class="fill-space"></span>
formnovalidate>{{t "ExternalNotFoundOption.AutoRegisterButtonText"}}</button> <button class="lgn-raised-button lgn-primary" name="autoregister" value="true">
{{t "ExternalNotFoundOption.AutoRegisterButtonText"}}
</button>
</div> </div>
{{template "error-message" .}} {{template "error-message" .}}
</form> </form>
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script> <script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script> <script src="{{ resourceUrl "scripts/external_not_found_check.js" }}"></script>
{{template "main-bottom" .}} {{template "main-bottom" .}}

View File

@ -0,0 +1,114 @@
{{template "main-top" .}}
<div class="lgn-head">
<h1>{{t "ExternalRegistrationUserOverview.Title"}}</h1>
<p>{{t "ExternalRegistrationUserOverview.Description"}}</p>
</div>
<form action="{{ externalRegistrationUrl }}" method="POST">
{{ .CSRF }}
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
<input type="hidden" id="external-idp-config-id" name="external-idp-config-id" value="{{ .ExternalIDPID }}" />
<input type="hidden" id="external-idp-ext-user-id" name="external-idp-ext-user-id" value="{{ .ExternalIDPUserID }}" />
<input type="hidden" id="external-idp-display-name" name="external-idp-display-name" value="{{ .ExternalIDPUserDisplayName }}" />
<input type="hidden" id="external-email" name="external-email" value="{{ .ExternalEmail }}" />
<input type="hidden" id="external-email-verified" name="external-email-verified" value="{{ .ExternalEmailVerified }}" />
<input type="hidden" id="external-phone" name="external-phone" value="{{ .ExternalPhone }}" />
<input type="hidden" id="external-phone-verified" name="external-phone-verified" value="{{ .ExternalPhoneVerified }}" />
<div class="lgn-register">
<div class="double-col">
<div class="lgn-field">
<label class="lgn-label" for="firstname">{{t "ExternalRegistrationUserOverview.FirstnameLabel"}}</label>
<input class="lgn-input" type="text" id="firstname" name="firstname" autocomplete="given-name"
value="{{ .Firstname }}" autofocus required>
</div>
<div class="lgn-field">
<label class="lgn-label" for="lastname">{{t "ExternalRegistrationUserOverview.LastnameLabel"}}</label>
<input class="lgn-input" type="text" id="lastname" name="lastname" autocomplete="family-name"
value="{{ .Lastname }}" required>
</div>
</div>
<div class="lgn-field double">
<label class="lgn-label" for="email">{{t "ExternalRegistrationUserOverview.EmailLabel"}}</label>
<input class="lgn-input" type="text" id="email" name="email" autocomplete="email" value="{{ .Email }}" required>
</div>
<div class="lgn-field double">
<label class="lgn-label" for="phone">{{t "ExternalRegistrationUserOverview.PhoneLabel"}}</label>
<input class="lgn-input" type="text" id="phone" name="phone" autocomplete="tel" value="{{ .Phone }}">
</div>
{{if .ShowUsername}}
<div class="lgn-field double">
<label class="lgn-label" for="username">{{t "ExternalRegistrationUserOverview.UsernameLabel"}}</label>
<div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required>
{{if .DisplayLoginNameSuffix}}
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
{{end}}
</div>
</div>
{{end}}
<div class="double-col">
<div class="lgn-field">
<label class="lgn-label" for="languages">{{t "ExternalRegistrationUserOverview.LanguageLabel"}}</label>
<select id="languages" name="language">
<option value=""></option>
<option value="de" id="de" {{if (selectedLanguage "de")}} selected {{end}}>{{t "ExternalRegistrationUserOverview.German"}}
</option>
<option value="en" id="en" {{if (selectedLanguage "en")}} selected {{end}}>{{t "ExternalRegistrationUserOverview.English"}}
</option>
</select>
</div>
</div>
{{ if or .TOSLink .PrivacyLink }}
<div class="lgn-field">
<label class="lgn-label">{{t "ExternalRegistrationUserOverview.TosAndPrivacyLabel"}}</label>
<div class="lgn-checkbox">
<input type="checkbox" id="register-term-confirmation"
name="register-term-confirmation" required>
<label for="register-term-confirmation">
{{t "ExternalRegistrationUserOverview.TosConfirm"}}
{{ if .TOSLink }}
<a class="tos-link" target="_blank" href="{{ .TOSLink }}" rel="noopener noreferrer">
{{t "ExternalRegistrationUserOverview.TosLinkText"}}
</a>
{{end}}
{{ if and .TOSLink .PrivacyLink }}
{{t "ExternalRegistrationUserOverview.TosConfirmAnd"}}
{{ end }}
{{ if .PrivacyLink }}
<a class="tos-link" target="_blank" href="{{ .PrivacyLink}}" rel="noopener noreferrer">
{{t "ExternalRegistrationUserOverview.PrivacyLinkText"}}
</a>
{{end}}
</label>
</div>
</div>
{{ end }}
</div>
{{template "error-message" .}}
<div class="lgn-actions">
<a class="lgn-stroked-button lgn-primary" href="{{ registerOptionUrl }}">
{{t "ExternalRegistrationUserOverview.BackButtonText"}}
</a>
<span class="fill-space"></span>
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "ExternalRegistrationUserOverview.NextButtonText"}}</button>
</div>
</form>
<script src="{{ resourceUrl "scripts/input_suffix_offset.js" }}"></script>
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
{{template "main-bottom" .}}

View File

@ -39,7 +39,7 @@
{{if .ShowUsername}} {{if .ShowUsername}}
<div class="lgn-field double"> <div class="lgn-field double">
<label class="lgn-label" for="email">{{t "RegistrationUser.UsernameLabel"}}</label> <label class="lgn-label" for="username">{{t "RegistrationUser.UsernameLabel"}}</label>
<div class="lgn-suffix-wrapper"> <div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required> <input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required>
{{if .DisplayLoginNameSuffix}} {{if .DisplayLoginNameSuffix}}

View File

@ -3393,6 +3393,7 @@ message SetCustomLoginTextsRequest {
zitadel.text.v1.PasswordlessPromptScreenText passwordless_prompt_text = 32; zitadel.text.v1.PasswordlessPromptScreenText passwordless_prompt_text = 32;
zitadel.text.v1.PasswordlessRegistrationScreenText passwordless_registration_text = 33; zitadel.text.v1.PasswordlessRegistrationScreenText passwordless_registration_text = 33;
zitadel.text.v1.PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34; zitadel.text.v1.PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34;
zitadel.text.v1.ExternalRegistrationUserOverviewScreenText external_registration_user_overview_text = 35;
} }
message SetCustomLoginTextsResponse { message SetCustomLoginTextsResponse {

View File

@ -4561,6 +4561,7 @@ message SetCustomLoginTextsRequest {
zitadel.text.v1.PasswordlessPromptScreenText passwordless_prompt_text = 32; zitadel.text.v1.PasswordlessPromptScreenText passwordless_prompt_text = 32;
zitadel.text.v1.PasswordlessRegistrationScreenText passwordless_registration_text = 33; zitadel.text.v1.PasswordlessRegistrationScreenText passwordless_registration_text = 33;
zitadel.text.v1.PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34; zitadel.text.v1.PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34;
zitadel.text.v1.ExternalRegistrationUserOverviewScreenText external_registration_user_overview_text = 35;
} }
message SetCustomLoginTextsResponse { message SetCustomLoginTextsResponse {

View File

@ -82,6 +82,7 @@ message LoginCustomText {
PasswordlessPromptScreenText passwordless_prompt_text = 32; PasswordlessPromptScreenText passwordless_prompt_text = 32;
PasswordlessRegistrationScreenText passwordless_registration_text = 33; PasswordlessRegistrationScreenText passwordless_registration_text = 33;
PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34; PasswordlessRegistrationDoneScreenText passwordless_registration_done_text = 34;
ExternalRegistrationUserOverviewScreenText external_registration_user_overview_text = 35;
} }
message SelectAccountScreenText { message SelectAccountScreenText {
@ -305,6 +306,25 @@ message RegistrationUserScreenText {
string tos_confirm_and = 22 [(validate.rules).string = {max_len: 200}]; string tos_confirm_and = 22 [(validate.rules).string = {max_len: 200}];
} }
message ExternalRegistrationUserOverviewScreenText {
string title = 1 [(validate.rules).string = {max_len: 200}];
string description = 2 [(validate.rules).string = {max_len: 500}];
string email_label = 3 [(validate.rules).string = {max_len: 200}];
string username_label = 4 [(validate.rules).string = {max_len: 200}];
string firstname_label = 5 [(validate.rules).string = {max_len: 200}];
string lastname_label = 6 [(validate.rules).string = {max_len: 200}];
string nickname_label = 7 [(validate.rules).string = {max_len: 200}];
string language_label = 8 [(validate.rules).string = {max_len: 200}];
string phone_label = 9 [(validate.rules).string = {max_len: 200}];
string tos_and_privacy_label = 10 [(validate.rules).string = {max_len: 200}];
string tos_confirm = 11 [(validate.rules).string = {max_len: 200}];
string tos_link_text = 12 [(validate.rules).string = {max_len: 200}];
string tos_confirm_and = 13 [(validate.rules).string = {max_len: 200}];
string privacy_link_text = 14 [(validate.rules).string = {max_len: 200}];
string back_button_text = 15 [(validate.rules).string = {max_len: 200}];
string next_button_text = 16 [(validate.rules).string = {max_len: 200}];
}
message RegistrationOrgScreenText { message RegistrationOrgScreenText {
reserved 13, 15, 16, 18; reserved 13, 15, 16, 18;
reserved "tos_link", "privacy_confirm", "privacy_link", "external_login_description"; reserved "tos_link", "privacy_confirm", "privacy_link", "external_login_description";
@ -337,6 +357,11 @@ message ExternalUserNotFoundScreenText {
string description = 2 [(validate.rules).string = {max_len: 500}]; string description = 2 [(validate.rules).string = {max_len: 500}];
string link_button_text = 3 [(validate.rules).string = {max_len: 100}]; string link_button_text = 3 [(validate.rules).string = {max_len: 100}];
string auto_register_button_text = 4 [(validate.rules).string = {max_len: 100}]; string auto_register_button_text = 4 [(validate.rules).string = {max_len: 100}];
string tos_and_privacy_label = 5 [(validate.rules).string = {max_len: 200}];
string tos_confirm = 6 [(validate.rules).string = {max_len: 200}];
string tos_link_text = 7 [(validate.rules).string = {max_len: 200}];
string privacy_link_text = 8 [(validate.rules).string = {max_len: 200}];
string tos_confirm_and = 9 [(validate.rules).string = {max_len: 200}];
} }
message SuccessLoginScreenText { message SuccessLoginScreenText {
@ -385,4 +410,5 @@ message PasswordlessRegistrationDoneScreenText {
string title = 1 [(validate.rules).string = {max_len: 200}]; string title = 1 [(validate.rules).string = {max_len: 200}];
string description = 2 [(validate.rules).string = {max_len: 500}]; string description = 2 [(validate.rules).string = {max_len: 500}];
string next_button_text = 3 [(validate.rules).string = {max_len: 100}]; string next_button_text = 3 [(validate.rules).string = {max_len: 100}];
string cancel_button_text = 4 [(validate.rules).string = {max_len: 100}];
} }