mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 23:37:23 +00:00
fix(login): allow fallback to local auth in case of IdP errors (#9178)
# Which Problems Are Solved The current login will always prefer external authentication (through an IdP) over local authentication. So as soon as either the user had connected to an IdP or even when the login policy was just set up to have an IdP allowed, users would be redirected to that IdP for (re)authentication. This could lead to problems, where the IdP was not available or any other error occurred in the process (such as secret expired for EntraID). Even when local authentication (passkeys or password) was allowed for the corresponding user, they would always be redirected to the IdP again, preventing any authentication. If admins were affected, they might not even be able to update the client secret of the IdP. # How the Problems Are Solved Errors during the external IdP flow are handled in an `externalAuthFailed` function, which will check if the organisation allows local authentication and if the user has set up such. If either password or passkeys is set up, the corresponding login page will be presented to the user. As already with local auth passkeys is preferred over password authentication. The user is informed that the external login failed and fail back to local auth as an error on the corresponding page in a focused mode. Any interaction or after 5 second the focus mode is disabled. # Additional Changes None. # Additional Context closes #6466
This commit is contained in:
parent
1949d1546a
commit
40082745f4
@ -35,10 +35,6 @@ func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errType, errMessage string
|
||||
if err != nil {
|
||||
errType, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
if authReq == nil || len(authReq.PossibleSteps) < 1 {
|
||||
l.renderError(w, r, authReq, err)
|
||||
@ -50,7 +46,7 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
|
||||
return
|
||||
}
|
||||
data := passwordData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "PasswordChange.Title", "PasswordChange.Description", errType, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "PasswordChange.Title", "PasswordChange.Description", err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
Expired: step.Expired,
|
||||
}
|
||||
@ -75,6 +71,6 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
|
||||
|
||||
func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "PasswordChange.Title", "PasswordChange.Description", "", "")
|
||||
data := l.getUserData(r, authReq, translator, "PasswordChange.Title", "PasswordChange.Description", nil)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangePasswordDone], data, nil)
|
||||
}
|
||||
|
@ -22,13 +22,11 @@ const (
|
||||
)
|
||||
|
||||
func (l *Login) renderDeviceAuthUserCode(w http.ResponseWriter, r *http.Request, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
logging.WithError(err).Error()
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), nil)
|
||||
data := l.getBaseData(r, nil, translator, "DeviceAuth.Title", "DeviceAuth.UserCode.Description", errID, errMessage)
|
||||
data := l.getBaseData(r, nil, translator, "DeviceAuth.Title", "DeviceAuth.UserCode.Description", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplDeviceAuthUserCode], data, nil)
|
||||
}
|
||||
|
||||
@ -41,7 +39,7 @@ func (l *Login) renderDeviceAuthAction(w http.ResponseWriter, r *http.Request, a
|
||||
ClientID string
|
||||
Scopes []string
|
||||
}{
|
||||
baseData: l.getBaseData(r, authReq, translator, "DeviceAuth.Title", "DeviceAuth.Action.Description", "", ""),
|
||||
baseData: l.getBaseData(r, authReq, translator, "DeviceAuth.Title", "DeviceAuth.Action.Description", nil),
|
||||
AuthRequestID: authReq.ID,
|
||||
Username: authReq.UserName,
|
||||
ClientID: authReq.ApplicationID,
|
||||
@ -63,7 +61,7 @@ func (l *Login) renderDeviceAuthDone(w http.ResponseWriter, r *http.Request, aut
|
||||
baseData
|
||||
Message string
|
||||
}{
|
||||
baseData: l.getBaseData(r, authReq, translator, "DeviceAuth.Title", "DeviceAuth.Done.Description", "", ""),
|
||||
baseData: l.getBaseData(r, authReq, translator, "DeviceAuth.Title", "DeviceAuth.Done.Description", nil),
|
||||
}
|
||||
switch action {
|
||||
case deviceAuthAllowed:
|
||||
|
@ -2,8 +2,10 @@ package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/crewjam/saml/samlsp"
|
||||
@ -150,7 +152,7 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
err = l.authRepo.SelectExternalIDP(r.Context(), authReq.ID, identityProvider.ID, userAgentID)
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
l.externalAuthFailed(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
var provider idp.Provider
|
||||
@ -183,17 +185,17 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
case domain.IDPTypeUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
l.renderLogin(w, r, authReq, zerrors.ThrowInvalidArgument(nil, "LOGIN-AShek", "Errors.ExternalIDP.IDPTypeNotImplemented"))
|
||||
l.externalAuthFailed(w, r, authReq, zerrors.ThrowInvalidArgument(nil, "LOGIN-AShek", "Errors.ExternalIDP.IDPTypeNotImplemented"))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
l.externalAuthFailed(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
params := l.sessionParamsFromAuthRequest(r.Context(), authReq, identityProvider.ID)
|
||||
session, err := provider.BeginAuth(r.Context(), authReq.ID, params...)
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
l.externalAuthFailed(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -215,7 +217,7 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
func (l *Login) handleExternalLoginCallbackForm(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, nil, err)
|
||||
l.externalAuthFailed(w, r, nil, err)
|
||||
return
|
||||
}
|
||||
state := r.Form.Get(queryState)
|
||||
@ -223,7 +225,7 @@ func (l *Login) handleExternalLoginCallbackForm(w http.ResponseWriter, r *http.R
|
||||
state = r.Form.Get(queryRelayState)
|
||||
}
|
||||
if state == "" {
|
||||
l.renderLogin(w, r, nil, zerrors.ThrowInvalidArgument(nil, "LOGIN-dsg3f", "Errors.AuthRequest.NotFound"))
|
||||
l.externalAuthFailed(w, r, nil, zerrors.ThrowInvalidArgument(nil, "LOGIN-dsg3f", "Errors.AuthRequest.NotFound"))
|
||||
return
|
||||
}
|
||||
l.caches.idpFormCallbacks.Set(r.Context(), &idpFormCallback{
|
||||
@ -243,7 +245,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
// workaround because of CSRF on external identity provider flows using form_post
|
||||
if r.URL.Query().Get(queryMethod) == http.MethodPost {
|
||||
if err := l.setDataFromFormCallback(r, r.URL.Query().Get(queryState)); err != nil {
|
||||
l.renderLogin(w, r, nil, err)
|
||||
l.externalAuthFailed(w, r, nil, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -251,7 +253,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
data := new(externalIDPCallbackData)
|
||||
err := l.getParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, nil, err)
|
||||
l.externalAuthFailed(w, r, nil, err)
|
||||
return
|
||||
}
|
||||
if data.State == "" {
|
||||
@ -261,12 +263,12 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
authReq, err := l.authRepo.AuthRequestByID(r.Context(), data.State, userAgentID)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
identityProvider, err := l.getIDPByID(r, authReq.SelectedIDPConfigID)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
var provider idp.Provider
|
||||
@ -275,75 +277,75 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
case domain.IDPTypeOAuth:
|
||||
provider, err = l.oauthProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &oauth.Session{Provider: provider.(*oauth.Provider), Code: data.Code}
|
||||
case domain.IDPTypeOIDC:
|
||||
provider, err = l.oidcProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &openid.Session{Provider: provider.(*openid.Provider), Code: data.Code}
|
||||
case domain.IDPTypeAzureAD:
|
||||
provider, err = l.azureProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &azuread.Session{Provider: provider.(*azuread.Provider), Code: data.Code}
|
||||
case domain.IDPTypeGitHub:
|
||||
provider, err = l.githubProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &oauth.Session{Provider: provider.(*github.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeGitHubEnterprise:
|
||||
provider, err = l.githubEnterpriseProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &oauth.Session{Provider: provider.(*github.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeGitLab:
|
||||
provider, err = l.gitlabProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &openid.Session{Provider: provider.(*gitlab.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeGitLabSelfHosted:
|
||||
provider, err = l.gitlabSelfHostedProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &openid.Session{Provider: provider.(*gitlab.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeGoogle:
|
||||
provider, err = l.googleProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &openid.Session{Provider: provider.(*google.Provider).Provider, Code: data.Code}
|
||||
case domain.IDPTypeApple:
|
||||
provider, err = l.appleProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session = &apple.Session{Session: &openid.Session{Provider: provider.(*apple.Provider).Provider, Code: data.Code}, UserFormValue: data.User}
|
||||
case domain.IDPTypeSAML:
|
||||
provider, err = l.samlProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
session, err = saml.NewSession(provider.(*saml.Provider), authReq.SAMLRequestID, r)
|
||||
if err != nil {
|
||||
l.externalAuthFailed(w, r, authReq, nil, nil, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, nil, nil, err)
|
||||
return
|
||||
}
|
||||
case domain.IDPTypeJWT,
|
||||
@ -351,7 +353,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
domain.IDPTypeUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
l.renderLogin(w, r, authReq, zerrors.ThrowInvalidArgument(nil, "LOGIN-SFefg", "Errors.ExternalIDP.IDPTypeNotImplemented"))
|
||||
l.externalAuthFailed(w, r, authReq, zerrors.ThrowInvalidArgument(nil, "LOGIN-SFefg", "Errors.ExternalIDP.IDPTypeNotImplemented"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -361,7 +363,7 @@ func (l *Login) handleExternalLoginCallback(w http.ResponseWriter, r *http.Reque
|
||||
"instance", authz.GetInstance(r.Context()).InstanceID(),
|
||||
"providerID", identityProvider.ID,
|
||||
).WithError(err).Info("external authentication failed")
|
||||
l.externalAuthFailed(w, r, authReq, tokens(session), user, err)
|
||||
l.externalAuthCallbackFailed(w, r, authReq, tokens(session), user, err)
|
||||
return
|
||||
}
|
||||
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
||||
@ -619,10 +621,6 @@ func (l *Login) autoCreateExternalUser(w http.ResponseWriter, r *http.Request, a
|
||||
// renderExternalNotFoundOption renders a page, where the user is able to edit the IDP data,
|
||||
// create a new externalUser of link to existing on (based on the IDP template)
|
||||
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.DomainPolicy, human *domain.Human, idpLink *domain.UserIDPLink, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
resourceOwner := determineResourceOwner(r.Context(), authReq)
|
||||
if orgIAMPolicy == nil {
|
||||
orgIAMPolicy, err = l.getOrgDomainPolicy(r, resourceOwner)
|
||||
@ -656,7 +654,7 @@ func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Requ
|
||||
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := externalNotFoundOptionData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "ExternalNotFound.Title", "ExternalNotFound.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "ExternalNotFound.Title", "ExternalNotFound.Description", err),
|
||||
externalNotFoundOptionFormData: externalNotFoundOptionFormData{
|
||||
externalRegisterFormData: externalRegisterFormData{
|
||||
Email: human.EmailAddress,
|
||||
@ -1215,7 +1213,7 @@ func (l *Login) appendUserGrants(ctx context.Context, userGrants []*domain.UserG
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens[*oidc.IDTokenClaims], user idp.User, err error) {
|
||||
func (l *Login) externalAuthCallbackFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, tokens *oidc.Tokens[*oidc.IDTokenClaims], user idp.User, err error) {
|
||||
if authReq == nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
@ -1223,7 +1221,37 @@ func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authR
|
||||
if _, _, actionErr := l.runPostExternalAuthenticationActions(&domain.ExternalUser{}, tokens, authReq, r, user, err); actionErr != nil {
|
||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||
}
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
l.externalAuthFailed(w, r, authReq, err)
|
||||
}
|
||||
|
||||
func (l *Login) externalAuthFailed(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
if authReq == nil || authReq.LoginPolicy == nil || !authReq.LoginPolicy.AllowUsernamePassword || authReq.UserID == "" {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
authMethods, authMethodsError := l.query.ListUserAuthMethodTypes(setUserContext(r.Context(), authReq.UserID, ""), authReq.UserID, true, false, "")
|
||||
if authMethodsError != nil {
|
||||
logging.WithFields("userID", authReq.UserID).WithError(authMethodsError).Warn("unable to load user's auth methods for idp login error")
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
passwordless := slices.Contains(authMethods.AuthMethodTypes, domain.UserAuthMethodTypePasswordless)
|
||||
password := slices.Contains(authMethods.AuthMethodTypes, domain.UserAuthMethodTypePassword)
|
||||
if !passwordless && !password {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
localAuthError := l.authRepo.RequestLocalAuth(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.AgentID)
|
||||
if localAuthError != nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
err = WrapIdPError(err)
|
||||
if passwordless {
|
||||
l.renderPasswordlessVerification(w, r, authReq, password, err)
|
||||
return
|
||||
}
|
||||
l.renderPassword(w, r, authReq, err)
|
||||
}
|
||||
|
||||
// tokens extracts the oidc.Tokens for backwards compatibility of PostExternalAuthenticationActions
|
||||
@ -1359,3 +1387,34 @@ func (l *Login) getUserLinks(ctx context.Context, userID, idpID string) (*query.
|
||||
}, nil,
|
||||
)
|
||||
}
|
||||
|
||||
// IdPError wraps an error from an external IDP to be able to distinguish it from other errors and to display it
|
||||
// more prominent (popup style) .
|
||||
// It's used if an error occurs during the login process with an external IDP and local authentication is allowed,
|
||||
// respectively used as fallback.
|
||||
type IdPError struct {
|
||||
err *zerrors.ZitadelError
|
||||
}
|
||||
|
||||
func (e *IdPError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *IdPError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *IdPError) Is(target error) bool {
|
||||
_, ok := target.(*IdPError)
|
||||
return ok
|
||||
}
|
||||
|
||||
func WrapIdPError(err error) *IdPError {
|
||||
zErr := new(zerrors.ZitadelError)
|
||||
id := "LOGIN-JWo3f"
|
||||
// keep the original error id if there is one
|
||||
if errors.As(err, &zErr) {
|
||||
id = zErr.ID
|
||||
}
|
||||
return &IdPError{err: zerrors.CreateZitadelError(err, id, "Errors.User.ExternalIDP.LoginFailedSwitchLocal")}
|
||||
}
|
||||
|
@ -112,10 +112,6 @@ func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authRe
|
||||
}
|
||||
|
||||
func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, code string, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if userID == "" && authReq != nil {
|
||||
userID = authReq.UserID
|
||||
}
|
||||
@ -123,7 +119,7 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
|
||||
data := initPasswordData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitPassword.Title", "InitPassword.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitPassword.Title", "InitPassword.Description", err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
UserID: userID,
|
||||
Code: code,
|
||||
@ -155,7 +151,7 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR
|
||||
|
||||
func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string) {
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "InitPasswordDone.Title", "InitPasswordDone.Description", "", "")
|
||||
data := l.getUserData(r, authReq, translator, "InitPasswordDone.Title", "InitPasswordDone.Description", nil)
|
||||
if authReq == nil {
|
||||
l.customTexts(r.Context(), translator, orgID)
|
||||
}
|
||||
|
@ -131,17 +131,13 @@ func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *
|
||||
}
|
||||
|
||||
func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, loginName string, code string, passwordSet bool, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if authReq != nil {
|
||||
userID = authReq.UserID
|
||||
}
|
||||
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := initUserData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitUser.Title", "InitUser.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitUser.Title", "InitUser.Description", err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
UserID: userID,
|
||||
Code: code,
|
||||
@ -179,7 +175,7 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *
|
||||
|
||||
func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string) {
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "InitUserDone.Title", "InitUserDone.Description", "", "")
|
||||
data := l.getUserData(r, authReq, translator, "InitUserDone.Title", "InitUserDone.Description", nil)
|
||||
if authReq == nil {
|
||||
l.customTexts(r.Context(), translator, orgID)
|
||||
}
|
||||
|
@ -119,10 +119,6 @@ func (l *Login) resendUserInvite(w http.ResponseWriter, r *http.Request, authReq
|
||||
}
|
||||
|
||||
func (l *Login) renderInviteUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, orgID, loginName string, code string, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if authReq != nil {
|
||||
userID = authReq.UserID
|
||||
orgID = authReq.UserOrgID
|
||||
@ -130,7 +126,7 @@ func (l *Login) renderInviteUser(w http.ResponseWriter, r *http.Request, authReq
|
||||
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := inviteUserData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "InviteUser.Title", "InviteUser.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "InviteUser.Title", "InviteUser.Description", err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
UserID: userID,
|
||||
Code: code,
|
||||
|
@ -30,13 +30,9 @@ func (l *Login) handleLDAP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderLDAPLogin(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
temp := l.renderer.Templates[tmplLDAPLogin]
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "Login.Title", "Login.Description", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "Login.Title", "Login.Description", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, temp, data, nil)
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,7 @@ func (l *Login) linkUsers(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
}
|
||||
|
||||
func (l *Login) renderLinkUsersDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errType, errMessage string
|
||||
if err != nil {
|
||||
errType, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "LinkingUsersDone.Title", "LinkingUsersDone.Description", errType, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "LinkingUsersDone.Title", "LinkingUsersDone.Description", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplLinkUsersDone], data, nil)
|
||||
}
|
||||
|
@ -91,16 +91,12 @@ func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if err == nil && singleIDPAllowed(authReq) {
|
||||
l.handleIDP(w, r, authReq, authReq.AllowedExternalIDPs[0].IDPConfigID)
|
||||
return
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "Login.Title", "Login.Description", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "Login.Title", "Login.Description", err)
|
||||
funcs := map[string]interface{}{
|
||||
"hasUsernamePasswordLogin": func() bool {
|
||||
return authReq != nil && authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowUsernamePassword
|
||||
|
@ -37,13 +37,9 @@ func (l *Login) handleLoginSuccess(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderSuccessAndCallback(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := loginSuccessData{
|
||||
userData: l.getUserData(r, authReq, translator, "LoginSuccess.Title", "", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "LoginSuccess.Title", "", err),
|
||||
}
|
||||
if authReq != nil {
|
||||
data.RedirectURI, err = l.authRequestCallback(r.Context(), authReq)
|
||||
|
@ -14,6 +14,6 @@ func (l *Login) handleLogoutDone(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (l *Login) renderLogoutDone(w http.ResponseWriter, r *http.Request) {
|
||||
translator := l.getTranslator(r.Context(), nil)
|
||||
data := l.getUserData(r, nil, translator, "LogoutDone.Title", "LogoutDone.Description", "", "")
|
||||
data := l.getUserData(r, nil, translator, "LogoutDone.Title", "LogoutDone.Description", nil)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplLogoutDone], data, nil)
|
||||
}
|
||||
|
@ -145,17 +145,13 @@ func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *d
|
||||
}
|
||||
|
||||
func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, code string, passwordInit bool, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if userID == "" && authReq != nil {
|
||||
userID = authReq.UserID
|
||||
}
|
||||
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := mailVerificationData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "EmailVerification.Title", "EmailVerification.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "EmailVerification.Title", "EmailVerification.Description", err),
|
||||
UserID: userID,
|
||||
profileData: l.getProfileData(authReq),
|
||||
Code: code,
|
||||
@ -191,7 +187,7 @@ func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, a
|
||||
func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string) {
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := mailVerificationData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "EmailVerificationDone.Title", "EmailVerificationDone.Description", "", ""),
|
||||
baseData: l.getBaseData(r, authReq, translator, "EmailVerificationDone.Title", "EmailVerificationDone.Description", nil),
|
||||
profileData: l.getProfileData(authReq),
|
||||
}
|
||||
if authReq == nil {
|
||||
|
@ -14,9 +14,8 @@ type mfaInitDoneData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaDoneData) {
|
||||
var errType, errMessage string
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFADone.Title", "InitMFADone.Description", errType, errMessage)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFADone.Title", "InitMFADone.Description", nil)
|
||||
data.profileData = l.getProfileData(authReq)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFAInitDone], data, nil)
|
||||
}
|
||||
|
@ -53,12 +53,8 @@ func (l *Login) handleRegisterOTPSMS(w http.ResponseWriter, r *http.Request, aut
|
||||
}
|
||||
|
||||
func (l *Login) renderRegisterSMS(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *smsInitData, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFAOTP.Title", "InitMFAOTP.Description", errID, errMessage)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFAOTP.Title", "InitMFAOTP.Description", err)
|
||||
data.profileData = l.getProfileData(authReq)
|
||||
data.MFAType = domain.MFATypeOTPSMS
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplMFASMSInit], data, nil)
|
||||
|
@ -18,21 +18,18 @@ type u2fInitData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage, credentialData string
|
||||
var credentialData string
|
||||
var u2f *domain.WebAuthNToken
|
||||
if err == nil {
|
||||
u2f, err = l.command.HumanAddU2FSetup(setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID), authReq.UserID, authReq.UserOrgID)
|
||||
}
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if u2f != nil {
|
||||
credentialData = base64.RawURLEncoding.EncodeToString(u2f.CredentialCreationData)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &u2fInitData{
|
||||
webAuthNData: webAuthNData{
|
||||
userData: l.getUserData(r, authReq, translator, "InitMFAU2F.Title", "InitMFAU2F.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "InitMFAU2F.Title", "InitMFAU2F.Description", err),
|
||||
CredentialCreationData: credentialData,
|
||||
},
|
||||
MFAType: domain.MFATypeU2F,
|
||||
|
@ -66,12 +66,8 @@ func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq
|
||||
}
|
||||
|
||||
func (l *Login) renderMFAInitVerify(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *mfaVerifyData, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFAOTP.Title", "InitMFAOTP.Description", errID, errMessage)
|
||||
data.baseData = l.getBaseData(r, authReq, translator, "InitMFAOTP.Title", "InitMFAOTP.Description", err)
|
||||
data.profileData = l.getProfileData(authReq)
|
||||
if data.MFAType == domain.MFATypeTOTP {
|
||||
code, err := generateQrCode(data.totpData.Url)
|
||||
|
@ -49,13 +49,9 @@ func (l *Login) handleMFAPromptSelection(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, mfaPromptData *domain.MFAPromptStep, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := mfaData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitMFAPrompt.Title", "InitMFAPrompt.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "InitMFAPrompt.Title", "InitMFAPrompt.Description", err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
}
|
||||
|
||||
|
@ -62,12 +62,8 @@ func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq
|
||||
}
|
||||
|
||||
func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, verificationStep *domain.MFAVerificationStep, selectedProvider domain.MFAType, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "", "", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "", "", err)
|
||||
if verificationStep == nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
|
@ -61,13 +61,9 @@ func (l *Login) handleOTPVerification(w http.ResponseWriter, r *http.Request, au
|
||||
}
|
||||
|
||||
func (l *Login) renderOTPVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, selectedProvider domain.MFAType, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &mfaOTPData{
|
||||
userData: l.getUserData(r, authReq, translator, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", err),
|
||||
MFAProviders: removeSelectedProviderFromList(providers, selectedProvider),
|
||||
SelectedProvider: selectedProvider,
|
||||
}
|
||||
|
@ -24,22 +24,19 @@ type mfaU2FFormData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, err error) {
|
||||
var errID, errMessage, credentialData string
|
||||
var credentialData string
|
||||
var webAuthNLogin *domain.WebAuthNLogin
|
||||
if err == nil {
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
webAuthNLogin, err = l.authRepo.BeginMFAU2FLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID)
|
||||
}
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if webAuthNLogin != nil {
|
||||
credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &mfaU2FData{
|
||||
webAuthNData: webAuthNData{
|
||||
userData: l.getUserData(r, authReq, translator, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", err),
|
||||
CredentialCreationData: credentialData,
|
||||
},
|
||||
MFAProviders: providers,
|
||||
|
@ -15,12 +15,8 @@ type passwordFormData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "Password.Title", "Password.Description", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "Password.Title", "Password.Description", err)
|
||||
funcs := map[string]interface{}{
|
||||
"showPasswordReset": func() bool {
|
||||
if authReq.LoginPolicy != nil {
|
||||
|
@ -30,11 +30,7 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "PasswordResetDone.Title", "PasswordResetDone.Description", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "PasswordResetDone.Title", "PasswordResetDone.Description", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplPasswordResetDone], data, nil)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package login
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -22,13 +23,15 @@ type passwordlessFormData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, passwordSet bool, err error) {
|
||||
var errID, errMessage, credentialData string
|
||||
var credentialData string
|
||||
var webAuthNLogin *domain.WebAuthNLogin
|
||||
if err == nil {
|
||||
webAuthNLogin, err = l.authRepo.BeginPasswordlessLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, authReq.AgentID)
|
||||
}
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
if err == nil || errors.Is(err, &IdPError{}) { // make sure we still proceed with the webauthn login even if the idp login failed
|
||||
var creationErr error
|
||||
webAuthNLogin, creationErr = l.authRepo.BeginPasswordlessLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, authReq.AgentID)
|
||||
// and only overwrite the error if the webauthn creation failed
|
||||
if creationErr != nil {
|
||||
err = creationErr
|
||||
}
|
||||
}
|
||||
if webAuthNLogin != nil {
|
||||
credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
|
||||
@ -39,7 +42,7 @@ func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Re
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &passwordlessData{
|
||||
webAuthNData{
|
||||
userData: l.getUserData(r, authReq, translator, "Passwordless.Title", "Passwordless.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "Passwordless.Title", "Passwordless.Description", err),
|
||||
CredentialCreationData: credentialData,
|
||||
},
|
||||
passwordSet,
|
||||
|
@ -27,13 +27,9 @@ func (l *Login) handlePasswordlessPrompt(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func (l *Login) renderPasswordlessPrompt(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &passwordlessPromptData{
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessPrompt.Title", "PasswordlessPrompt.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessPrompt.Title", "PasswordlessPrompt.Description", err),
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplPasswordlessPrompt], data, nil)
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ func (l *Login) handlePasswordlessRegistration(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
|
||||
func (l *Login) renderPasswordlessRegistration(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, orgID, codeID, code string, requestedPlatformType authPlatform, err error) {
|
||||
var errID, errMessage, credentialData string
|
||||
var credentialData string
|
||||
var disabled bool
|
||||
if authReq != nil {
|
||||
userID = authReq.UserID
|
||||
@ -93,7 +93,6 @@ func (l *Login) renderPasswordlessRegistration(w http.ResponseWriter, r *http.Re
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
disabled = true
|
||||
}
|
||||
if webAuthNToken != nil {
|
||||
@ -102,7 +101,7 @@ func (l *Login) renderPasswordlessRegistration(w http.ResponseWriter, r *http.Re
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := &passwordlessRegistrationData{
|
||||
webAuthNData{
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessRegistration.Title", "PasswordlessRegistration.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessRegistration.Title", "PasswordlessRegistration.Description", err),
|
||||
CredentialCreationData: credentialData,
|
||||
},
|
||||
code,
|
||||
@ -185,13 +184,9 @@ func (l *Login) checkPasswordlessRegistration(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
func (l *Login) renderPasswordlessRegistrationDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgID string, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := passwordlessRegistrationDoneDate{
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessRegistrationDone.Title", "PasswordlessRegistrationDone.Description", errID, errMessage),
|
||||
userData: l.getUserData(r, authReq, translator, "PasswordlessRegistrationDone.Title", "PasswordlessRegistrationDone.Description", err),
|
||||
HideNextButton: authReq == nil,
|
||||
}
|
||||
if authReq == nil {
|
||||
|
@ -142,10 +142,6 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authRequest *domain.AuthRequest, formData *registerFormData, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authRequest)
|
||||
if formData == nil {
|
||||
formData = new(registerFormData)
|
||||
@ -156,7 +152,7 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
|
||||
|
||||
resourceOwner := determineResourceOwner(r.Context(), authRequest)
|
||||
data := registerData{
|
||||
baseData: l.getBaseData(r, authRequest, translator, "RegistrationUser.Title", "RegistrationUser.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authRequest, translator, "RegistrationUser.Title", "RegistrationUser.Description", err),
|
||||
registerFormData: *formData,
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,6 @@ func (l *Login) handleRegisterOption(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
allowed := registrationAllowed(authReq)
|
||||
externalAllowed := externalRegistrationAllowed(authReq)
|
||||
if err == nil {
|
||||
@ -54,7 +50,7 @@ func (l *Login) renderRegisterOption(w http.ResponseWriter, r *http.Request, aut
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := registerOptionData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "RegisterOption.Title", "RegisterOption.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, "RegisterOption.Title", "RegisterOption.Description", err),
|
||||
}
|
||||
funcs := map[string]interface{}{
|
||||
"hasRegistration": func() bool {
|
||||
|
@ -97,16 +97,12 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderRegisterOrg(w http.ResponseWriter, r *http.Request, authRequest *domain.AuthRequest, formData *registerOrgFormData, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if formData == nil {
|
||||
formData = new(registerOrgFormData)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authRequest)
|
||||
data := registerOrgData{
|
||||
baseData: l.getBaseData(r, authRequest, translator, "RegistrationOrg.Title", "RegistrationOrg.Description", errID, errMessage),
|
||||
baseData: l.getBaseData(r, authRequest, translator, "RegistrationOrg.Title", "RegistrationOrg.Description", err),
|
||||
registerOrgFormData: *formData,
|
||||
}
|
||||
pwPolicy := l.getPasswordComplexityPolicy(r, "0")
|
||||
|
@ -341,7 +341,6 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
|
||||
}
|
||||
|
||||
func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var msg string
|
||||
if err != nil {
|
||||
log := logging.WithError(err)
|
||||
if authReq != nil {
|
||||
@ -352,17 +351,15 @@ func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, auth
|
||||
} else {
|
||||
log.Info()
|
||||
}
|
||||
|
||||
_, msg = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getBaseData(r, authReq, translator, "Errors.Internal", "", "Internal", msg)
|
||||
data := l.getBaseData(r, authReq, translator, "Errors.Internal", "", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplError], data, nil)
|
||||
}
|
||||
|
||||
func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, translator *i18n.Translator, titleI18nKey string, descriptionI18nKey string, errType, errMessage string) userData {
|
||||
func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, translator *i18n.Translator, titleI18nKey string, descriptionI18nKey string, err error) userData {
|
||||
userData := userData{
|
||||
baseData: l.getBaseData(r, authReq, translator, titleI18nKey, descriptionI18nKey, errType, errMessage),
|
||||
baseData: l.getBaseData(r, authReq, translator, titleI18nKey, descriptionI18nKey, err),
|
||||
profileData: l.getProfileData(authReq),
|
||||
}
|
||||
if authReq != nil && authReq.LinkingUsers != nil {
|
||||
@ -371,7 +368,7 @@ func (l *Login) getUserData(r *http.Request, authReq *domain.AuthRequest, transl
|
||||
return userData
|
||||
}
|
||||
|
||||
func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, translator *i18n.Translator, titleI18nKey string, descriptionI18nKey string, errType, errMessage string) baseData {
|
||||
func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, translator *i18n.Translator, titleI18nKey string, descriptionI18nKey string, err error) baseData {
|
||||
title := ""
|
||||
if titleI18nKey != "" {
|
||||
title = translator.LocalizeWithoutArgs(titleI18nKey)
|
||||
@ -383,10 +380,16 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, transl
|
||||
}
|
||||
|
||||
lang, _ := l.renderer.ReqLang(translator, r).Base()
|
||||
var errID, errMessage string
|
||||
var errPopup bool
|
||||
if err != nil {
|
||||
errID, errMessage, errPopup = l.getErrorMessage(r, err)
|
||||
}
|
||||
baseData := baseData{
|
||||
errorData: errorData{
|
||||
ErrID: errType,
|
||||
ErrID: errID,
|
||||
ErrMessage: errMessage,
|
||||
ErrPopup: errPopup,
|
||||
},
|
||||
Lang: lang.String(),
|
||||
Title: title,
|
||||
@ -482,14 +485,17 @@ func (l *Login) setLinksOnBaseData(baseData baseData, privacyPolicy *domain.Priv
|
||||
return baseData
|
||||
}
|
||||
|
||||
func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string) {
|
||||
func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg string, popup bool) {
|
||||
idpErr := new(IdPError)
|
||||
if errors.Is(err, idpErr) {
|
||||
popup = true
|
||||
}
|
||||
caosErr := new(zerrors.ZitadelError)
|
||||
if errors.As(err, &caosErr) {
|
||||
localized := l.renderer.LocalizeFromRequest(l.getTranslator(r.Context(), nil), r, caosErr.Message, nil)
|
||||
return caosErr.ID, localized
|
||||
|
||||
localized := l.renderer.LocalizeFromRequest(l.getTranslator(r.Context(), nil), r, caosErr.Message, map[string]interface{}{"Details": caosErr.Parent})
|
||||
return caosErr.ID, localized, popup
|
||||
}
|
||||
return "", err.Error()
|
||||
return "", err.Error(), popup
|
||||
}
|
||||
|
||||
func (l *Login) getTheme(r *http.Request) string {
|
||||
@ -662,6 +668,7 @@ type baseData struct {
|
||||
type errorData struct {
|
||||
ErrID string
|
||||
ErrMessage string
|
||||
ErrPopup bool
|
||||
}
|
||||
|
||||
type userData struct {
|
||||
|
@ -27,7 +27,7 @@ func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, auth
|
||||
descriptionI18nKey = "SelectAccount.DescriptionLinking"
|
||||
}
|
||||
data := userSelectionData{
|
||||
baseData: l.getBaseData(r, authReq, translator, titleI18nKey, descriptionI18nKey, "", ""),
|
||||
baseData: l.getBaseData(r, authReq, translator, titleI18nKey, descriptionI18nKey, nil),
|
||||
Users: selectionData.Users,
|
||||
Linking: linking,
|
||||
}
|
||||
|
@ -493,6 +493,10 @@ Errors:
|
||||
CreationNotAllowed: Създаването на нов потребител не е разрешено на този доставчик
|
||||
LinkingNotAllowed: Свързването на потребител не е разрешено на този доставчик
|
||||
NoOptionAllowed: Нито създаване, нито свързване е разрешено за този доставчик. Моля, свържете се с администратора.
|
||||
LoginFailedSwitchLocal: |
|
||||
Вход в външен доставчик на идентификация е неуспешен. Връщане към локален вход.
|
||||
|
||||
Подробности за грешката: {{.Details}}
|
||||
GrantRequired: 'Влизането не е възможно. '
|
||||
ProjectRequired: 'Влизането не е възможно. '
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: Vytvoření nového uživatele není na tomto poskytovateli povoleno
|
||||
LinkingNotAllowed: Propojení uživatele není na tomto poskytovateli povoleno
|
||||
NoOptionAllowed: Ani vytvoření, ani propojení není povoleno pro tohoto poskytovatele. Obraťte se na svého správce.
|
||||
LoginFailedSwitchLocal: |
|
||||
Přihlášení u externího poskytovatele identit selhalo. Vracíme se k místnímu přihlášení.
|
||||
|
||||
Podrobnosti o chybě: {{.Details}}
|
||||
GrantRequired: Přihlášení není možné. Uživatel musí mít alespoň jeden oprávnění na aplikaci. Prosím, kontaktujte svého správce.
|
||||
ProjectRequired: Přihlášení není možné. Organizace uživatele musí být přidělena k projektu. Prosím, kontaktujte svého správce.
|
||||
IdentityProvider:
|
||||
|
@ -504,6 +504,10 @@ Errors:
|
||||
CreationNotAllowed: Erstellen eines neuen Benutzers mit diesem Provider ist nicht erlaubt
|
||||
LinkingNotAllowed: Verknüpfen eines Benutzers mit diesem Provider ist nicht erlaubt
|
||||
NoOptionAllowed: Weder Erstellung noch Verknüpfung ist für diesen Provider erlaubt. Bitte wenden Sie sich an Ihren Administrator.
|
||||
LoginFailedSwitchLocal: |
|
||||
Anmeldung beim externen Identitätsanbieter fehlgeschlagen. Zurück zur lokalen Anmeldung.
|
||||
|
||||
Fehlerdetails: {{.Details}}
|
||||
GrantRequired: Die Anmeldung an diese Applikation ist nicht möglich. Der Benutzer benötigt mindestens eine Berechtigung an der Applikation. Bitte wende dich an deinen Administrator.
|
||||
ProjectRequired: Die Anmeldung an dieser Applikation ist nicht möglich. Die Organisation des Benutzer benötigt Berechtigung auf das Projekt. Bitte wende dich an deinen Administrator.
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: Creation of a new user is not allowed on this provider
|
||||
LinkingNotAllowed: Linking of a user is not allowed on this provider
|
||||
NoOptionAllowed: Neither creation of linking is allowed on this provider. Please contact your administrator.
|
||||
LoginFailedSwitchLocal: |
|
||||
Login at External IDP failed. Falling back to local login.
|
||||
|
||||
Error details: {{.Details}}
|
||||
GrantRequired: Login not possible. The user is required to have at least one grant on the application. Please contact your administrator.
|
||||
ProjectRequired: Login not possible. The organization of the user must be granted to the project. Please contact your administrator.
|
||||
IdentityProvider:
|
||||
|
@ -488,6 +488,10 @@ Errors:
|
||||
CreationNotAllowed: La creación de un nuevo usuario no está permitida para este proveedor
|
||||
LinkingNotAllowed: La vinculación de un usuario no está permitida para este proveedor
|
||||
NoOptionAllowed: Ni la creación ni la vinculación están permitidas en este proveedor. Póngase en contacto con su administrador.
|
||||
LoginFailedSwitchLocal: |
|
||||
Error al iniciar sesión en el proveedor de identidad externo. Volviendo al inicio de sesión local.
|
||||
|
||||
Detalles del error: {{.Details}}
|
||||
GrantRequired: El inicio de sesión no es posible. Se requiere que el usuario tenga al menos una concesión sobre la aplicación. Por favor contacta con tu administrador.
|
||||
ProjectRequired: El inicio de sesión no es posible. La organización del usuario debe tener el acceso concedido para el proyecto. Por favor contacta con tu administrador.
|
||||
IdentityProvider:
|
||||
|
@ -506,6 +506,10 @@ Errors:
|
||||
CreationNotAllowed: La création d'un nouvel utilisateur n'est pas autorisée sur ce fournisseur.
|
||||
LinkingNotAllowed: La création d'un lien vers un utilisateur n'est pas autorisée pour ce fournisseur.
|
||||
NoOptionAllowed: Ni la création ni la liaison sont autorisées pour ce fournisseur. Veuillez contacter votre administrateur.
|
||||
LoginFailedSwitchLocal: |
|
||||
Échec de la connexion au fournisseur d'identité externe. Retour à la connexion locale.
|
||||
|
||||
Détails de l'erreur: {{.Details}}
|
||||
GrantRequired: Connexion impossible. L'utilisateur doit avoir au moins une subvention sur l'application. Veuillez contacter votre administrateur.
|
||||
ProjectRequired: Connexion impossible. L'organisation de l'utilisateur doit être accordée au projet. Veuillez contacter votre administrateur.
|
||||
IdentityProvider:
|
||||
|
@ -465,6 +465,10 @@ Errors:
|
||||
CreationNotAllowed: Új felhasználó létrehozása nem engedélyezett ezen a szolgáltatón
|
||||
LinkingNotAllowed: A felhasználó összekapcsolása nem engedélyezett ezen a szolgáltatón
|
||||
NoOptionAllowed: Sem új felhasználó létrehozása, sem összekapcsolás nem engedélyezett ezen a szolgáltatón. Kérjük, lépj kapcsolatba az adminisztrátoroddal.
|
||||
LoginFailedSwitchLocal: |
|
||||
Az egyéni azonosító szolgáltatóhoz való bejelentkezés sikertelen volt. Visszatérés a helyi bejelentkezéshez.
|
||||
|
||||
Hiba részletei: {{.Details}}
|
||||
GrantRequired: Bejelentkezés nem lehetséges. A felhasználónak legalább egy jogosultsággal kell rendelkeznie az alkalmazáson. Kérlek, lépj kapcsolatba az adminisztrátoroddal.
|
||||
ProjectRequired: Bejelentkezés nem lehetséges. A felhasználó szervezetének engedélyezve kell lennie a projektre. Kérlek, lépj kapcsolatba az adminisztrátoroddal.
|
||||
IdentityProvider:
|
||||
|
@ -464,6 +464,10 @@ Errors:
|
||||
CreationNotAllowed: Pembuatan pengguna baru tidak diperbolehkan pada penyedia ini
|
||||
LinkingNotAllowed: Menautkan pengguna tidak diperbolehkan di penyedia ini
|
||||
NoOptionAllowed: 'Pembuatan tautan tidak diperbolehkan pada penyedia ini. '
|
||||
LoginFailedSwitchLocal: |
|
||||
Gagal masuk ke Penyedia ID Eksternal. Kembali ke login lokal.
|
||||
|
||||
Detail kesalahan: {{.Details}}
|
||||
GrantRequired: 'Masuk tidak dapat dilakukan. '
|
||||
ProjectRequired: 'Masuk tidak dapat dilakukan. '
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: La creazione di un nuovo utente non è consentita su questo provider.
|
||||
LinkingNotAllowed: Il collegamento di un utente non è consentito su questo provider.
|
||||
NoOptionAllowed: Né la creazione né il collegamento sono consentiti per questo provider. Contattare l'amministratore.
|
||||
LoginFailedSwitchLocal: |
|
||||
Accesso al provider di identità esterno non riuscito. Ritorno all'accesso locale.
|
||||
|
||||
Dettagli dell'errore: {{.Details}}
|
||||
GrantRequired: Accesso non possibile. L'utente deve avere almeno una sovvenzione sull'applicazione. Contatta il tuo amministratore.
|
||||
ProjectRequired: Accesso non possibile. L'organizzazione dell'utente deve essere concessa al progetto. Contatta il tuo amministratore.
|
||||
IdentityProvider:
|
||||
|
@ -469,6 +469,10 @@ Errors:
|
||||
CreationNotAllowed: このプロバイダーでは、新しいユーザーの作成は許可されていません
|
||||
LinkingNotAllowed: このプロバイダーでは、ユーザーのリンクが許可されていません
|
||||
NoOptionAllowed: このプロバイダーでは作成もリンクも許可されていません。 管理者にお問い合わせください。
|
||||
LoginFailedSwitchLocal: |
|
||||
外部IDプロバイダーへのログインに失敗しました。ローカルログインに戻ります。
|
||||
|
||||
エラーの詳細: {{.Details}}
|
||||
GrantRequired: ログインできません。このユーザーは、アプリケーションに少なくとも1つの権限を付与されていることが必要です。管理者にお問い合わせください。
|
||||
ProjectRequired: ログインできません。ユーザーの組織がプロジェクトに権限を付与されている必要があります。管理者にお問い合わせください。
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: 이 제공자에서는 새 사용자 생성을 허용하지 않습니다
|
||||
LinkingNotAllowed: 이 제공자에서는 사용자를 연결할 수 없습니다
|
||||
NoOptionAllowed: 이 제공자에서는 생성과 연결이 모두 허용되지 않습니다. 관리자에게 문의하세요.
|
||||
LoginFailedSwitchLocal: |
|
||||
외부 IDP에서 로그인에 실패했습니다. 로컬 로그인으로 돌아갑니다.
|
||||
|
||||
오류 세부 정보: {{.Details}}
|
||||
GrantRequired: 로그인 불가. 사용자는 애플리케이션에서 최소한 하나의 권한이 필요합니다. 관리자에게 문의하세요.
|
||||
ProjectRequired: 로그인 불가. 사용자의 조직이 프로젝트에 허가되어야 합니다. 관리자에게 문의하세요.
|
||||
IdentityProvider:
|
||||
|
@ -506,6 +506,10 @@ Errors:
|
||||
CreationNotAllowed: Креирањето на нов корисник не е дозволено на овој провајдер
|
||||
LinkingNotAllowed: Поврзувањето на корисник не е дозволено на овој провајдер
|
||||
NoOptionAllowed: NНиту создавање, ниту поврзување е дозволено за овој провајдер. Ве молиме контактирајте го вашиот администратор.
|
||||
LoginFailedSwitchLocal: |
|
||||
Најавата во надворешен провајдер на идентитет не успеа. Враќање на локална најава.
|
||||
|
||||
Детали за грешката: {{.Details}}
|
||||
GrantRequired: Не е можно најавување. Корисникот мора да има барем едно овластување за апликацијата. Ве молиме контактирајте го вашиот администратор.
|
||||
ProjectRequired: Не е можно најавување. Организацијата на корисникот мора да биде доделена на проектот. Ве молиме контактирајте го вашиот администратор.
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: Creatie van een nieuwe gebruiker is niet toegestaan op deze Provider
|
||||
LinkingNotAllowed: Koppeling van een gebruiker is niet toegestaan op deze Provider
|
||||
NoOptionAllowed: Noch aanmaak noch koppeling is toegestaan voor deze provider. Neem contact op met uw beheerder.
|
||||
LoginFailedSwitchLocal: |
|
||||
Aanmelding bij externe identiteitsprovider is mislukt. Terug naar lokale aanmelding.
|
||||
|
||||
Foutdetails: {{.Details}}
|
||||
GrantRequired: Inloggen niet mogelijk. De gebruiker moet minimaal één grant hebben op de applicatie. Neem contact op met uw beheerder.
|
||||
ProjectRequired: Inloggen niet mogelijk. De organisatie van de gebruiker moet toegekend zijn aan het project. Neem contact op met uw beheerder.
|
||||
IdentityProvider:
|
||||
|
@ -506,6 +506,10 @@ Errors:
|
||||
CreationNotAllowed: Tworzenie nowego użytkownika nie jest dozwolone w tym Providencie
|
||||
LinkingNotAllowed: Linkowanie użytkownika nie jest dozwolone na tym Providencie
|
||||
NoOptionAllowed: Ani tworzenie, ani łączenie nie jest dozwolone dla tego dostawcy. Skontaktuj się z administratorem.
|
||||
LoginFailedSwitchLocal: |
|
||||
Logowanie w zewnętrznym dostawcy tożsamości nie powiodło się. Powrót do logowania lokalnego.
|
||||
|
||||
Szczegóły błędu: {{.Details}}
|
||||
GrantRequired: Logowanie nie jest możliwe. Użytkownik musi posiadać przynajmniej jedno uprawnienie w aplikacji. Skontaktuj się z administratorem.
|
||||
ProjectRequired: Logowanie nie jest możliwe. Organizacja użytkownika musi zostać udzielona projektowi. Skontaktuj się z administratorem.
|
||||
IdentityProvider:
|
||||
|
@ -502,6 +502,10 @@ Errors:
|
||||
CreationNotAllowed: A criação de um novo usuário não é permitida neste provedor
|
||||
LinkingNotAllowed: A vinculação de um usuário não é permitida neste provedor
|
||||
NoOptionAllowed: Nem criação nem vinculação são permitidas neste fornecedor. Contate o seu administrador.
|
||||
LoginFailedSwitchLocal: |
|
||||
Falha no login no provedor de identidade externo. Retornando ao login local.
|
||||
|
||||
Detalhes do erro: {{.Details}}
|
||||
GrantRequired: Login não é possível. O usuário precisa ter pelo menos uma permissão no aplicativo. Entre em contato com o administrador.
|
||||
ProjectRequired: Login não é possível. A organização do usuário precisa ser concedida ao projeto. Entre em contato com o administrador.
|
||||
IdentityProvider:
|
||||
|
@ -506,6 +506,10 @@ Errors:
|
||||
CreationNotAllowed: Создание нового пользователя для этого провайдера запрещено
|
||||
LinkingNotAllowed: Привязка к этому провайдеру запрещена
|
||||
NoOptionAllowed: Ни создание, ни привязка пользователя к этому провайдеру невозможны. Обратитесь к администратору.
|
||||
LoginFailedSwitchLocal: |
|
||||
Вход в внешний поставщик идентификации не удался. Возвращаемся к локальному входу.
|
||||
|
||||
Подробности об ошибке: {{.Details}}
|
||||
GrantRequired: Вход невозможен. Пользователь должен иметь хотя бы один допуск к приложению. Обратитесь к администратору.
|
||||
ProjectRequired: Вход невозможен. Организация пользователя должна иметь доступ к проекту. Обратитесь к администратору.
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: Det är inte tillåtet att skapa nya konton från den här externa leverantören
|
||||
LinkingNotAllowed: Det är inte tillåtet att koppla ihop konton från den här externa leverantören
|
||||
NoOptionAllowed: Varken skapande eller länkande är tillåtet för denna leverantör. Kontakta administratören.
|
||||
LoginFailedSwitchLocal: |
|
||||
Inloggning vid extern identitetsprovider misslyckades. Återgår till lokal inloggning.
|
||||
|
||||
Felaktighetsdetaljer: {{.Details}}
|
||||
GrantRequired: Det går inte att logga in just nu. Användarkontot har inte tillgång till någonting i tjänsten. Ta kontakt med systemansvarig.
|
||||
ProjectRequired: Det går inte att logga in just nu. Användarkontots organisation har inte tillgång till tjänsten. Ta kontakt med systemansvarig.
|
||||
IdentityProvider:
|
||||
|
@ -505,6 +505,10 @@ Errors:
|
||||
CreationNotAllowed: 不允许在该供应商上创建新用户
|
||||
LinkingNotAllowed: 在此提供者上不允许链接一个用户
|
||||
NoOptionAllowed: 此提供商不允许创建或链接。请联系您的管理员。
|
||||
LoginFailedSwitchLocal: |
|
||||
外部身份提供商的登录失败。返回到本地登录。
|
||||
|
||||
错误详情: {{.Details}}
|
||||
GrantRequired: 无法登录,用户需要在应用程序上拥有至少一项授权,请联系您的管理员。
|
||||
ProjectRequired: 无法登录,用户的组织必须授予项目,请联系您的管理员。
|
||||
IdentityProvider:
|
||||
|
@ -0,0 +1,30 @@
|
||||
function removeOverlay(overlay) {
|
||||
if (overlay.classList.contains("show")) {
|
||||
overlay.classList.remove("show");
|
||||
document.removeEventListener("mousemove", onMouseMove);
|
||||
document.removeEventListener("click", onClick);
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseMove() {
|
||||
const overlay = document.getElementById("dialog_overlay");
|
||||
if (overlay) {
|
||||
removeOverlay(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
const overlay = document.getElementById("dialog_overlay");
|
||||
if (overlay) {
|
||||
removeOverlay(overlay);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const overlay = document.getElementById("dialog_overlay");
|
||||
if (overlay && overlay.classList.contains("show")) {
|
||||
setTimeout(() => removeOverlay(overlay), 5000);
|
||||
document.addEventListener("mousemove", onMouseMove);
|
||||
document.addEventListener("click", onClick);
|
||||
}
|
||||
});
|
@ -20,3 +20,26 @@ body {
|
||||
.text-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dialog_overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: black;
|
||||
z-index: 1001;
|
||||
-moz-opacity: 0.8;
|
||||
opacity: .80;
|
||||
filter: alpha(opacity=80);
|
||||
}
|
||||
|
||||
.dialog_overlay.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dialog_content {
|
||||
position: relative;
|
||||
z-index: 1002;
|
||||
}
|
@ -6,6 +6,10 @@
|
||||
margin-right: .5rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.lgn-error-message {
|
||||
white-space: pre-line;
|
||||
}
|
||||
}
|
||||
|
||||
#wa-error {
|
||||
|
@ -1,10 +1,9 @@
|
||||
{{ define "error-message" }}
|
||||
{{if .ErrMessage }}
|
||||
<div class="lgn-error" title="{{.ErrID}}">
|
||||
<div class="lgn-error dialog_content" title="{{.ErrID}}">
|
||||
<i class="lgn-icon-exclamation-circle-solid lgn-warn"></i>
|
||||
<p class="lgn-error-message">
|
||||
{{ .ErrMessage }}
|
||||
</p>
|
||||
<p class="lgn-error-message">{{ .ErrMessage }}</p>
|
||||
</div>
|
||||
<div id="dialog_overlay" class="dialog_overlay {{if .ErrPopup}}show{{end}}"></div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{ end }}
|
@ -41,4 +41,5 @@
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/error_popup.js" }}"></script>
|
||||
|
||||
|
@ -40,5 +40,6 @@
|
||||
<script src="{{ resourceUrl "scripts/utils.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/webauthn.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/webauthn_login.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/error_popup.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
|
@ -16,12 +16,8 @@ type changeUsernameData struct {
|
||||
}
|
||||
|
||||
func (l *Login) renderChangeUsername(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "UsernameChange.Title", "UsernameChange.Description", errID, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "UsernameChange.Title", "UsernameChange.Description", err)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangeUsername], data, nil)
|
||||
}
|
||||
|
||||
@ -41,8 +37,7 @@ func (l *Login) handleChangeUsername(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (l *Login) renderChangeUsernameDone(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
|
||||
var errType, errMessage string
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := l.getUserData(r, authReq, translator, "UsernameChangeDone.Title", "UsernameChangeDone.Description", errType, errMessage)
|
||||
data := l.getUserData(r, authReq, translator, "UsernameChangeDone.Title", "UsernameChangeDone.Description", nil)
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplChangeUsernameDone], data, nil)
|
||||
}
|
||||
|
@ -41,4 +41,5 @@ type AuthRequestRepository interface {
|
||||
AutoRegisterExternalUser(ctx context.Context, user *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) error
|
||||
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
|
||||
ResetSelectedIDP(ctx context.Context, authReqID, userAgentID string) error
|
||||
RequestLocalAuth(ctx context.Context, authReqID, userAgentID string) error
|
||||
}
|
||||
|
@ -563,6 +563,15 @@ func (repo *AuthRequestRepo) ResetSelectedIDP(ctx context.Context, authReqID, us
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) RequestLocalAuth(ctx context.Context, authReqID, userAgentID string) error {
|
||||
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.RequestLocalAuth = true
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) (err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@ -1059,7 +1068,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
request.PreferredLanguage = gu.Ptr(language.Make(user.HumanView.PreferredLanguage))
|
||||
}
|
||||
|
||||
isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
|
||||
isInternalLogin := (request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == "") || request.RequestLocalAuth
|
||||
idps, err := checkExternalIDPsOfUser(ctx, repo.IDPUserLinksProvider, user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -1067,7 +1076,9 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
||||
noLocalAuth := request.LoginPolicy != nil && !request.LoginPolicy.AllowUsernamePassword
|
||||
|
||||
allowedLinkedIDPs := checkForAllowedIDPs(request.AllowedExternalIDPs, idps.Links)
|
||||
if (!isInternalLogin || len(allowedLinkedIDPs) > 0 || noLocalAuth) && len(request.LinkingUsers) == 0 {
|
||||
if (!isInternalLogin || len(allowedLinkedIDPs) > 0 || noLocalAuth) &&
|
||||
len(request.LinkingUsers) == 0 &&
|
||||
!request.RequestLocalAuth {
|
||||
step, err := repo.idpChecked(request, allowedLinkedIDPs, userSession)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2263,6 +2263,86 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
[]domain.NextStep{&domain.LinkUsersStep{}},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"local auth requested (passwordless and password set up), passwordless step",
|
||||
fields{
|
||||
userSessionViewProvider: &mockViewUserSession{},
|
||||
userViewProvider: &mockViewUser{
|
||||
PasswordSet: true,
|
||||
IsEmailVerified: true,
|
||||
MFAMaxSetUp: int32(domain.MFALevelMultiFactor),
|
||||
PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||
policy: &query.LockoutPolicy{
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{
|
||||
idps: []*query.IDPUserLink{{IDPID: "IDPConfigID"}},
|
||||
},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
AllowedExternalIDPs: []*domain.IDPProvider{
|
||||
{
|
||||
IDPConfigID: "IDPConfigID",
|
||||
},
|
||||
},
|
||||
RequestLocalAuth: true,
|
||||
}, false},
|
||||
[]domain.NextStep{
|
||||
&domain.PasswordlessStep{
|
||||
PasswordSet: true,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"local auth requested (password set up), password step",
|
||||
fields{
|
||||
userSessionViewProvider: &mockViewUserSession{},
|
||||
userViewProvider: &mockViewUser{
|
||||
PasswordSet: true,
|
||||
IsEmailVerified: true,
|
||||
},
|
||||
userEventProvider: &mockEventUser{},
|
||||
orgViewProvider: &mockViewOrg{State: domain.OrgStateActive},
|
||||
lockoutPolicyProvider: &mockLockoutPolicy{
|
||||
policy: &query.LockoutPolicy{
|
||||
ShowFailures: true,
|
||||
},
|
||||
},
|
||||
idpUserLinksProvider: &mockIDPUserLinks{
|
||||
idps: []*query.IDPUserLink{{IDPID: "IDPConfigID"}},
|
||||
},
|
||||
},
|
||||
args{
|
||||
&domain.AuthRequest{
|
||||
UserID: "UserID",
|
||||
SelectedIDPConfigID: "IDPConfigID",
|
||||
LoginPolicy: &domain.LoginPolicy{
|
||||
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||
},
|
||||
AllowedExternalIDPs: []*domain.IDPProvider{
|
||||
{
|
||||
IDPConfigID: "IDPConfigID",
|
||||
},
|
||||
},
|
||||
RequestLocalAuth: true,
|
||||
}, false},
|
||||
[]domain.NextStep{
|
||||
&domain.PasswordStep{},
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -60,6 +60,7 @@ type AuthRequest struct {
|
||||
DefaultTranslations []*CustomText
|
||||
OrgTranslations []*CustomText
|
||||
SAMLRequestID string
|
||||
RequestLocalAuth bool
|
||||
// orgID the policies were last loaded with
|
||||
policyOrgID string
|
||||
// SessionID is set to the computed sessionID of the login session table
|
||||
|
Loading…
x
Reference in New Issue
Block a user