also unicode-normalize usernames (email addresses) when logging into the imapserver and webapps

and don't do needless normalization for the username we got from scram: the
scram package would have failed if the name wasn't already normalized.

unicode may not be specified for sasl with imap (i'm not sure), but there's no
point in accepting it over smtpserver but not in imapserver.
This commit is contained in:
Mechiel Lukkien 2025-02-06 15:37:33 +01:00
parent 7b3ebb2647
commit c7354cc22b
No known key found for this signature in database
3 changed files with 11 additions and 7 deletions

View File

@ -60,6 +60,7 @@ import (
"time"
"golang.org/x/exp/maps"
"golang.org/x/text/unicode/norm"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
@ -1921,8 +1922,8 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) {
if len(plain) != 3 {
xsyntaxErrorf("bad plain auth data, expected 3 nul-separated tokens, got %d tokens", len(plain))
}
authz := string(plain[0])
username = string(plain[1])
authz := norm.NFC.String(string(plain[0]))
username = norm.NFC.String(string(plain[1]))
password := string(plain[2])
c.loginAttempt.LoginAddress = username
@ -1956,7 +1957,7 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) {
if len(t) != 2 || len(t[1]) != 2*md5.Size {
xsyntaxErrorf("malformed cram-md5 response")
}
username = t[0]
username = norm.NFC.String(t[0])
c.loginAttempt.LoginAddress = username
c.log.Debug("cram-md5 auth", slog.String("address", username))
var err error
@ -2110,7 +2111,7 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) {
// ../rfc/4422:1618
buf := xreadInitial()
username = string(buf)
username = norm.NFC.String(string(buf))
c.loginAttempt.LoginAddress = username
if !c.tls {
@ -2201,7 +2202,7 @@ func (c *conn) cmdLogin(tag, cmd string, p *parser) {
// Request syntax: ../rfc/9051:6667 ../rfc/3501:4804
p.xspace()
username := p.xastring()
username := norm.NFC.String(p.xastring())
c.loginAttempt.LoginAddress = username
p.xspace()
password := p.xastring()

View File

@ -1544,7 +1544,7 @@ func (c *conn) cmdAuth(p *parser) {
c.log.Infox("scram protocol error", err, slog.Any("remote", c.remoteIP))
xsmtpUserErrorf(smtp.C455BadParams, smtp.SePol7Other0, "scram protocol error: %s", err)
}
username = norm.NFC.String(ss.Authentication)
username = ss.Authentication
la.LoginAddress = username
c.log.Debug("scram auth", slog.String("authentication", username))
account, la.AccountName, _, err = store.OpenEmail(c.log, username, false)
@ -1620,7 +1620,7 @@ func (c *conn) cmdAuth(p *parser) {
// ../rfc/4422:1618
buf := xreadInitial("")
username = string(buf)
username = norm.NFC.String(string(buf))
la.LoginAddress = username
if !c.tls {

View File

@ -45,6 +45,8 @@ import (
"strings"
"time"
"golang.org/x/text/unicode/norm"
"github.com/mjl-/sherpa"
"github.com/mjl-/mox/metrics"
@ -266,6 +268,7 @@ func Login(ctx context.Context, log mlog.Log, sessionAuth SessionAuth, kind, coo
return "", &sherpa.Error{Code: "user:error", Message: "too many authentication attempts"}
}
username = norm.NFC.String(username)
valid, disabled, accountName, err := sessionAuth.login(ctx, log, username, password)
la := loginAttempt(r, kind, "weblogin")
la.LoginAddress = username