diff --git a/dashboard/src/components/EnvComponents/Features.tsx b/dashboard/src/components/EnvComponents/Features.tsx
index 929da5b..9f0c445 100644
--- a/dashboard/src/components/EnvComponents/Features.tsx
+++ b/dashboard/src/components/EnvComponents/Features.tsx
@@ -4,6 +4,7 @@ import InputField from '../InputField';
import { SwitchInputType } from '../../constants';
const Features = ({ variables, setVariables }: any) => {
+ // window.alert(variables)
return (
{' '}
@@ -24,6 +25,8 @@ const Features = ({ variables, setVariables }: any) => {
/>
+
+
Email Verification:
@@ -97,6 +100,7 @@ const Features = ({ variables, setVariables }: any) => {
also ignore the user MFA setting.
+
{
/>
+
+ {
+ !variables.DISABLE_MULTI_FACTOR_AUTHENTICATION &&
+
+
+ TOTP:
+
+ Note: to enable totp mfa
+
+
+
+
+
+
+
+ }
+ {!variables.DISABLE_MULTI_FACTOR_AUTHENTICATION &&
+
+
+ EMAIL OTP:
+
+ Note: to enable email otp mfa
+
+
+
+
+
+
+ }
+
diff --git a/dashboard/src/constants.ts b/dashboard/src/constants.ts
index 2dbf412..7a12131 100644
--- a/dashboard/src/constants.ts
+++ b/dashboard/src/constants.ts
@@ -85,6 +85,8 @@ export const SwitchInputType = {
DISABLE_MULTI_FACTOR_AUTHENTICATION: 'DISABLE_MULTI_FACTOR_AUTHENTICATION',
ENFORCE_MULTI_FACTOR_AUTHENTICATION: 'ENFORCE_MULTI_FACTOR_AUTHENTICATION',
DISABLE_PLAYGROUND: 'DISABLE_PLAYGROUND',
+ DISABLE_TOTP_LOGIN: 'DISABLE_TOTP_LOGIN',
+ DISABLE_MAIL_OTP_LOGIN: 'DISABLE_MAIL_OTP_LOGIN',
};
export const DateInputType = {
@@ -169,6 +171,8 @@ export interface envVarTypes {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: string;
DEFAULT_AUTHORIZE_RESPONSE_MODE: string;
DISABLE_PLAYGROUND: boolean;
+ DISABLE_TOTP_LOGIN: boolean;
+ DISABLE_MAIL_OTP_LOGIN: boolean;
}
export const envSubViews = {
diff --git a/dashboard/src/graphql/queries/index.ts b/dashboard/src/graphql/queries/index.ts
index c5152f5..ffa8cd9 100644
--- a/dashboard/src/graphql/queries/index.ts
+++ b/dashboard/src/graphql/queries/index.ts
@@ -74,6 +74,8 @@ export const EnvVariablesQuery = `
DEFAULT_AUTHORIZE_RESPONSE_TYPE
DEFAULT_AUTHORIZE_RESPONSE_MODE
DISABLE_PLAYGROUND
+ DISABLE_TOTP_LOGIN
+ DISABLE_MAIL_OTP_LOGIN
}
}
`;
diff --git a/dashboard/src/pages/Environment.tsx b/dashboard/src/pages/Environment.tsx
index c8d405c..8871f4a 100644
--- a/dashboard/src/pages/Environment.tsx
+++ b/dashboard/src/pages/Environment.tsx
@@ -94,6 +94,8 @@ const Environment = () => {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: '',
DEFAULT_AUTHORIZE_RESPONSE_MODE: '',
DISABLE_PLAYGROUND: false,
+ DISABLE_TOTP_LOGIN: false,
+ DISABLE_MAIL_OTP_LOGIN: true,
});
const [fieldVisibility, setFieldVisibility] = React.useState<
diff --git a/server/constants/env.go b/server/constants/env.go
index 649603c..e89984b 100644
--- a/server/constants/env.go
+++ b/server/constants/env.go
@@ -160,9 +160,12 @@ const (
// EnvKeyDisableMultiFactorAuthentication is key for env variable DISABLE_MULTI_FACTOR_AUTHENTICATION
// this variable is used to completely disable multi factor authentication. It will have no effect on profile preference
EnvKeyDisableMultiFactorAuthentication = "DISABLE_MULTI_FACTOR_AUTHENTICATION"
- // EnvKeyDisableTotpAuthentication is key for env variable DISABLE_TOTP_AUTHENTICATION
+ // EnvKeyDisableTOTPLogin is key for env variable DISABLE_TOTP_LOGIN
// this variable is used to completely disable totp verification
- EnvKeyDisableTotpAuthentication = "DISABLE_TOTP_AUTHENTICATION"
+ EnvKeyDisableTOTPLogin = "DISABLE_TOTP_LOGIN"
+ // EnvKeyDisableMailOTPLogin is key for env variable DISABLE_MAIL_OTP_LOGIN
+ // this variable is used to completely disable totp verification
+ EnvKeyDisableMailOTPLogin = "DISABLE_MAIL_OTP_LOGIN"
// EnvKeyDisablePhoneVerification is key for env variable DISABLE_PHONE_VERIFICATION
// this variable is used to disable phone verification
EnvKeyDisablePhoneVerification = "DISABLE_PHONE_VERIFICATION"
diff --git a/server/env/env.go b/server/env/env.go
index 3f65cf2..46ae2f4 100644
--- a/server/env/env.go
+++ b/server/env/env.go
@@ -104,6 +104,8 @@ func InitAllEnv() error {
osDisableStrongPassword := os.Getenv(constants.EnvKeyDisableStrongPassword)
osEnforceMultiFactorAuthentication := os.Getenv(constants.EnvKeyEnforceMultiFactorAuthentication)
osDisableMultiFactorAuthentication := os.Getenv(constants.EnvKeyDisableMultiFactorAuthentication)
+ osDisableTOTPLogin := os.Getenv(constants.EnvKeyDisableTOTPLogin)
+ osDisableMailOTPLogin := os.Getenv(constants.EnvKeyDisableMailOTPLogin)
// phone verification var
osDisablePhoneVerification := os.Getenv(constants.EnvKeyDisablePhoneVerification)
osDisablePlayground := os.Getenv(constants.EnvKeyDisablePlayGround)
@@ -689,6 +691,7 @@ func InitAllEnv() error {
envData[constants.EnvKeyDisableEmailVerification] = true
envData[constants.EnvKeyDisableMagicLinkLogin] = true
envData[constants.EnvKeyIsEmailServiceEnabled] = false
+ envData[constants.EnvKeyDisableMailOTPLogin] = true
}
if envData[constants.EnvKeySmtpHost] != "" && envData[constants.EnvKeySmtpUsername] != "" && envData[constants.EnvKeySmtpPassword] != "" && envData[constants.EnvKeySenderEmail] != "" && envData[constants.EnvKeySmtpPort] != "" {
@@ -705,6 +708,7 @@ func InitAllEnv() error {
if envData[constants.EnvKeyDisableEmailVerification].(bool) {
envData[constants.EnvKeyDisableMagicLinkLogin] = true
+ envData[constants.EnvKeyDisableMailOTPLogin] = true
}
if val, ok := envData[constants.EnvKeyAllowedOrigins]; !ok || val == "" {
@@ -840,6 +844,47 @@ func InitAllEnv() error {
}
}
+ if _, ok := envData[constants.EnvKeyDisableTOTPLogin]; !ok {
+ envData[constants.EnvKeyDisableTOTPLogin] = osDisableTOTPLogin == "false"
+ }
+ if osDisableTOTPLogin != "" {
+ boolValue, err := strconv.ParseBool(osDisableTOTPLogin)
+ if err != nil {
+ return err
+ }
+ if boolValue != envData[constants.EnvKeyDisableTOTPLogin].(bool) {
+ envData[constants.EnvKeyDisableTOTPLogin] = boolValue
+ }
+ }
+
+ if _, ok := envData[constants.EnvKeyDisableMailOTPLogin]; !ok {
+ envData[constants.EnvKeyDisableMailOTPLogin] = osDisableMailOTPLogin == "true"
+ }
+ if osDisableMailOTPLogin != "" {
+ boolValue, err := strconv.ParseBool(osDisableMailOTPLogin)
+ if err != nil {
+ return err
+ }
+ if boolValue != envData[constants.EnvKeyDisableMailOTPLogin].(bool) {
+ envData[constants.EnvKeyDisableMailOTPLogin] = boolValue
+ }
+ }
+
+ if envData[constants.EnvKeyDisableTOTPLogin] == false && envData[constants.EnvKeyDisableMailOTPLogin].(bool) == false {
+ errors.New("can't enable both mfa")
+ }
+
+ if envData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) {
+ envData[constants.EnvKeyDisableTOTPLogin] = true
+ envData[constants.EnvKeyDisableMailOTPLogin] = true
+ } else {
+ if !envData[constants.EnvKeyDisableMailOTPLogin].(bool) && !envData[constants.EnvKeyDisableTOTPLogin].(bool) {
+ errors.New("can't enable both mfa methods at same time")
+ envData[constants.EnvKeyDisableMailOTPLogin] = false
+ envData[constants.EnvKeyDisableTOTPLogin] = true
+ }
+ }
+
err = memorystore.Provider.UpdateEnvStore(envData)
if err != nil {
log.Debug("Error while updating env store: ", err)
diff --git a/server/env/persist_env.go b/server/env/persist_env.go
index eb0b64f..56142c5 100644
--- a/server/env/persist_env.go
+++ b/server/env/persist_env.go
@@ -196,7 +196,7 @@ func PersistEnv() error {
envValue := strings.TrimSpace(os.Getenv(key))
if envValue != "" {
switch key {
- case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround:
+ case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyIsSMSServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure, constants.EnvKeyDisablePhoneVerification, constants.EnvKeyDisablePlayGround, constants.EnvKeyDisableTOTPLogin, constants.EnvKeyDisableMailOTPLogin:
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
if value.(bool) != envValueBool {
storeData[key] = envValueBool
@@ -227,6 +227,11 @@ func PersistEnv() error {
storeData[constants.EnvKeyDisableMagicLinkLogin] = true
hasChanged = true
}
+
+ if !storeData[constants.EnvKeyDisableMailOTPLogin].(bool) {
+ storeData[constants.EnvKeyDisableMailOTPLogin] = true
+ hasChanged = true
+ }
}
err = memorystore.Provider.UpdateEnvStore(storeData)
diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go
index 84523cc..2694bc5 100644
--- a/server/graph/generated/generated.go
+++ b/server/graph/generated/generated.go
@@ -97,11 +97,13 @@ type ComplexityRoot struct {
DisableEmailVerification func(childComplexity int) int
DisableLoginPage func(childComplexity int) int
DisableMagicLinkLogin func(childComplexity int) int
+ DisableMailOtpLogin func(childComplexity int) int
DisableMultiFactorAuthentication func(childComplexity int) int
DisablePlayground func(childComplexity int) int
DisableRedisForEnv func(childComplexity int) int
DisableSignUp func(childComplexity int) int
DisableStrongPassword func(childComplexity int) int
+ DisableTotpLogin func(childComplexity int) int
EnforceMultiFactorAuthentication func(childComplexity int) int
FacebookClientID func(childComplexity int) int
FacebookClientSecret func(childComplexity int) int
@@ -699,6 +701,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Env.DisableMagicLinkLogin(childComplexity), true
+ case "Env.DISABLE_MAIL_OTP_LOGIN":
+ if e.complexity.Env.DisableMailOtpLogin == nil {
+ break
+ }
+
+ return e.complexity.Env.DisableMailOtpLogin(childComplexity), true
+
case "Env.DISABLE_MULTI_FACTOR_AUTHENTICATION":
if e.complexity.Env.DisableMultiFactorAuthentication == nil {
break
@@ -734,6 +743,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Env.DisableStrongPassword(childComplexity), true
+ case "Env.DISABLE_TOTP_LOGIN":
+ if e.complexity.Env.DisableTotpLogin == nil {
+ break
+ }
+
+ return e.complexity.Env.DisableTotpLogin(childComplexity), true
+
case "Env.ENFORCE_MULTI_FACTOR_AUTHENTICATION":
if e.complexity.Env.EnforceMultiFactorAuthentication == nil {
break
@@ -2384,6 +2400,8 @@ type Env {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
DISABLE_PLAYGROUND: Boolean!
+ DISABLE_MAIL_OTP_LOGIN: Boolean!
+ DISABLE_TOTP_LOGIN: Boolean!
}
type ValidateJWTTokenResponse {
@@ -2507,6 +2525,8 @@ input UpdateEnvInput {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
DISABLE_PLAYGROUND: Boolean
+ DISABLE_MAIL_OTP_LOGIN: Boolean
+ DISABLE_TOTP_LOGIN: Boolean
}
input AdminLoginInput {
@@ -6895,6 +6915,94 @@ func (ec *executionContext) fieldContext_Env_DISABLE_PLAYGROUND(ctx context.Cont
return fc, nil
}
+func (ec *executionContext) _Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableMailOtpLogin, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Env",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Env_DISABLE_TOTP_LOGIN(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DisableTotpLogin, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Env_DISABLE_TOTP_LOGIN(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Env",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Error_message(ctx context.Context, field graphql.CollectedField, obj *model.Error) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Error_message(ctx, field)
if err != nil {
@@ -10810,6 +10918,10 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
return ec.fieldContext_Env_DEFAULT_AUTHORIZE_RESPONSE_MODE(ctx, field)
case "DISABLE_PLAYGROUND":
return ec.fieldContext_Env_DISABLE_PLAYGROUND(ctx, field)
+ case "DISABLE_MAIL_OTP_LOGIN":
+ return ec.fieldContext_Env_DISABLE_MAIL_OTP_LOGIN(ctx, field)
+ case "DISABLE_TOTP_LOGIN":
+ return ec.fieldContext_Env_DISABLE_TOTP_LOGIN(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Env", field.Name)
},
@@ -17196,7 +17308,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
asMap[k] = v
}
- fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND"}
+ fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -17627,6 +17739,22 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
if err != nil {
return it, err
}
+ case "DISABLE_MAIL_OTP_LOGIN":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_MAIL_OTP_LOGIN"))
+ it.DisableMailOtpLogin, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ case "DISABLE_TOTP_LOGIN":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("DISABLE_TOTP_LOGIN"))
+ it.DisableTotpLogin, err = ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
}
}
@@ -18625,6 +18753,20 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._Env_DISABLE_PLAYGROUND(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "DISABLE_MAIL_OTP_LOGIN":
+
+ out.Values[i] = ec._Env_DISABLE_MAIL_OTP_LOGIN(ctx, field, obj)
+
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ case "DISABLE_TOTP_LOGIN":
+
+ out.Values[i] = ec._Env_DISABLE_TOTP_LOGIN(ctx, field, obj)
+
if out.Values[i] == graphql.Null {
invalids++
}
diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go
index 49adb71..7430472 100644
--- a/server/graph/model/models_gen.go
+++ b/server/graph/model/models_gen.go
@@ -123,6 +123,8 @@ type Env struct {
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
DisablePlayground bool `json:"DISABLE_PLAYGROUND"`
+ DisableMailOtpLogin bool `json:"DISABLE_MAIL_OTP_LOGIN"`
+ DisableTotpLogin bool `json:"DISABLE_TOTP_LOGIN"`
}
type Error struct {
@@ -382,6 +384,8 @@ type UpdateEnvInput struct {
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE"`
DefaultAuthorizeResponseMode *string `json:"DEFAULT_AUTHORIZE_RESPONSE_MODE"`
DisablePlayground *bool `json:"DISABLE_PLAYGROUND"`
+ DisableMailOtpLogin *bool `json:"DISABLE_MAIL_OTP_LOGIN"`
+ DisableTotpLogin *bool `json:"DISABLE_TOTP_LOGIN"`
}
type UpdateProfileInput struct {
diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls
index 44a90ba..433144a 100644
--- a/server/graph/schema.graphqls
+++ b/server/graph/schema.graphqls
@@ -174,6 +174,8 @@ type Env {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
DISABLE_PLAYGROUND: Boolean!
+ DISABLE_MAIL_OTP_LOGIN: Boolean!
+ DISABLE_TOTP_LOGIN: Boolean!
}
type ValidateJWTTokenResponse {
@@ -297,6 +299,8 @@ input UpdateEnvInput {
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
DEFAULT_AUTHORIZE_RESPONSE_MODE: String
DISABLE_PLAYGROUND: Boolean
+ DISABLE_MAIL_OTP_LOGIN: Boolean
+ DISABLE_TOTP_LOGIN: Boolean
}
input AdminLoginInput {
diff --git a/server/memorystore/memory_store.go b/server/memorystore/memory_store.go
index 4004d68..a143d04 100644
--- a/server/memorystore/memory_store.go
+++ b/server/memorystore/memory_store.go
@@ -36,9 +36,11 @@ func InitMemStore() error {
constants.EnvKeyIsSMSServiceEnabled: false,
constants.EnvKeyEnforceMultiFactorAuthentication: false,
constants.EnvKeyDisableMultiFactorAuthentication: false,
+ constants.EnvKeyDisableTOTPLogin: false,
constants.EnvKeyAppCookieSecure: true,
constants.EnvKeyAdminCookieSecure: true,
constants.EnvKeyDisablePlayGround: true,
+ constants.EnvKeyDisableMailOTPLogin: true,
}
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
diff --git a/server/memorystore/providers/redis/store.go b/server/memorystore/providers/redis/store.go
index d761ce1..a1b21db 100644
--- a/server/memorystore/providers/redis/store.go
+++ b/server/memorystore/providers/redis/store.go
@@ -176,7 +176,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
return nil, err
}
for key, value := range data {
- if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyIsSMSServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure || key == constants.EnvKeyDisablePlayGround {
+ if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyIsSMSServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure || key == constants.EnvKeyDisablePlayGround || key == constants.EnvKeyDisableTOTPLogin || key == constants.EnvKeyDisableMailOTPLogin {
boolValue, err := strconv.ParseBool(value)
if err != nil {
return res, err
diff --git a/server/resolvers/env.go b/server/resolvers/env.go
index b7a949a..5eb86bd 100644
--- a/server/resolvers/env.go
+++ b/server/resolvers/env.go
@@ -203,6 +203,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
res.AdminCookieSecure = store[constants.EnvKeyAdminCookieSecure].(bool)
res.AppCookieSecure = store[constants.EnvKeyAppCookieSecure].(bool)
res.DisablePlayground = store[constants.EnvKeyDisablePlayGround].(bool)
+ res.DisableMailOtpLogin = store[constants.EnvKeyDisableMailOTPLogin].(bool)
+ res.DisableTotpLogin = store[constants.EnvKeyDisableTOTPLogin].(bool)
return res, nil
}
diff --git a/server/resolvers/login.go b/server/resolvers/login.go
index bc1f3d9..1472697 100644
--- a/server/resolvers/login.go
+++ b/server/resolvers/login.go
@@ -110,8 +110,18 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
log.Debug("MFA service not enabled: ", err)
}
+ isTOTPLoginDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableTOTPLogin)
+ if err != nil || !isTOTPLoginDisabled {
+ log.Debug("totp service not enabled: ", err)
+ }
+
+ isMailOTPDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMailOTPLogin)
+ if err != nil || !isMailOTPDisabled {
+ log.Debug("mail OTP service not enabled: ", err)
+ }
+
// If email service is not enabled continue the process in any way
- if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled {
+ if refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isMailOTPDisabled && !isMFADisabled {
otp := utils.GenerateOTP()
expires := time.Now().Add(1 * time.Minute).Unix()
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
@@ -150,14 +160,16 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
}, nil
}
- if !isMFADisabled && refs.BoolValue(user.IsMultiFactorAuthEnabled) {
+ if !isMFADisabled && refs.BoolValue(user.IsMultiFactorAuthEnabled) && !isTOTPLoginDisabled {
if user.TotpSecret == nil {
base64URL, err := db.Provider.GenerateTotp(ctx, user.ID)
if err != nil {
log.Debug("error while generating base64 url: ", err)
}
res.TotpBase64url = base64URL
+
}
+
}
code := ""
diff --git a/server/resolvers/update_env.go b/server/resolvers/update_env.go
index 96388aa..6b3fe0e 100644
--- a/server/resolvers/update_env.go
+++ b/server/resolvers/update_env.go
@@ -263,6 +263,17 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
}
}
+ if updatedData[constants.EnvKeyDisableMultiFactorAuthentication].(bool) {
+ updatedData[constants.EnvKeyDisableTOTPLogin] = true
+ updatedData[constants.EnvKeyDisableMailOTPLogin] = true
+ } else {
+ if !updatedData[constants.EnvKeyDisableMailOTPLogin].(bool) && !updatedData[constants.EnvKeyDisableTOTPLogin].(bool) {
+ errors.New("can't enable both mfa methods at same time")
+ updatedData[constants.EnvKeyDisableMailOTPLogin] = true
+ updatedData[constants.EnvKeyDisableTOTPLogin] = false
+ }
+ }
+
if updatedData[constants.EnvKeySmtpHost] != "" || updatedData[constants.EnvKeySmtpUsername] != "" || updatedData[constants.EnvKeySmtpPassword] != "" || updatedData[constants.EnvKeySenderEmail] != "" && updatedData[constants.EnvKeySmtpPort] != "" {
updatedData[constants.EnvKeyIsEmailServiceEnabled] = true
}