mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 10:07:32 +00:00
fix: correctly check user auth methods and enable button (#8342)
# Which Problems Are Solved #8291 added backwards compatibilty for users who were created through the user V2 API and want to sign in to the login UI. There were however to issues, where users might be prompted to set a password even if they already had one set or they would not be able to submit the email verification code. # How the Problems Are Solved - Replaced `SearchUserAuthMethods `with `ListUserAuthMethodTypes` to check for set up auth methods. - Fixed page / javascript to disable submit button. # Additional Changes - Changed `ListActiveUserAuthMethodTypes ` to `ListUserAuthMethodTypes` and a `activeOnly` boolean parameter # Additional Context - relates to #8291 - noticed internally on QA
This commit is contained in:
@@ -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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -4,12 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
"github.com/zitadel/logging"
|
||||||
|
|
||||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"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 {
|
func (l *Login) checkUserNoFirstFactor(ctx context.Context, userID string) bool {
|
||||||
userIDQuery, err := query.NewUserAuthMethodUserIDSearchQuery(userID)
|
authMethods, err := l.query.ListUserAuthMethodTypes(setUserContext(ctx, userID, ""), userID, false)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.WithFields("userID", userID).OnError(err).Warn("unable to load user's auth methods for mail verification")
|
logging.WithFields("userID", userID).OnError(err).Warn("unable to load user's auth methods for mail verification")
|
||||||
return false
|
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) {
|
func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@@ -39,7 +39,7 @@
|
|||||||
{{ template "error-message" .}}
|
{{ template "error-message" .}}
|
||||||
|
|
||||||
<div class="lgn-actions lgn-reverse-order">
|
<div class="lgn-actions lgn-reverse-order">
|
||||||
<button type="submit" id="init-button" name="resend" value="false"
|
<button type="submit" id="{{if.PasswordInit}}init-button{{else}}submit-button{{end}}" name="resend" value="false"
|
||||||
class="lgn-primary lgn-raised-button">{{t "EmailVerification.NextButtonText"}}
|
class="lgn-primary lgn-raised-button">{{t "EmailVerification.NextButtonText"}}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -56,7 +56,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||||
|
{{ if .PasswordInit }}
|
||||||
<script src="{{ resourceUrl "scripts/password_policy_check.js" }}"></script>
|
<script src="{{ resourceUrl "scripts/password_policy_check.js" }}"></script>
|
||||||
<script src="{{ resourceUrl "scripts/init_password_check.js" }}"></script>
|
<script src="{{ resourceUrl "scripts/init_password_check.js" }}"></script>
|
||||||
|
{{ else }}
|
||||||
|
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
{{template "main-bottom" .}}
|
{{template "main-bottom" .}}
|
||||||
|
@@ -146,7 +146,7 @@ func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMe
|
|||||||
return userAuthMethods, err
|
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)
|
ctxData := authz.GetCtxData(ctx)
|
||||||
if ctxData.UserID != userID {
|
if ctxData.UserID != userID {
|
||||||
if err := q.checkPermission(ctx, domain.PermissionUserRead, ctxData.OrgID, userID); err != nil {
|
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)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
query, scan := prepareActiveUserAuthMethodTypesQuery(ctx, q.client)
|
query, scan := prepareUserAuthMethodTypesQuery(ctx, q.client, activeOnly)
|
||||||
eq := sq.Eq{
|
eq := sq.Eq{
|
||||||
UserIDCol.identifier(): userID,
|
UserIDCol.identifier(): userID,
|
||||||
UserInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
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)) {
|
func prepareUserAuthMethodTypesQuery(ctx context.Context, db prepareDatabase, activeOnly bool) (sq.SelectBuilder, func(*sql.Rows) (*AuthMethodTypes, error)) {
|
||||||
authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery()
|
authMethodsQuery, authMethodsArgs, err := prepareAuthMethodQuery(activeOnly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sq.SelectBuilder{}, nil
|
return sq.SelectBuilder{}, nil
|
||||||
}
|
}
|
||||||
@@ -468,14 +468,16 @@ func prepareAuthMethodsIDPsQuery() (string, error) {
|
|||||||
return idpsQuery, err
|
return idpsQuery, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareAuthMethodQuery() (string, []interface{}, error) {
|
func prepareAuthMethodQuery(activeOnly bool) (string, []interface{}, error) {
|
||||||
return sq.Select(
|
q := sq.Select(
|
||||||
"DISTINCT("+authMethodTypeType.identifier()+")",
|
"DISTINCT("+authMethodTypeType.identifier()+")",
|
||||||
authMethodTypeUserID.identifier(),
|
authMethodTypeUserID.identifier(),
|
||||||
authMethodTypeInstanceID.identifier()).
|
authMethodTypeInstanceID.identifier()).
|
||||||
From(authMethodTypeTable.identifier()).
|
From(authMethodTypeTable.identifier())
|
||||||
Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady}).
|
if activeOnly {
|
||||||
ToSql()
|
q = q.Where(sq.Eq{authMethodTypeState.identifier(): domain.MFAStateReady})
|
||||||
|
}
|
||||||
|
return q.ToSql()
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareAuthMethodsForceMFAQuery() (string, error) {
|
func prepareAuthMethodsForceMFAQuery() (string, error) {
|
||||||
|
@@ -217,8 +217,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
|
|||||||
object: (*AuthMethodTypes)(nil),
|
object: (*AuthMethodTypes)(nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareActiveUserAuthMethodTypesQuery no result",
|
name: "prepareUserAuthMethodTypesQuery no result",
|
||||||
prepare: prepareActiveUserAuthMethodTypesQuery,
|
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{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
||||||
@@ -229,8 +234,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
|
|||||||
object: &AuthMethodTypes{AuthMethodTypes: []domain.UserAuthMethodType{}},
|
object: &AuthMethodTypes{AuthMethodTypes: []domain.UserAuthMethodType{}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareActiveUserAuthMethodTypesQuery one second factor",
|
name: "prepareUserAuthMethodTypesQuery one second factor",
|
||||||
prepare: prepareActiveUserAuthMethodTypesQuery,
|
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{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
||||||
@@ -256,8 +266,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareActiveUserAuthMethodTypesQuery multiple second factors",
|
name: "prepareUserAuthMethodTypesQuery multiple second factors",
|
||||||
prepare: prepareActiveUserAuthMethodTypesQuery,
|
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{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
||||||
@@ -289,8 +304,13 @@ func Test_UserAuthMethodPrepares(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareActiveUserAuthMethodTypesQuery sql err",
|
name: "prepareUserAuthMethodTypesQuery sql err",
|
||||||
prepare: prepareActiveUserAuthMethodTypesQuery,
|
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{
|
want: want{
|
||||||
sqlExpectations: mockQueryErr(
|
sqlExpectations: mockQueryErr(
|
||||||
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
regexp.QuoteMeta(prepareActiveAuthMethodTypesStmt),
|
||||||
|
Reference in New Issue
Block a user