providers/radius: TOTP MFA support (#7217)

* move CheckPasswordMFA to flow executor

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add mfa support field to radius

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L
2023-10-18 19:43:36 +02:00
committed by GitHub
parent 3c734da86a
commit 8aafa06259
11 changed files with 145 additions and 50 deletions

View File

@ -2,9 +2,6 @@ package direct
import (
"context"
"regexp"
"strconv"
"strings"
"beryju.io/ldap"
"github.com/getsentry/sentry-go"
@ -16,10 +13,6 @@ import (
"goauthentik.io/internal/outpost/ldap/metrics"
)
const CodePasswordSeparator = ";"
var alphaNum = regexp.MustCompile(`^[a-zA-Z0-9]*$`)
func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResultCode, error) {
fe := flow.NewFlowExecutor(req.Context(), db.si.GetAuthenticationFlowSlug(), db.si.GetAPIClient().GetConfig(), log.Fields{
"bindDN": req.BindDN,
@ -31,7 +24,9 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul
fe.Answers[flow.StageIdentification] = username
fe.Answers[flow.StagePassword] = req.BindPW
db.CheckPasswordMFA(fe)
if db.si.GetMFASupport() {
fe.CheckPasswordInlineMFA()
}
passed, err := fe.Execute()
flags := flags.UserFlags{
@ -141,41 +136,3 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul
uisp.Finish()
return ldap.LDAPResultSuccess, nil
}
func (db *DirectBinder) CheckPasswordMFA(fe *flow.FlowExecutor) {
if !db.si.GetMFASupport() {
return
}
password := fe.Answers[flow.StagePassword]
// We already have an authenticator answer
if fe.Answers[flow.StageAuthenticatorValidate] != "" {
return
}
// password doesn't contain the separator
if !strings.Contains(password, CodePasswordSeparator) {
return
}
// 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
}
} 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[flow.StagePassword] = password[:idx]
fe.Answers[flow.StageAuthenticatorValidate] = authenticator
}