diff --git a/internal/api/grpc/user/v2/user.go b/internal/api/grpc/user/v2/user.go
index dc91fe3ef..dd96f3107 100644
--- a/internal/api/grpc/user/v2/user.go
+++ b/internal/api/grpc/user/v2/user.go
@@ -590,7 +590,7 @@ func (s *Server) checkIntentToken(token string, intentID string) error {
}
func (s *Server) ListAuthenticationMethodTypes(ctx context.Context, req *user.ListAuthenticationMethodTypesRequest) (*user.ListAuthenticationMethodTypesResponse, error) {
- authMethods, err := s.query.ListActiveUserAuthMethodTypes(ctx, req.GetUserId())
+ authMethods, err := s.query.ListUserAuthMethodTypes(ctx, req.GetUserId(), true)
if err != nil {
return nil, err
}
diff --git a/internal/api/ui/login/mail_verify_handler.go b/internal/api/ui/login/mail_verify_handler.go
index 85c611457..a14aa197a 100644
--- a/internal/api/ui/login/mail_verify_handler.go
+++ b/internal/api/ui/login/mail_verify_handler.go
@@ -4,12 +4,12 @@ import (
"context"
"net/http"
"net/url"
+ "slices"
"github.com/zitadel/logging"
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/domain"
- "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -72,16 +72,16 @@ func (l *Login) handleMailVerification(w http.ResponseWriter, r *http.Request) {
}
func (l *Login) checkUserNoFirstFactor(ctx context.Context, userID string) bool {
- userIDQuery, err := query.NewUserAuthMethodUserIDSearchQuery(userID)
- logging.WithFields("userID", userID).OnError(err).Warn("error creating NewUserAuthMethodUserIDSearchQuery")
- authMethodsQuery, err := query.NewUserAuthMethodTypesSearchQuery(domain.UserAuthMethodTypeIDP, domain.UserAuthMethodTypePassword, domain.UserAuthMethodTypePasswordless)
- logging.WithFields("userID", userID).OnError(err).Warn("error creating NewUserAuthMethodTypesSearchQuery")
- authMethods, err := l.query.SearchUserAuthMethods(ctx, &query.UserAuthMethodSearchQueries{Queries: []query.SearchQuery{userIDQuery, authMethodsQuery}}, false)
+ authMethods, err := l.query.ListUserAuthMethodTypes(setUserContext(ctx, userID, ""), userID, false)
if err != nil {
logging.WithFields("userID", userID).OnError(err).Warn("unable to load user's auth methods for mail verification")
return false
}
- return len(authMethods.AuthMethods) == 0
+ return !slices.ContainsFunc(authMethods.AuthMethodTypes, func(m domain.UserAuthMethodType) bool {
+ return m == domain.UserAuthMethodTypeIDP ||
+ m == domain.UserAuthMethodTypePassword ||
+ m == domain.UserAuthMethodTypePasswordless
+ })
}
func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Request) {
diff --git a/internal/api/ui/login/static/templates/mail_verification.html b/internal/api/ui/login/static/templates/mail_verification.html
index 011947c17..961718567 100644
--- a/internal/api/ui/login/static/templates/mail_verification.html
+++ b/internal/api/ui/login/static/templates/mail_verification.html
@@ -39,7 +39,7 @@
{{ template "error-message" .}}
-
@@ -56,7 +56,11 @@
+{{ if .PasswordInit }}
+{{ else }}
+
+{{ end }}
{{template "main-bottom" .}}
diff --git a/internal/query/user_auth_method.go b/internal/query/user_auth_method.go
index f1e2721ba..243c465a8 100644
--- a/internal/query/user_auth_method.go
+++ b/internal/query/user_auth_method.go
@@ -146,7 +146,7 @@ func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMe
return userAuthMethods, err
}
-func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID string) (userAuthMethodTypes *AuthMethodTypes, err error) {
+func (q *Queries) ListUserAuthMethodTypes(ctx context.Context, userID string, activeOnly bool) (userAuthMethodTypes *AuthMethodTypes, err error) {
ctxData := authz.GetCtxData(ctx)
if ctxData.UserID != userID {
if err := q.checkPermission(ctx, domain.PermissionUserRead, ctxData.OrgID, userID); err != nil {
@@ -156,7 +156,7 @@ func (q *Queries) ListActiveUserAuthMethodTypes(ctx context.Context, userID stri
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
- query, scan := prepareActiveUserAuthMethodTypesQuery(ctx, q.client)
+ query, scan := prepareUserAuthMethodTypesQuery(ctx, q.client, activeOnly)
eq := sq.Eq{
UserIDCol.identifier(): userID,
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
@@ -353,8 +353,8 @@ func prepareUserAuthMethodsQuery(ctx context.Context, db prepareDatabase) (sq.Se
}
}
-func prepareActiveUserAuthMethodTypesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
- authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery()
+func prepareUserAuthMethodTypesQuery(ctx context.Context, db prepareDatabase, activeOnly bool) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
+ authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery(activeOnly)
if err != nil {
return sq.SelectBuilder{}, nil
}
@@ -468,14 +468,16 @@ func prepareAuthMethodsIDPsQuery() (string, error) {
return idpsQuery, err
}
-func prepareAuthMethodQuery() (string, []interface{}, error) {
- return sq.Select(
+func prepareAuthMethodQuery(activeOnly bool) (string, []interface{}, error) {
+ q := sq.Select(
"DISTINCT("+authMethodTypeType.identifier()+")",
authMethodTypeUserID.identifier(),
authMethodTypeInstanceID.identifier()).
- From(authMethodTypeTable.identifier()).
- Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady}).
- ToSql()
+ From(authMethodTypeTable.identifier())
+ if activeOnly {
+ q = q.Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady})
+ }
+ return q.ToSql()
}
func prepareAuthMethodsForceMFAQuery() (string, error) {
diff --git a/internal/query/user_auth_method_test.go b/internal/query/user_auth_method_test.go
index 59004f5da..95f9a0229 100644
--- a/internal/query/user_auth_method_test.go
+++ b/internal/query/user_auth_method_test.go
@@ -217,8 +217,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
object: (*AuthMethodTypes)(nil),
},
{
- name: "prepareActiveUserAuthMethodTypesQuery no result",
- prepare: prepareActiveUserAuthMethodTypesQuery,
+ name: "prepareUserAuthMethodTypesQuery no result",
+ prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
+ builder, scan := prepareUserAuthMethodTypesQuery(ctx, db, true)
+ return builder, func(rows *sql.Rows) (*AuthMethodTypes, error) {
+ return scan(rows)
+ }
+ },
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
@@ -229,8 +234,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
object: &AuthMethodTypes{AuthMethodTypes: []domain.UserAuthMethodType{}},
},
{
- name: "prepareActiveUserAuthMethodTypesQuery one second factor",
- prepare: prepareActiveUserAuthMethodTypesQuery,
+ name: "prepareUserAuthMethodTypesQuery one second factor",
+ prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
+ builder, scan := prepareUserAuthMethodTypesQuery(ctx, db, true)
+ return builder, func(rows *sql.Rows) (*AuthMethodTypes, error) {
+ return scan(rows)
+ }
+ },
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
@@ -256,8 +266,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
},
},
{
- name: "prepareActiveUserAuthMethodTypesQuery multiple second factors",
- prepare: prepareActiveUserAuthMethodTypesQuery,
+ name: "prepareUserAuthMethodTypesQuery multiple second factors",
+ prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
+ builder, scan := prepareUserAuthMethodTypesQuery(ctx, db, true)
+ return builder, func(rows *sql.Rows) (*AuthMethodTypes, error) {
+ return scan(rows)
+ }
+ },
want: want{
sqlExpectations: mockQueries(
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
@@ -289,8 +304,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
},
},
{
- name: "prepareActiveUserAuthMethodTypesQuery sql err",
- prepare: prepareActiveUserAuthMethodTypesQuery,
+ name: "prepareUserAuthMethodTypesQuery sql err",
+ prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
+ builder, scan := prepareUserAuthMethodTypesQuery(ctx, db, true)
+ return builder, func(rows *sql.Rows) (*AuthMethodTypes, error) {
+ return scan(rows)
+ }
+ },
want: want{
sqlExpectations: mockQueryErr(
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),