feat: add is_multi_factor_auth_enabled

This commit is contained in:
Lakhan Samani 2022-07-23 15:26:44 +05:30
parent 0f081ac3c8
commit 9ef5f33f7a
8 changed files with 216 additions and 117 deletions

View File

@ -29,6 +29,7 @@ type User struct {
Picture *string `gorm:"type:text" json:"picture" bson:"picture" cql:"picture"` Picture *string `gorm:"type:text" json:"picture" bson:"picture" cql:"picture"`
Roles string `json:"roles" bson:"roles" cql:"roles"` Roles string `json:"roles" bson:"roles" cql:"roles"`
RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp" cql:"revoked_timestamp"` RevokedTimestamp *int64 `json:"revoked_timestamp" bson:"revoked_timestamp" cql:"revoked_timestamp"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled" bson:"is_multi_factor_auth_enabled" cql:"is_multi_factor_auth_enabled"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at"`
} }
@ -58,6 +59,7 @@ func (user *User) AsAPIUser() *model.User {
Picture: user.Picture, Picture: user.Picture,
Roles: strings.Split(user.Roles, ","), Roles: strings.Split(user.Roles, ","),
RevokedTimestamp: user.RevokedTimestamp, RevokedTimestamp: user.RevokedTimestamp,
IsMultiFactorAuthEnabled: user.IsMultiFactorAuthEnabled,
CreatedAt: refs.NewInt64Ref(user.CreatedAt), CreatedAt: refs.NewInt64Ref(user.CreatedAt),
UpdatedAt: refs.NewInt64Ref(user.UpdatedAt), UpdatedAt: refs.NewInt64Ref(user.UpdatedAt),
} }

View File

@ -159,6 +159,12 @@ func NewProvider() (*provider, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// add is_multi_factor_auth_enabled on users table
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean;`, KeySpace, models.Collections.User)
err = session.Query(userTableAlterQuery).Exec()
if err != nil {
return nil, err
}
// token is reserved keyword in cassandra, hence we need to use jwt_token // token is reserved keyword in cassandra, hence we need to use jwt_token
verificationRequestCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, jwt_token text, identifier text, expires_at bigint, email text, nonce text, redirect_uri text, created_at bigint, updated_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.VerificationRequest) verificationRequestCollectionQuery := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s.%s (id text, jwt_token text, identifier text, expires_at bigint, email text, nonce text, redirect_uri text, created_at bigint, updated_at bigint, PRIMARY KEY (id))", KeySpace, models.Collections.VerificationRequest)

View File

@ -212,6 +212,7 @@ type ComplexityRoot struct {
Gender func(childComplexity int) int Gender func(childComplexity int) int
GivenName func(childComplexity int) int GivenName func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
IsMultiFactorAuthEnabled func(childComplexity int) int
MiddleName func(childComplexity int) int MiddleName func(childComplexity int) int
Nickname func(childComplexity int) int Nickname func(childComplexity int) int
PhoneNumber func(childComplexity int) int PhoneNumber func(childComplexity int) int
@ -1429,6 +1430,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.User.ID(childComplexity), true return e.complexity.User.ID(childComplexity), true
case "User.is_multi_factor_auth_enabled":
if e.complexity.User.IsMultiFactorAuthEnabled == nil {
break
}
return e.complexity.User.IsMultiFactorAuthEnabled(childComplexity), true
case "User.middle_name": case "User.middle_name":
if e.complexity.User.MiddleName == nil { if e.complexity.User.MiddleName == nil {
break break
@ -1836,6 +1844,7 @@ type User {
created_at: Int64 created_at: Int64
updated_at: Int64 updated_at: Int64
revoked_timestamp: Int64 revoked_timestamp: Int64
is_multi_factor_auth_enabled: Boolean
} }
type Users { type Users {
@ -2052,6 +2061,7 @@ input SignUpInput {
roles: [String!] roles: [String!]
scope: [String!] scope: [String!]
redirect_uri: String redirect_uri: String
is_multi_factor_auth_enabled: Boolean
} }
input LoginInput { input LoginInput {
@ -2083,6 +2093,7 @@ input UpdateProfileInput {
birthdate: String birthdate: String
phone_number: String phone_number: String
picture: String picture: String
is_multi_factor_auth_enabled: Boolean
} }
input UpdateUserInput { input UpdateUserInput {
@ -2098,6 +2109,7 @@ input UpdateUserInput {
phone_number: String phone_number: String
picture: String picture: String
roles: [String] roles: [String]
is_multi_factor_auth_enabled: Boolean
} }
input ForgotPasswordInput { input ForgotPasswordInput {
@ -7888,6 +7900,38 @@ func (ec *executionContext) _User_revoked_timestamp(ctx context.Context, field g
return ec.marshalOInt642ᚖint64(ctx, field.Selections, res) return ec.marshalOInt642ᚖint64(ctx, field.Selections, res)
} }
func (ec *executionContext) _User_is_multi_factor_auth_enabled(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "User",
Field: field,
Args: nil,
IsMethod: false,
IsResolver: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.IsMultiFactorAuthEnabled, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*bool)
fc.Result = res
return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
}
func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql.CollectedField, obj *model.Users) (ret graphql.Marshaler) { func (ec *executionContext) _Users_pagination(ctx context.Context, field graphql.CollectedField, obj *model.Users) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -10765,6 +10809,14 @@ func (ec *executionContext) unmarshalInputSignUpInput(ctx context.Context, obj i
if err != nil { if err != nil {
return it, err return it, err
} }
case "is_multi_factor_auth_enabled":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_multi_factor_auth_enabled"))
it.IsMultiFactorAuthEnabled, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
} }
} }
@ -11304,6 +11356,14 @@ func (ec *executionContext) unmarshalInputUpdateProfileInput(ctx context.Context
if err != nil { if err != nil {
return it, err return it, err
} }
case "is_multi_factor_auth_enabled":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_multi_factor_auth_enabled"))
it.IsMultiFactorAuthEnabled, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
} }
} }
@ -11415,6 +11475,14 @@ func (ec *executionContext) unmarshalInputUpdateUserInput(ctx context.Context, o
if err != nil { if err != nil {
return it, err return it, err
} }
case "is_multi_factor_auth_enabled":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_multi_factor_auth_enabled"))
it.IsMultiFactorAuthEnabled, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
if err != nil {
return it, err
}
} }
} }
@ -12482,6 +12550,8 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._User_updated_at(ctx, field, obj) out.Values[i] = ec._User_updated_at(ctx, field, obj)
case "revoked_timestamp": case "revoked_timestamp":
out.Values[i] = ec._User_revoked_timestamp(ctx, field, obj) out.Values[i] = ec._User_revoked_timestamp(ctx, field, obj)
case "is_multi_factor_auth_enabled":
out.Values[i] = ec._User_is_multi_factor_auth_enabled(ctx, field, obj)
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }

View File

@ -219,6 +219,7 @@ type SignUpInput struct {
Roles []string `json:"roles"` Roles []string `json:"roles"`
Scope []string `json:"scope"` Scope []string `json:"scope"`
RedirectURI *string `json:"redirect_uri"` RedirectURI *string `json:"redirect_uri"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
} }
type TestEndpointRequest struct { type TestEndpointRequest struct {
@ -297,6 +298,7 @@ type UpdateProfileInput struct {
Birthdate *string `json:"birthdate"` Birthdate *string `json:"birthdate"`
PhoneNumber *string `json:"phone_number"` PhoneNumber *string `json:"phone_number"`
Picture *string `json:"picture"` Picture *string `json:"picture"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
} }
type UpdateUserInput struct { type UpdateUserInput struct {
@ -312,6 +314,7 @@ type UpdateUserInput struct {
PhoneNumber *string `json:"phone_number"` PhoneNumber *string `json:"phone_number"`
Picture *string `json:"picture"` Picture *string `json:"picture"`
Roles []*string `json:"roles"` Roles []*string `json:"roles"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
} }
type UpdateWebhookRequest struct { type UpdateWebhookRequest struct {
@ -341,6 +344,7 @@ type User struct {
CreatedAt *int64 `json:"created_at"` CreatedAt *int64 `json:"created_at"`
UpdatedAt *int64 `json:"updated_at"` UpdatedAt *int64 `json:"updated_at"`
RevokedTimestamp *int64 `json:"revoked_timestamp"` RevokedTimestamp *int64 `json:"revoked_timestamp"`
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
} }
type Users struct { type Users struct {

View File

@ -47,6 +47,7 @@ type User {
created_at: Int64 created_at: Int64
updated_at: Int64 updated_at: Int64
revoked_timestamp: Int64 revoked_timestamp: Int64
is_multi_factor_auth_enabled: Boolean
} }
type Users { type Users {
@ -263,6 +264,7 @@ input SignUpInput {
roles: [String!] roles: [String!]
scope: [String!] scope: [String!]
redirect_uri: String redirect_uri: String
is_multi_factor_auth_enabled: Boolean
} }
input LoginInput { input LoginInput {
@ -294,6 +296,7 @@ input UpdateProfileInput {
birthdate: String birthdate: String
phone_number: String phone_number: String
picture: String picture: String
is_multi_factor_auth_enabled: Boolean
} }
input UpdateUserInput { input UpdateUserInput {
@ -309,6 +312,7 @@ input UpdateUserInput {
phone_number: String phone_number: String
picture: String picture: String
roles: [String] roles: [String]
is_multi_factor_auth_enabled: Boolean
} }
input ForgotPasswordInput { input ForgotPasswordInput {

View File

@ -157,6 +157,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
user.Picture = params.Picture user.Picture = params.Picture
} }
if params.IsMultiFactorAuthEnabled != nil {
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
}
user.SignupMethods = constants.AuthRecipeMethodBasicAuth user.SignupMethods = constants.AuthRecipeMethodBasicAuth
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
if err != nil { if err != nil {

View File

@ -94,6 +94,10 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
user.Picture = params.Picture user.Picture = params.Picture
} }
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
}
isPasswordChanging := false isPasswordChanging := false
if params.NewPassword != nil && params.ConfirmNewPassword == nil { if params.NewPassword != nil && params.ConfirmNewPassword == nil {
isPasswordChanging = true isPasswordChanging = true

View File

@ -15,6 +15,7 @@ import (
"github.com/authorizerdev/authorizer/server/graph/model" "github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/memorystore" "github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/parsers" "github.com/authorizerdev/authorizer/server/parsers"
"github.com/authorizerdev/authorizer/server/refs"
"github.com/authorizerdev/authorizer/server/token" "github.com/authorizerdev/authorizer/server/token"
"github.com/authorizerdev/authorizer/server/utils" "github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators" "github.com/authorizerdev/authorizer/server/validators"
@ -56,38 +57,42 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
return res, fmt.Errorf(`User not found`) return res, fmt.Errorf(`User not found`)
} }
if params.GivenName != nil && user.GivenName != params.GivenName { if params.GivenName != nil && refs.StringValue(user.GivenName) != refs.StringValue(params.GivenName) {
user.GivenName = params.GivenName user.GivenName = params.GivenName
} }
if params.FamilyName != nil && user.FamilyName != params.FamilyName { if params.FamilyName != nil && refs.StringValue(user.FamilyName) != refs.StringValue(params.FamilyName) {
user.FamilyName = params.FamilyName user.FamilyName = params.FamilyName
} }
if params.MiddleName != nil && user.MiddleName != params.MiddleName { if params.MiddleName != nil && refs.StringValue(user.MiddleName) != refs.StringValue(params.MiddleName) {
user.MiddleName = params.MiddleName user.MiddleName = params.MiddleName
} }
if params.Nickname != nil && user.Nickname != params.Nickname { if params.Nickname != nil && refs.StringValue(user.Nickname) != refs.StringValue(params.Nickname) {
user.Nickname = params.Nickname user.Nickname = params.Nickname
} }
if params.Birthdate != nil && user.Birthdate != params.Birthdate { if params.Birthdate != nil && refs.StringValue(user.Birthdate) != refs.StringValue(params.Birthdate) {
user.Birthdate = params.Birthdate user.Birthdate = params.Birthdate
} }
if params.Gender != nil && user.Gender != params.Gender { if params.Gender != nil && refs.StringValue(user.Gender) != refs.StringValue(params.Gender) {
user.Gender = params.Gender user.Gender = params.Gender
} }
if params.PhoneNumber != nil && user.PhoneNumber != params.PhoneNumber { if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
user.PhoneNumber = params.PhoneNumber user.PhoneNumber = params.PhoneNumber
} }
if params.Picture != nil && user.Picture != params.Picture { if params.Picture != nil && refs.StringValue(user.Picture) != refs.StringValue(params.Picture) {
user.Picture = params.Picture user.Picture = params.Picture
} }
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
}
if params.EmailVerified != nil { if params.EmailVerified != nil {
if *params.EmailVerified { if *params.EmailVerified {
now := time.Now().Unix() now := time.Now().Unix()