mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:57:31 +00:00
feat: auth method query side (#3068)
* feat: queries for searching mfas and passwordless * feat: tests for user auth method queries * Update internal/api/grpc/auth/multi_factor.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/api/grpc/auth/passwordless.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/api/grpc/management/user.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/api/grpc/management/user.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
274
internal/query/user_auth_method.go
Normal file
274
internal/query/user_auth_method.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
errs "errors"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/caos/zitadel/internal/query/projection"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
userAuthMethodTable = table{
|
||||
name: projection.UserAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnTokenID = Column{
|
||||
name: projection.UserAuthMethodTokenIDCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnCreationDate = Column{
|
||||
name: projection.UserAuthMethodCreationDateCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnChangeDate = Column{
|
||||
name: projection.UserAuthMethodChangeDateCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnResourceOwner = Column{
|
||||
name: projection.UserAuthMethodResourceOwnerCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnUserID = Column{
|
||||
name: projection.UserAuthMethodUserIDCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnSequence = Column{
|
||||
name: projection.UserAuthMethodSequenceCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnName = Column{
|
||||
name: projection.UserAuthMethodNameCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnState = Column{
|
||||
name: projection.UserAuthMethodStateCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
UserAuthMethodColumnMethodType = Column{
|
||||
name: projection.UserAuthMethodTypeCol,
|
||||
table: userAuthMethodTable,
|
||||
}
|
||||
)
|
||||
|
||||
type AuthMethods struct {
|
||||
SearchResponse
|
||||
AuthMethods []*AuthMethod
|
||||
}
|
||||
type AuthMethod struct {
|
||||
UserID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
ResourceOwner string
|
||||
State domain.MFAState
|
||||
Sequence uint64
|
||||
|
||||
TokenID string
|
||||
Name string
|
||||
Type domain.UserAuthMethodType
|
||||
}
|
||||
|
||||
type UserAuthMethodSearchQueries struct {
|
||||
SearchRequest
|
||||
Queries []SearchQuery
|
||||
}
|
||||
|
||||
func (q *Queries) UserAuthMethodByIDs(ctx context.Context, userID, tokenID, resourceOwner string, methodType domain.UserAuthMethodType) (*AuthMethod, error) {
|
||||
stmt, scan := prepareUserAuthMethodQuery()
|
||||
query, args, err := stmt.Where(sq.Eq{
|
||||
UserAuthMethodColumnUserID.identifier(): userID,
|
||||
UserAuthMethodColumnTokenID.identifier(): tokenID,
|
||||
UserAuthMethodColumnResourceOwner.identifier(): resourceOwner,
|
||||
UserAuthMethodColumnMethodType.identifier(): methodType,
|
||||
}).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-2m00Q", "Errors.Query.SQLStatment")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, query, args...)
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func (q *Queries) SearchUserAuthMethods(ctx context.Context, queries *UserAuthMethodSearchQueries) (userAuthMethods *AuthMethods, err error) {
|
||||
query, scan := prepareUserAuthMethodsQuery()
|
||||
stmt, args, err := queries.toQuery(query).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-j9NJd", "Errors.Query.InvalidRequest")
|
||||
}
|
||||
|
||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-3n99f", "Errors.Internal")
|
||||
}
|
||||
userAuthMethods, err = scan(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userAuthMethods.LatestSequence, err = q.latestSequence(ctx, userAuthMethodTable)
|
||||
return userAuthMethods, err
|
||||
}
|
||||
|
||||
func NewUserAuthMethodUserIDSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(UserAuthMethodColumnUserID, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewUserAuthMethodTokenIDSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(UserAuthMethodColumnTokenID, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewUserAuthMethodResourceOwnerSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(UserAuthMethodColumnResourceOwner, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewUserAuthMethodTypeSearchQuery(value domain.UserAuthMethodType) (SearchQuery, error) {
|
||||
return NewNumberQuery(UserAuthMethodColumnMethodType, value, NumberEquals)
|
||||
}
|
||||
|
||||
func NewUserAuthMethodTypesSearchQuery(values ...domain.UserAuthMethodType) (SearchQuery, error) {
|
||||
list := make([]interface{}, len(values))
|
||||
for i, value := range values {
|
||||
list[i] = value
|
||||
}
|
||||
return NewListQuery(UserAuthMethodColumnMethodType, list, ListIn)
|
||||
}
|
||||
|
||||
func (r *UserAuthMethodSearchQueries) AppendResourceOwnerQuery(orgID string) error {
|
||||
query, err := NewUserAuthMethodResourceOwnerSearchQuery(orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Queries = append(r.Queries, query)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserAuthMethodSearchQueries) AppendUserIDQuery(userID string) error {
|
||||
query, err := NewUserAuthMethodUserIDSearchQuery(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Queries = append(r.Queries, query)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserAuthMethodSearchQueries) AppendTokenIDQuery(tokenID string) error {
|
||||
query, err := NewUserAuthMethodTokenIDSearchQuery(tokenID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Queries = append(r.Queries, query)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserAuthMethodSearchQueries) AppendAuthMethodQuery(authMethod domain.UserAuthMethodType) error {
|
||||
query, err := NewUserAuthMethodTypeSearchQuery(authMethod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Queries = append(r.Queries, query)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *UserAuthMethodSearchQueries) AppendAuthMethodsQuery(authMethod ...domain.UserAuthMethodType) error {
|
||||
query, err := NewUserAuthMethodTypesSearchQuery(authMethod...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Queries = append(r.Queries, query)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *UserAuthMethodSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||
query = q.SearchRequest.toQuery(query)
|
||||
for _, q := range q.Queries {
|
||||
query = q.toQuery(query)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func prepareUserAuthMethodQuery() (sq.SelectBuilder, func(*sql.Row) (*AuthMethod, error)) {
|
||||
return sq.Select(
|
||||
UserAuthMethodColumnTokenID.identifier(),
|
||||
UserAuthMethodColumnCreationDate.identifier(),
|
||||
UserAuthMethodColumnChangeDate.identifier(),
|
||||
UserAuthMethodColumnResourceOwner.identifier(),
|
||||
UserAuthMethodColumnUserID.identifier(),
|
||||
UserAuthMethodColumnSequence.identifier(),
|
||||
UserAuthMethodColumnName.identifier(),
|
||||
UserAuthMethodColumnState.identifier(),
|
||||
UserAuthMethodColumnMethodType.identifier()).
|
||||
From(userAuthMethodTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*AuthMethod, error) {
|
||||
authMethod := new(AuthMethod)
|
||||
err := row.Scan(
|
||||
&authMethod.TokenID,
|
||||
&authMethod.CreationDate,
|
||||
&authMethod.ChangeDate,
|
||||
&authMethod.ResourceOwner,
|
||||
&authMethod.UserID,
|
||||
&authMethod.Sequence,
|
||||
&authMethod.Name,
|
||||
&authMethod.State,
|
||||
&authMethod.Type,
|
||||
)
|
||||
if err != nil {
|
||||
if errs.Is(err, sql.ErrNoRows) {
|
||||
return nil, errors.ThrowNotFound(err, "QUERY-dniiF", "Errors.AuthMethod.NotFound")
|
||||
}
|
||||
return nil, errors.ThrowInternal(err, "QUERY-3n9Fs", "Errors.Internal")
|
||||
}
|
||||
return authMethod, nil
|
||||
}
|
||||
}
|
||||
|
||||
func prepareUserAuthMethodsQuery() (sq.SelectBuilder, func(*sql.Rows) (*AuthMethods, error)) {
|
||||
return sq.Select(
|
||||
UserAuthMethodColumnTokenID.identifier(),
|
||||
UserAuthMethodColumnCreationDate.identifier(),
|
||||
UserAuthMethodColumnChangeDate.identifier(),
|
||||
UserAuthMethodColumnResourceOwner.identifier(),
|
||||
UserAuthMethodColumnUserID.identifier(),
|
||||
UserAuthMethodColumnSequence.identifier(),
|
||||
UserAuthMethodColumnName.identifier(),
|
||||
UserAuthMethodColumnState.identifier(),
|
||||
UserAuthMethodColumnMethodType.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(userAuthMethodTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*AuthMethods, error) {
|
||||
userAuthMethods := make([]*AuthMethod, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
authMethod := new(AuthMethod)
|
||||
err := rows.Scan(
|
||||
&authMethod.TokenID,
|
||||
&authMethod.CreationDate,
|
||||
&authMethod.ChangeDate,
|
||||
&authMethod.ResourceOwner,
|
||||
&authMethod.UserID,
|
||||
&authMethod.Sequence,
|
||||
&authMethod.Name,
|
||||
&authMethod.State,
|
||||
&authMethod.Type,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userAuthMethods = append(userAuthMethods, authMethod)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-3n9fl", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &AuthMethods{
|
||||
AuthMethods: userAuthMethods,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user