feat: improve MFA by using user's own Email and Phone (#2002)

* refactor: mfa

* fix: clean code

* fix: clean code

* fix: fix crash and improve robot
This commit is contained in:
Yaodong Yu
2023-06-21 18:56:37 +08:00
committed by GitHub
parent 6ebca6dbe7
commit c391af4552
28 changed files with 528 additions and 362 deletions

View File

@ -370,6 +370,7 @@ func (c *ApiController) GetAccount() {
user.Permissions = object.GetMaskedPermissions(user.Permissions)
user.Roles = object.GetMaskedRoles(user.Roles)
user.MultiFactorAuths = object.GetAllMfaProps(user, true)
organization, err := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
if err != nil {

View File

@ -71,7 +71,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
if form.Password != "" && user.IsMfaEnabled() {
c.setMfaSessionData(&object.MfaSessionData{UserId: userId})
resp = &Response{Status: object.NextMfa, Data: user.GetPreferMfa(true)}
resp = &Response{Status: object.NextMfa, Data: user.GetPreferredMfaProps(true)}
return
}
@ -656,15 +656,20 @@ func (c *ApiController) Login() {
}
if authForm.Passcode != "" {
MfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferMfa(false))
err = MfaUtil.Verify(authForm.Passcode)
mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferredMfaProps(false))
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err = mfaUtil.Verify(authForm.Passcode)
if err != nil {
c.ResponseError(err.Error())
return
}
}
if authForm.RecoveryCode != "" {
err = object.RecoverTfs(user, authForm.RecoveryCode)
err = object.MfaRecover(user, authForm.RecoveryCode)
if err != nil {
c.ResponseError(err.Error())
return

View File

@ -177,6 +177,10 @@ func (c *ApiController) SetSessionData(s *SessionData) {
}
func (c *ApiController) setMfaSessionData(data *object.MfaSessionData) {
if data == nil {
c.SetSession(object.MfaSessionUserId, nil)
return
}
c.SetSession(object.MfaSessionUserId, data.UserId)
}

View File

@ -34,7 +34,7 @@ import (
func (c *ApiController) MfaSetupInitiate() {
owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name")
authType := c.Ctx.Request.Form.Get("type")
mfaType := c.Ctx.Request.Form.Get("mfaType")
userId := util.GetId(owner, name)
if len(userId) == 0 {
@ -42,10 +42,11 @@ func (c *ApiController) MfaSetupInitiate() {
return
}
MfaUtil := object.GetMfaUtil(authType, nil)
MfaUtil := object.GetMfaUtil(mfaType, nil)
if MfaUtil == nil {
c.ResponseError("Invalid auth type")
}
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
@ -79,16 +80,20 @@ func (c *ApiController) MfaSetupInitiate() {
// @Success 200 {object} Response object
// @router /mfa/setup/verify [post]
func (c *ApiController) MfaSetupVerify() {
authType := c.Ctx.Request.Form.Get("type")
mfaType := c.Ctx.Request.Form.Get("mfaType")
passcode := c.Ctx.Request.Form.Get("passcode")
if authType == "" || passcode == "" {
if mfaType == "" || passcode == "" {
c.ResponseError("missing auth type or passcode")
return
}
MfaUtil := object.GetMfaUtil(authType, nil)
mfaUtil := object.GetMfaUtil(mfaType, nil)
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err := MfaUtil.SetupVerify(c.Ctx, passcode)
err := mfaUtil.SetupVerify(c.Ctx, passcode)
if err != nil {
c.ResponseError(err.Error())
} else {
@ -108,7 +113,7 @@ func (c *ApiController) MfaSetupVerify() {
func (c *ApiController) MfaSetupEnable() {
owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name")
authType := c.Ctx.Request.Form.Get("type")
mfaType := c.Ctx.Request.Form.Get("mfaType")
user, err := object.GetUser(util.GetId(owner, name))
if err != nil {
@ -121,8 +126,13 @@ func (c *ApiController) MfaSetupEnable() {
return
}
twoFactor := object.GetMfaUtil(authType, nil)
err = twoFactor.Enable(c.Ctx, user)
mfaUtil := object.GetMfaUtil(mfaType, nil)
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err = mfaUtil.Enable(c.Ctx, user)
if err != nil {
c.ResponseError(err.Error())
return
@ -137,11 +147,9 @@ func (c *ApiController) MfaSetupEnable() {
// @Description: Delete MFA
// @param owner form string true "owner of user"
// @param name form string true "name of user"
// @param id form string true "id of user's MFA props"
// @Success 200 {object} Response object
// @router /delete-mfa/ [post]
func (c *ApiController) DeleteMfa() {
id := c.Ctx.Request.Form.Get("id")
owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name")
userId := util.GetId(owner, name)
@ -151,28 +159,18 @@ func (c *ApiController) DeleteMfa() {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError("User doesn't exist")
return
}
mfaProps := user.MultiFactorAuths[:0]
i := 0
for _, mfaProp := range mfaProps {
if mfaProp.Id != id {
mfaProps[i] = mfaProp
i++
}
}
user.MultiFactorAuths = mfaProps
_, err = object.UpdateUser(userId, user, []string{"multi_factor_auths"}, user.IsAdminUser())
err = object.DisabledMultiFactorAuth(user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(user.MultiFactorAuths)
c.ResponseOk(object.GetAllMfaProps(user, true))
}
// SetPreferredMfa
@ -185,7 +183,7 @@ func (c *ApiController) DeleteMfa() {
// @Success 200 {object} Response object
// @router /set-preferred-mfa [post]
func (c *ApiController) SetPreferredMfa() {
id := c.Ctx.Request.Form.Get("id")
mfaType := c.Ctx.Request.Form.Get("mfaType")
owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name")
userId := util.GetId(owner, name)
@ -195,29 +193,15 @@ func (c *ApiController) SetPreferredMfa() {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError("User doesn't exist")
return
}
mfaProps := user.MultiFactorAuths
for i, mfaProp := range user.MultiFactorAuths {
if mfaProp.Id == id {
mfaProps[i].IsPreferred = true
} else {
mfaProps[i].IsPreferred = false
}
}
_, err = object.UpdateUser(userId, user, []string{"multi_factor_auths"}, user.IsAdminUser())
err = object.SetPreferredMultiFactorAuth(user, mfaType)
if err != nil {
c.ResponseError(err.Error())
return
}
for i, mfaProp := range mfaProps {
mfaProps[i] = object.GetMaskedProps(mfaProp)
}
c.ResponseOk(mfaProps)
c.ResponseOk(object.GetAllMfaProps(user, true))
}

View File

@ -193,6 +193,7 @@ func (c *ApiController) GetUser() {
panic(err)
}
user.MultiFactorAuths = object.GetAllMfaProps(user, true)
err = object.ExtendUserWithRolesAndPermissions(user)
if err != nil {
panic(err)

View File

@ -93,9 +93,10 @@ func (c *ApiController) SendVerificationCode() {
}
}
// mfaSessionData != nil, means method is MfaSetupVerification
// mfaSessionData != nil, means method is MfaAuthVerification
if mfaSessionData := c.getMfaSessionData(); mfaSessionData != nil {
user, err = object.GetUser(mfaSessionData.UserId)
c.setMfaSessionData(nil)
if err != nil {
c.ResponseError(err.Error())
return
@ -129,7 +130,7 @@ func (c *ApiController) SendVerificationCode() {
} else if vform.Method == ResetVerification {
user = c.getCurrentUser()
} else if vform.Method == MfaAuthVerification {
mfaProps := user.GetPreferMfa(false)
mfaProps := user.GetPreferredMfaProps(false)
if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest {
vform.Dest = mfaProps.Secret
}
@ -157,12 +158,14 @@ func (c *ApiController) SendVerificationCode() {
}
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
} else if vform.Method == ResetVerification {
if user = c.getCurrentUser(); user != nil {
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
} else if vform.Method == ResetVerification || vform.Method == MfaSetupVerification {
if vform.CountryCode == "" {
if user = c.getCurrentUser(); user != nil {
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
}
}
} else if vform.Method == MfaAuthVerification {
mfaProps := user.GetPreferMfa(false)
mfaProps := user.GetPreferredMfaProps(false)
if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest {
vform.Dest = mfaProps.Secret
}