精简: 去掉 LDAP(目录登录+用户同步): util/ldap 包、同步 job、登录分支、全部 ldap* 设置

This commit is contained in:
Muse
2026-10-20 10:04:28 +00:00
parent f9b0672d84
commit 7ece6e079b
11 changed files with 114 additions and 947 deletions
-156
View File
@@ -1,156 +0,0 @@
package ldaputil
import (
"crypto/tls"
"fmt"
"slices"
"github.com/go-ldap/ldap/v3"
)
type Config struct {
Host string
Port int
UseTLS bool
InsecureSkipVerify bool
BindDN string
Password string
BaseDN string
UserFilter string
UserAttr string
FlagField string
TruthyVals []string
Invert bool
}
func tlsConfig(cfg Config) *tls.Config {
return &tls.Config{InsecureSkipVerify: cfg.InsecureSkipVerify}
}
// FetchVlessFlags returns map[email]enabled
func FetchVlessFlags(cfg Config) (map[string]bool, error) {
addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
scheme := "ldap"
if cfg.UseTLS {
scheme = "ldaps"
}
ldapURL := fmt.Sprintf("%s://%s", scheme, addr)
var opts []ldap.DialOpt
if cfg.UseTLS {
opts = append(opts, ldap.DialWithTLSConfig(tlsConfig(cfg)))
}
conn, err := ldap.DialURL(ldapURL, opts...)
if err != nil {
return nil, err
}
defer conn.Close()
if cfg.BindDN != "" {
if err := conn.Bind(cfg.BindDN, cfg.Password); err != nil {
return nil, err
}
}
if cfg.UserFilter == "" {
cfg.UserFilter = "(objectClass=person)"
}
if cfg.UserAttr == "" {
cfg.UserAttr = "mail"
}
// if field not set we fallback to legacy vless_enabled
if cfg.FlagField == "" {
cfg.FlagField = "vless_enabled"
}
req := ldap.NewSearchRequest(
cfg.BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
cfg.UserFilter,
[]string{cfg.UserAttr, cfg.FlagField},
nil,
)
res, err := conn.Search(req)
if err != nil {
return nil, err
}
result := make(map[string]bool, len(res.Entries))
for _, e := range res.Entries {
user := e.GetAttributeValue(cfg.UserAttr)
if user == "" {
continue
}
val := e.GetAttributeValue(cfg.FlagField)
enabled := slices.Contains(cfg.TruthyVals, val)
if cfg.Invert {
enabled = !enabled
}
result[user] = enabled
}
return result, nil
}
// AuthenticateUser searches user by cfg.UserAttr and attempts to bind with provided password.
func AuthenticateUser(cfg Config, username, password string) (bool, error) {
addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
scheme := "ldap"
if cfg.UseTLS {
scheme = "ldaps"
}
ldapURL := fmt.Sprintf("%s://%s", scheme, addr)
var opts []ldap.DialOpt
if cfg.UseTLS {
opts = append(opts, ldap.DialWithTLSConfig(tlsConfig(cfg)))
}
conn, err := ldap.DialURL(ldapURL, opts...)
if err != nil {
return false, err
}
defer conn.Close()
// Optional initial bind for search
if cfg.BindDN != "" {
if err := conn.Bind(cfg.BindDN, cfg.Password); err != nil {
return false, err
}
}
if cfg.UserFilter == "" {
cfg.UserFilter = "(objectClass=person)"
}
if cfg.UserAttr == "" {
cfg.UserAttr = "uid"
}
// Build filter to find specific user
filter := fmt.Sprintf("(&%s(%s=%s))", cfg.UserFilter, cfg.UserAttr, ldap.EscapeFilter(username))
req := ldap.NewSearchRequest(
cfg.BaseDN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 1, 0, false,
filter,
[]string{"dn"},
nil,
)
res, err := conn.Search(req)
if err != nil {
return false, err
}
if len(res.Entries) == 0 {
return false, nil
}
userDN := res.Entries[0].DN
// Try to bind as the user
if err := conn.Bind(userDN, password); err != nil {
return false, nil
}
return true, nil
}
-22
View File
@@ -1,22 +0,0 @@
package ldaputil
import "testing"
func TestTLSConfig_InsecureSkipVerifyPropagates(t *testing.T) {
cases := []struct {
name string
skip bool
want bool
}{
{"default verifies", false, false},
{"skip flows through", true, true},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got := tlsConfig(Config{InsecureSkipVerify: c.skip})
if got.InsecureSkipVerify != c.want {
t.Fatalf("InsecureSkipVerify = %v, want %v", got.InsecureSkipVerify, c.want)
}
})
}
}