Match groups
This commit is contained in:
parent
551ee05177
commit
05f005707c
12
k8s.yaml
12
k8s.yaml
|
@ -14,16 +14,14 @@ data:
|
|||
bindDN: uid=seviceaccount,cn=users,dc=example,dc=com
|
||||
bindPW: password
|
||||
user:
|
||||
baseDN: cn=users,dc=example,dc=com
|
||||
filter: "(objectClass=person)"
|
||||
userAttr: uid
|
||||
baseDN: ou=users,dc=example,dc=com
|
||||
filter: "(cn={0})"
|
||||
requiredGroups:
|
||||
- appAdmin
|
||||
group:
|
||||
baseDN: cn=groups,dc=freeipa,dc=example,dc=com
|
||||
filter: "(objectClass=group)"
|
||||
userAttr: uid
|
||||
groupAttr: member
|
||||
baseDN: ou=groups,dc=example,dc=com
|
||||
groupAttr: cn
|
||||
filter: "(member={0})"
|
||||
timeout:
|
||||
success: 24h
|
||||
wrong: 5m
|
||||
|
|
|
@ -10,15 +10,13 @@ type AuthConfig struct {
|
|||
type UserConfig struct {
|
||||
BaseDN string `yaml:"baseDN"`
|
||||
Filter string `yaml:"filter"`
|
||||
UserAttr string `yaml:"userAttr"`
|
||||
RequiredGroups []string `yaml:"requiredGroups"`
|
||||
}
|
||||
|
||||
type GroupConfig struct {
|
||||
BaseDN string `yaml:"baseDN"`
|
||||
Filter string `yaml:"filter"`
|
||||
UserAttr string `yaml:"userAttr"`
|
||||
GroupAttr string `yaml:"groupAttr"`
|
||||
Filter string `yaml:"filter"`
|
||||
}
|
||||
|
||||
type TimeoutConfig struct {
|
||||
|
|
89
src/ldap.go
89
src/ldap.go
|
@ -2,22 +2,29 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
ldap "gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
var conn *ldap.Conn
|
||||
var (
|
||||
conn *ldap.Conn
|
||||
admin bool
|
||||
lock sync.Mutex
|
||||
)
|
||||
|
||||
func setupLDAP() error {
|
||||
size := len(config.Servers)
|
||||
if size == 0 {
|
||||
return fmt.Errorf("No LDAP server available on %+v", config)
|
||||
return errors.New("No LDAP server available!")
|
||||
}
|
||||
|
||||
r := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
|
@ -79,22 +86,28 @@ func setupLDAP() error {
|
|||
}
|
||||
}
|
||||
|
||||
if config.Auth.BindDN != "" || config.Auth.BindPW != "" {
|
||||
err = conn.Bind(config.Auth.BindDN, config.Auth.BindPW)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
admin = false
|
||||
return auth()
|
||||
}
|
||||
|
||||
func auth() error {
|
||||
if admin || config.Auth.BindDN == "" && config.Auth.BindPW == "" {
|
||||
return nil
|
||||
}
|
||||
err := conn.Bind(config.Auth.BindDN, config.Auth.BindPW)
|
||||
if err == nil {
|
||||
admin = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ldapLogin(username, password string) (bool, error) {
|
||||
// TODO: lock
|
||||
if config.Auth.BindDN != "" || config.Auth.BindPW != "" {
|
||||
err := conn.Bind(config.Auth.BindDN, config.Auth.BindPW)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
err := auth()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req := ldap.NewSearchRequest(
|
||||
|
@ -105,12 +118,11 @@ func ldapLogin(username, password string) (bool, error) {
|
|||
0,
|
||||
false,
|
||||
strings.Replace(config.User.Filter, "{0}", username, -1),
|
||||
[]string{config.User.UserAttr},
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
res, err := conn.Search(req)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -119,6 +131,51 @@ func ldapLogin(username, password string) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
admin = false
|
||||
err = conn.Bind(res.Entries[0].DN, password)
|
||||
return err == nil, nil
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err = auth()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(config.User.RequiredGroups) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
req = ldap.NewSearchRequest(
|
||||
config.Group.BaseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
strings.Replace(config.Group.Filter, "{0}", res.Entries[0].DN, -1),
|
||||
[]string{config.Group.GroupAttr},
|
||||
nil,
|
||||
)
|
||||
|
||||
res, err = conn.Search(req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
groups := []string{}
|
||||
for _, entry := range res.Entries {
|
||||
groups = append(groups, entry.GetAttributeValue(config.Group.GroupAttr))
|
||||
}
|
||||
|
||||
sort.Strings(groups)
|
||||
|
||||
for _, group := range config.User.RequiredGroups {
|
||||
pos := sort.SearchStrings(groups, group)
|
||||
if pos >= len(groups) || groups[pos] != group {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
|
10
src/main.go
10
src/main.go
|
@ -19,11 +19,11 @@ var (
|
|||
Web: "0.0.0.0:5555",
|
||||
Path: "/",
|
||||
User: UserConfig{
|
||||
UserAttr: "uid",
|
||||
Filter: "(cn={0})",
|
||||
},
|
||||
Group: GroupConfig{
|
||||
UserAttr: "uid",
|
||||
GroupAttr: "member",
|
||||
Filter: "(member={0})",
|
||||
GroupAttr: "cn",
|
||||
},
|
||||
Timeout: TimeoutConfig{
|
||||
Success: 24 * time.Hour,
|
||||
|
@ -45,7 +45,7 @@ func main() {
|
|||
log.Fatalf("Error on parse config: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Loaded config: %+v\n", config)
|
||||
fmt.Printf("Loaded config \"%s\".\n", *configFile)
|
||||
|
||||
err = setupLDAP()
|
||||
if err != nil {
|
||||
|
@ -73,6 +73,8 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
|||
secret := strings.SplitN(string(decoded), ":", 2)
|
||||
|
||||
if len(secret) == 2 && validate(secret[0], secret[1]) {
|
||||
// TODO: match by header, e.g: X-Original-URL X-Original-Method X-Sent-From X-Auth-Request-Redirect
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
|
Reference in a new issue