1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-17 14:37:02 +00:00

trace: Use request tracing in auth and domaininfo

This patch adds tracing for the auth and domaininfo modules. In the
latter, we replace the long-running event with the short-term request
tracing, which is more practical and useful.

There are no logic changes, it only adds tracing instrumentation to help
troubleshooting.
This commit is contained in:
Alberto Bertogli
2021-06-05 18:31:55 +01:00
parent a3685439dc
commit b9f147fa8b
2 changed files with 48 additions and 14 deletions

View File

@@ -11,6 +11,7 @@ import (
"time" "time"
"blitiri.com.ar/go/chasquid/internal/normalize" "blitiri.com.ar/go/chasquid/internal/normalize"
"blitiri.com.ar/go/chasquid/internal/trace"
) )
// Backend is the common interface for all authentication backends. // Backend is the common interface for all authentication backends.
@@ -65,6 +66,9 @@ func (a *Authenticator) Register(domain string, be Backend) {
// Authenticate the user@domain with the given password. // Authenticate the user@domain with the given password.
func (a *Authenticator) Authenticate(user, domain, password string) (bool, error) { func (a *Authenticator) Authenticate(user, domain, password string) (bool, error) {
tr := trace.New("Auth.Authenticate", user+"@"+domain)
defer tr.Finish()
// Make sure the call takes a.AuthDuration + 0-20% regardless of the // Make sure the call takes a.AuthDuration + 0-20% regardless of the
// outcome, to prevent basic timing attacks. // outcome, to prevent basic timing attacks.
defer func(start time.Time) { defer func(start time.Time) {
@@ -79,31 +83,42 @@ func (a *Authenticator) Authenticate(user, domain, password string) (bool, error
if be, ok := a.backends[domain]; ok { if be, ok := a.backends[domain]; ok {
ok, err := be.Authenticate(user, password) ok, err := be.Authenticate(user, password)
tr.Debugf("Backend: %v %v", ok, err)
if ok || err != nil { if ok || err != nil {
return ok, err return ok, err
} }
} }
if a.Fallback != nil { if a.Fallback != nil {
return a.Fallback.Authenticate(user+"@"+domain, password) ok, err := a.Fallback.Authenticate(user+"@"+domain, password)
tr.Debugf("Fallback: %v %v", ok, err)
return ok, err
} }
tr.Debugf("Rejected by default")
return false, nil return false, nil
} }
// Exists checks that user@domain exists. // Exists checks that user@domain exists.
func (a *Authenticator) Exists(user, domain string) (bool, error) { func (a *Authenticator) Exists(user, domain string) (bool, error) {
tr := trace.New("Auth.Exists", user+"@"+domain)
defer tr.Finish()
if be, ok := a.backends[domain]; ok { if be, ok := a.backends[domain]; ok {
ok, err := be.Exists(user) ok, err := be.Exists(user)
tr.Debugf("Backend: %v %v", ok, err)
if ok || err != nil { if ok || err != nil {
return ok, err return ok, err
} }
} }
if a.Fallback != nil { if a.Fallback != nil {
return a.Fallback.Exists(user + "@" + domain) ok, err := a.Fallback.Exists(user + "@" + domain)
tr.Debugf("Fallback: %v %v", ok, err)
return ok, err
} }
tr.Debugf("Rejected by default")
return false, nil return false, nil
} }
@@ -112,16 +127,22 @@ func (a *Authenticator) Reload() error {
msgs := []string{} msgs := []string{}
for domain, be := range a.backends { for domain, be := range a.backends {
tr := trace.New("Auth.Reload", domain)
err := be.Reload() err := be.Reload()
if err != nil { if err != nil {
tr.Error(err)
msgs = append(msgs, fmt.Sprintf("%q: %v", domain, err)) msgs = append(msgs, fmt.Sprintf("%q: %v", domain, err))
} }
tr.Finish()
} }
if a.Fallback != nil { if a.Fallback != nil {
tr := trace.New("Auth.Reload", "<fallback>")
err := a.Fallback.Reload() err := a.Fallback.Reload()
if err != nil { if err != nil {
tr.Error(err)
msgs = append(msgs, fmt.Sprintf("<fallback>: %v", err)) msgs = append(msgs, fmt.Sprintf("<fallback>: %v", err))
} }
tr.Finish()
} }
if len(msgs) > 0 { if len(msgs) > 0 {

View File

@@ -20,8 +20,6 @@ type DB struct {
info map[string]*Domain info map[string]*Domain
sync.Mutex sync.Mutex
ev *trace.EventLog
} }
// New opens a domain information database on the given dir, creating it if // New opens a domain information database on the given dir, creating it if
@@ -36,7 +34,6 @@ func New(dir string) (*DB, error) {
store: st, store: st,
info: map[string]*Domain{}, info: map[string]*Domain{},
} }
l.ev = trace.NewEventLog("DomainInfo", dir)
err = l.Reload() err = l.Reload()
if err != nil { if err != nil {
@@ -48,6 +45,9 @@ func New(dir string) (*DB, error) {
// Reload the database from disk. // Reload the database from disk.
func (db *DB) Reload() error { func (db *DB) Reload() error {
tr := trace.New("DomainInfo.Reload", "reload")
defer tr.Finish()
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
@@ -56,6 +56,7 @@ func (db *DB) Reload() error {
ids, err := db.store.ListIDs() ids, err := db.store.ListIDs()
if err != nil { if err != nil {
tr.Error(err)
return err return err
} }
@@ -63,28 +64,36 @@ func (db *DB) Reload() error {
d := &Domain{} d := &Domain{}
_, err := db.store.Get(id, d) _, err := db.store.Get(id, d)
if err != nil { if err != nil {
tr.Errorf("id %q: %v", id, err)
return fmt.Errorf("error loading %q: %v", id, err) return fmt.Errorf("error loading %q: %v", id, err)
} }
db.info[d.Name] = d db.info[d.Name] = d
} }
db.ev.Debugf("loaded %d domains", len(ids)) tr.Debugf("loaded %d domains", len(ids))
return nil return nil
} }
func (db *DB) write(d *Domain) { func (db *DB) write(d *Domain) {
tr := trace.New("DomainInfo.write", d.Name)
defer tr.Finish()
err := db.store.Put(d.Name, d) err := db.store.Put(d.Name, d)
if err != nil { if err != nil {
db.ev.Errorf("%s error saving: %v", d.Name, err) tr.Error(err)
} else { } else {
db.ev.Debugf("%s saved", d.Name) tr.Debugf("saved")
} }
} }
// IncomingSecLevel checks an incoming security level for the domain. // IncomingSecLevel checks an incoming security level for the domain.
// Returns true if allowed, false otherwise. // Returns true if allowed, false otherwise.
func (db *DB) IncomingSecLevel(domain string, level SecLevel) bool { func (db *DB) IncomingSecLevel(domain string, level SecLevel) bool {
tr := trace.New("DomainInfo.Incoming", domain)
defer tr.Finish()
tr.Debugf("incoming at level %s", level)
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
@@ -96,15 +105,15 @@ func (db *DB) IncomingSecLevel(domain string, level SecLevel) bool {
} }
if level < d.IncomingSecLevel { if level < d.IncomingSecLevel {
db.ev.Errorf("%s incoming denied: %s < %s", tr.Errorf("%s incoming denied: %s < %s",
d.Name, level, d.IncomingSecLevel) d.Name, level, d.IncomingSecLevel)
return false return false
} else if level == d.IncomingSecLevel { } else if level == d.IncomingSecLevel {
db.ev.Debugf("%s incoming allowed: %s == %s", tr.Debugf("%s incoming allowed: %s == %s",
d.Name, level, d.IncomingSecLevel) d.Name, level, d.IncomingSecLevel)
return true return true
} else { } else {
db.ev.Printf("%s incoming level raised: %s > %s", tr.Printf("%s incoming level raised: %s > %s",
d.Name, level, d.IncomingSecLevel) d.Name, level, d.IncomingSecLevel)
d.IncomingSecLevel = level d.IncomingSecLevel = level
if exists { if exists {
@@ -117,6 +126,10 @@ func (db *DB) IncomingSecLevel(domain string, level SecLevel) bool {
// OutgoingSecLevel checks an incoming security level for the domain. // OutgoingSecLevel checks an incoming security level for the domain.
// Returns true if allowed, false otherwise. // Returns true if allowed, false otherwise.
func (db *DB) OutgoingSecLevel(domain string, level SecLevel) bool { func (db *DB) OutgoingSecLevel(domain string, level SecLevel) bool {
tr := trace.New("DomainInfo.Outgoing", domain)
defer tr.Finish()
tr.Debugf("outgoing at level %s", level)
db.Lock() db.Lock()
defer db.Unlock() defer db.Unlock()
@@ -128,15 +141,15 @@ func (db *DB) OutgoingSecLevel(domain string, level SecLevel) bool {
} }
if level < d.OutgoingSecLevel { if level < d.OutgoingSecLevel {
db.ev.Errorf("%s outgoing denied: %s < %s", tr.Errorf("%s outgoing denied: %s < %s",
d.Name, level, d.OutgoingSecLevel) d.Name, level, d.OutgoingSecLevel)
return false return false
} else if level == d.OutgoingSecLevel { } else if level == d.OutgoingSecLevel {
db.ev.Debugf("%s outgoing allowed: %s == %s", tr.Debugf("%s outgoing allowed: %s == %s",
d.Name, level, d.OutgoingSecLevel) d.Name, level, d.OutgoingSecLevel)
return true return true
} else { } else {
db.ev.Printf("%s outgoing level raised: %s > %s", tr.Printf("%s outgoing level raised: %s > %s",
d.Name, level, d.OutgoingSecLevel) d.Name, level, d.OutgoingSecLevel)
d.OutgoingSecLevel = level d.OutgoingSecLevel = level
if exists { if exists {