Skip to content

Commit

Permalink
impl simple ldap backend
Browse files Browse the repository at this point in the history
  • Loading branch information
mrhaoxx committed May 2, 2024
1 parent 76ae8b7 commit 8fc325a
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 17 deletions.
14 changes: 0 additions & 14 deletions auth/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@ func (mgr *fileBackend) CheckSSHKey(ctx *ssh.Ctx, pubkey gossh.PublicKey) bool {
return false
}

func (mgr *fileBackend) SSHAuthPwd(ctx *ssh.Ctx, password []byte) bool {
usr, ok := mgr.usrs[ctx.User]
if !ok {
return false
}
if !usr.allowsshpwd {
return false
}
if usr.checkpwd(string(password)) {
return true
}
return false
}

func (mgr *fileBackend) CheckPassword(username string, password string) bool {
usr, ok := mgr.usrs[username]
if !ok {
Expand Down
129 changes: 128 additions & 1 deletion auth/ldap.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,137 @@
package auth

type ldapAuth struct {
import (
"crypto/tls"
"fmt"
"reflect"
"strings"
"sync"

"github.com/go-ldap/ldap/v3"
"github.com/mrhaoxx/OpenNG/ssh"
gossh "golang.org/x/crypto/ssh"
)

type ldapBackend struct {
url string
searchBase string

bindDN string
bindPW string

ldapQueryConnPool sync.Pool
}

func (backend *ldapBackend) tryGetQueryConn() *ldap.Conn {
conn, ok := backend.ldapQueryConnPool.Get().(*ldap.Conn)
if !ok {
return nil
}
for conn.IsClosing() {
if !ok {
return nil
}

conn, ok = backend.ldapQueryConnPool.Get().(*ldap.Conn)
}

return conn
}

func (backend *ldapBackend) CheckPassword(username string, password string) bool {

conn := backend.tryGetQueryConn()
defer backend.ldapQueryConnPool.Put(conn)

searchRequest := ldap.NewSearchRequest(
backend.searchBase,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=posixAccount)(uid="+username+"))",
[]string{"dn"},
nil,
)
if result, err := conn.Search(searchRequest); err == nil {
if len(result.Entries) != 1 {
return false
}

try, err := ldap.DialURL(backend.url, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
if err != nil {
return false
}
defer try.Close()

return try.Bind(result.Entries[0].DN, password) == nil

}
return false
}

func (backend *ldapBackend) CheckSSHKey(ctx *ssh.Ctx, pubkey gossh.PublicKey) bool {

if strings.ContainsAny(ctx.User, "\" ',=+<>#:;\\()") {
return false
}

conn := backend.tryGetQueryConn()
defer backend.ldapQueryConnPool.Put(conn)

searchRequest := ldap.NewSearchRequest(
backend.searchBase,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=posixAccount)(uid="+ctx.User+"))",
[]string{"sshPublicKey"},
nil,
)
if result, err := conn.Search(searchRequest); err == nil {
if len(result.Entries) != 1 {
return false
}

for _, attr := range result.Entries[0].Attributes {
if attr.Name != "sshPublicKey" {
continue
}

for _, val := range attr.Values {
got, _, _, _, err := gossh.ParseAuthorizedKey([]byte(val))
if err != nil {
continue
}
if pubkey.Type() == got.Type() && reflect.DeepEqual(pubkey.Marshal(), got.Marshal()) {
return true
}
}
}
}
return false
}

func (mgr *ldapBackend) AllowForwardProxy(username string) bool {
return false
}

func NewLDAPBackend(url, searchBase, bindDN, bindPW string) *ldapBackend {

back := &ldapBackend{
url: url,
searchBase: searchBase,
bindDN: bindDN,
bindPW: bindPW,
}

back.ldapQueryConnPool.New = func() interface{} {
conn, err := ldap.DialURL(back.url, ldap.DialWithTLSConfig(&tls.Config{InsecureSkipVerify: true}))
if err != nil {
panic(err)
}
err = conn.Bind(back.bindDN, back.bindPW)
if err != nil {
panic(err)
}
fmt.Println("LDAP connection established")
return conn
}

return back
}
17 changes: 17 additions & 0 deletions scheme.ldif
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
dn: cn=netgate,cn=scheme,cn=config
objectClass: olcSchemaConfig
cn: netgate
olcAttributeTypes: {0}( 1.3.6.1.4.1.61850.1.1.1.1
NAME 'allowForwardProxy'
DESC 'Allow forward proxy'
EQUALITY booleanMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
)
olcObjectClasses: {0}( 1.3.6.1.4.1.61850.1.1.2.1
NAME 'ngUserAccount'
DESC 'Netgate User Account'
SUP top
AUXILIARY
MUST ( uid )
MAY ( allowForwardProxy $ userPassword $ sshPublicKey )
)
13 changes: 11 additions & 2 deletions ui/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ type Cfg struct {
}

type authConfig struct {
Users []User `yaml:"Users,flow"`
Policies []Policy `yaml:"Policies,flow"`
Users []User `yaml:"Users,flow"`
Policies []Policy `yaml:"Policies,flow"`
LDAP LDAPConfig `yaml:"LDAP"`
}

type LDAPConfig struct {
Url string `yaml:"Url"`
SearchBase string `yaml:"SearchBase"`
BindDN string `yaml:"BindDN"`
BindPW string `yaml:"BindPW"`
}

type User struct {
Username string `yaml:"Username"`
PasswordHash string `yaml:"PasswordHash"`
Expand Down
5 changes: 5 additions & 0 deletions ui/myservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ func LoadCfg(cfgs []byte) error {

fileBackend.SetUser(u.Username, u.PasswordHash, u.AllowForwardProxy, pks, u.SSHAllowPassword)
}
if cfg.Auth.LDAP.Url != "" {
ldapBackend := auth.NewLDAPBackend(cfg.Auth.LDAP.Url, cfg.Auth.LDAP.SearchBase, cfg.Auth.LDAP.BindDN, cfg.Auth.LDAP.BindPW)
pba.AddBackends([]auth.PolicyBackend{ldapBackend})
log.Println("sys", "auth", "use ldap backend as [1]")
}
for _, p := range cfg.Auth.Policies {
log.Println("sys", "auth", "Found Policy", p.Name)
if err = pba.AddPolicy(p.Name, p.Allowance, p.Users, p.Hosts, p.Paths); err != nil {
Expand Down

0 comments on commit 8fc325a

Please sign in to comment.