refactor CheckPasswordInlineMFA to SetSecrets

This commit is contained in:
Matthias G 2024-01-01 20:04:04 +01:00
parent cec021117c
commit 658b37c718
3 changed files with 34 additions and 39 deletions

View File

@ -10,39 +10,44 @@ const CodePasswordSeparator = ";"
var alphaNum = regexp.MustCompile(`^[a-zA-Z0-9]*$`) var alphaNum = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
// CheckPasswordInlineMFA For protocols that only support username/password, check if the password // SetSecrets sets the secret answers for the flow executor for protocols that only support username/password
// contains the TOTP code // acccording to used options
func (fe *FlowExecutor) CheckPasswordInlineMFA() { func (fe *FlowExecutor) SetSecrets(password string, mfacodebased bool) {
password := fe.Answers[StagePassword] if fe.Answers[StageAuthenticatorValidate] != "" || fe.Answers[StagePassword] != "" {
// We already have an authenticator answer
if fe.Answers[StageAuthenticatorValidate] != "" {
return return
} }
// password doesn't contain the separator fe.Answers[StagePassword] = password
if !strings.Contains(password, CodePasswordSeparator) { if mfacodebased {
return // password doesn't contain the separator
} if !strings.Contains(password, CodePasswordSeparator) {
// password ends with the separator, so it won't contain an answer
if strings.HasSuffix(password, CodePasswordSeparator) {
return
}
idx := strings.LastIndex(password, CodePasswordSeparator)
authenticator := password[idx+1:]
// Authenticator is either 6 chars (totp code) or 8 chars (long totp or static)
if len(authenticator) == 6 {
// authenticator answer isn't purely numerical, so won't be value
if _, err := strconv.Atoi(authenticator); err != nil {
return return
} }
} else if len(authenticator) == 8 { // password ends with the separator, so it won't contain an answer
// 8 chars can be a long totp or static token, so it needs to be alphanumerical if strings.HasSuffix(password, CodePasswordSeparator) {
if !alphaNum.MatchString(authenticator) {
return return
} }
idx := strings.LastIndex(password, CodePasswordSeparator)
authenticator := password[idx+1:]
// Authenticator is either 6 chars (totp code) or 8 chars (long totp or static)
if len(authenticator) == 6 {
// authenticator answer isn't purely numerical, so won't be value
if _, err := strconv.Atoi(authenticator); err != nil {
return
}
} else if len(authenticator) == 8 {
// 8 chars can be a long totp or static token, so it needs to be alphanumerical
if !alphaNum.MatchString(authenticator) {
return
}
} else {
// Any other length, doesn't contain an answer
return
}
fe.Answers[StagePassword] = password[:idx]
fe.Answers[StageAuthenticatorValidate] = authenticator
} else { } else {
// Any other length, doesn't contain an answer // If code-based MFA is disabled StageAuthenticatorValidate answer is set to password.
return // This allows flows with a mfa stage only.
fe.Answers[StageAuthenticatorValidate] = password
} }
fe.Answers[StagePassword] = password[:idx]
fe.Answers[StageAuthenticatorValidate] = authenticator
} }

View File

@ -23,10 +23,7 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul
fe.Params.Add("goauthentik.io/outpost/ldap", "true") fe.Params.Add("goauthentik.io/outpost/ldap", "true")
fe.Answers[flow.StageIdentification] = username fe.Answers[flow.StageIdentification] = username
fe.Answers[flow.StagePassword] = req.BindPW fe.SetSecrets(req.BindPW, db.si.GetMFASupport())
if db.si.GetMFASupport() {
fe.CheckPasswordInlineMFA()
}
passed, err := fe.Execute() passed, err := fe.Execute()
flags := flags.UserFlags{ flags := flags.UserFlags{

View File

@ -21,14 +21,7 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR
fe.Params.Add("goauthentik.io/outpost/radius", "true") fe.Params.Add("goauthentik.io/outpost/radius", "true")
fe.Answers[flow.StageIdentification] = username fe.Answers[flow.StageIdentification] = username
fe.Answers[flow.StagePassword] = rfc2865.UserPassword_GetString(r.Packet) fe.SetSecrets(rfc2865.UserPassword_GetString(r.Packet), r.pi.MFASupport)
if r.pi.MFASupport {
fe.CheckPasswordInlineMFA()
} else {
// If code-based MFA is disabled StageAuthenticatorValidate answer is set to StagePassword answer.
// This allows flows with only a mfa stage
fe.Answers[flow.StageAuthenticatorValidate] = fe.Answers[flow.StagePassword]
}
passed, err := fe.Execute() passed, err := fe.Execute()
if err != nil { if err != nil {