Compare commits

..

2 Commits

Author SHA1 Message Date
Chris F Ravenscroft c8e7a7e7e6 fix: use configHandler.Bind rather than helper.Bind in test harness 2026-07-18 14:44:15 -07:00
kanywst 2e125a4a2f fix: reject disabled users on all backends in Bind
A user with disabled = true could still bind on the config backend, since
configHandler.FindUser and LDAPOpsHelper.Bind never checked Disabled while the
SQL backends drop such users at lookup. Enforce it in Bind so every backend
behaves the same.
2026-07-19 00:10:27 +09:00
3 changed files with 76 additions and 1 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ Use it to centralize account management across your Linux servers, your OSX mach
### Contributing
- Please base all Pull Requests on [dev](https://github.com/glauth/glauth/tree/dev), not master.
- Format your code automatically using `gofmt -d ./` before committing
- Format your code autonmatically using `gofmt -d ./` before committing
### Quickstart
This quickstart is a great way to try out GLAuth in a non-production environment. *Be warned that you should take the extra steps to setup SSL (TLS) for production use!*
+69
View File
@@ -0,0 +1,69 @@
package handler
import (
"encoding/hex"
"net"
"testing"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace/noop"
"golang.org/x/crypto/bcrypt"
"github.com/glauth/glauth/v2/pkg/config"
"github.com/glauth/ldap"
)
type disabledBindTestMonitor struct{}
func (disabledBindTestMonitor) SetResponseTimeMetric(map[string]string, float64) error {
return nil
}
func (disabledBindTestMonitor) SetLDAPMetric(map[string]string, float64) error {
return nil
}
func TestConfigBackendDisabledUserCannotBind(t *testing.T) {
pw := "correct horse"
raw, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.MinCost)
if err != nil {
t.Fatal(err)
}
hexHash := hex.EncodeToString(raw)
cfg := &config.Config{}
cfg.Users = []config.User{
{Name: "activeuser", PrimaryGroup: 5501, PassBcrypt: hexHash, Disabled: false},
{Name: "disableduser", PrimaryGroup: 5501, PassBcrypt: hexHash, Disabled: true},
}
logger := zerolog.Nop()
tracer := noop.NewTracerProvider().Tracer("f001")
helper := NewLDAPOpsHelper(tracer)
h := configHandler{
backend: config.Backend{
BaseDN: "dc=example,dc=com",
NameFormatAsArray: []string{"cn"},
GroupFormatAsArray: []string{"ou"},
},
log: &logger,
cfg: cfg,
ldohelper: helper,
monitor: disabledBindTestMonitor{},
tracer: tracer,
}
_, server := net.Pipe()
defer server.Close()
bind := func(dn, pass string) ldap.LDAPResultCode {
code, _ := h.Bind(dn, pass, server)
return code
}
if code := bind("cn=activeuser,dc=example,dc=com", pw); code != ldap.LDAPResultSuccess {
t.Fatalf("active user with correct pw should bind, got %d", code)
}
if code := bind("cn=disableduser,dc=example,dc=com", pw); code != ldap.LDAPResultInvalidCredentials {
t.Errorf("disabled user must be rejected; got code %d, want InvalidCredentials(49)", code)
}
}
+6
View File
@@ -91,6 +91,12 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
return ldapcode, nil
}
// a disabled account must never authenticate, on any backend
if user.Disabled {
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("Bind attempt on disabled account")
return ldap.LDAPResultInvalidCredentials, nil
}
validotp := false
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {