Password cache map with ttl
This commit is contained in:
parent
f0c61005dd
commit
134c5508c1
|
@ -1,6 +1,6 @@
|
|||
# Nginx LDAP Auth
|
||||
|
||||
Use this in order to provide a ingress authentication over LDAP for Kubernetes, change the ConfigMap inside `k8s.yaml` to match your LDAP server and run:
|
||||
Use this in order to provide a ingress authentication over LDAP for Kubernetes, change the Secret inside `k8s.yaml` to match your LDAP server and run:
|
||||
|
||||
kubectl apply -f k8s.yaml
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
)
|
||||
|
||||
var configFile = flag.String("config", "/etc/nginx-ldap-auth/config.yaml", "Configuration file")
|
||||
var config Config
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
@ -19,7 +20,6 @@ func main() {
|
|||
log.Fatalf("Could not read file \"%s\": %v\n", *configFile, err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
err = yaml.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
log.Fatalf("Error on parse config: %v\n", err)
|
||||
|
|
119
src/timeout.go
Normal file
119
src/timeout.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type passtimer struct {
|
||||
password string
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
type userpass struct {
|
||||
correct *passtimer
|
||||
wrong []passtimer
|
||||
}
|
||||
|
||||
var (
|
||||
passwords map[string]userpass
|
||||
mutex = sync.RWMutex{}
|
||||
)
|
||||
|
||||
func containsWrongPassword(data *userpass, password string) (int, bool) {
|
||||
size := len(data.wrong)
|
||||
if size == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
pos := sort.Search(size, func(i int) bool {
|
||||
return data.wrong[i].password < password
|
||||
})
|
||||
|
||||
return pos, pos < size &&
|
||||
data.wrong[pos].password == password
|
||||
}
|
||||
|
||||
func getCache(username, password string) (bool, bool) {
|
||||
defer mutex.RUnlock()
|
||||
mutex.RLock()
|
||||
|
||||
data, found := passwords[username]
|
||||
if !found {
|
||||
return false, false
|
||||
}
|
||||
|
||||
if data.correct != nil && (*data.correct).password == password {
|
||||
return true, true
|
||||
}
|
||||
|
||||
_, found = containsWrongPassword(&data, password)
|
||||
|
||||
return false, found
|
||||
}
|
||||
|
||||
func putCache(username, password string, ok bool) {
|
||||
defer mutex.Unlock()
|
||||
mutex.Lock()
|
||||
|
||||
data, found := passwords[username]
|
||||
if !found {
|
||||
data = userpass{}
|
||||
passwords[username] = data
|
||||
}
|
||||
|
||||
if ok {
|
||||
if data.correct != nil {
|
||||
data.correct.timer.Stop()
|
||||
}
|
||||
data.correct = &passtimer{
|
||||
password: password,
|
||||
timer: time.AfterFunc(config.Timeout.Success, func() {
|
||||
removeCache(username, "", true)
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
pass := passtimer{
|
||||
password: password,
|
||||
timer: time.AfterFunc(config.Timeout.Wrong, func() {
|
||||
removeCache(username, password, false)
|
||||
}),
|
||||
}
|
||||
pos, found := containsWrongPassword(&data, password)
|
||||
if found {
|
||||
data.wrong[pos].timer.Stop()
|
||||
} else {
|
||||
data.wrong = append(data.wrong, passtimer{})
|
||||
copy(data.wrong[pos+1:], data.wrong[pos:])
|
||||
}
|
||||
data.wrong[pos] = pass
|
||||
}
|
||||
}
|
||||
|
||||
func removeCache(username, password string, ok bool) {
|
||||
defer mutex.Unlock()
|
||||
mutex.Lock()
|
||||
|
||||
data, found := passwords[username]
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
if ok {
|
||||
if data.correct != nil {
|
||||
data.correct.timer.Stop()
|
||||
data.correct = nil
|
||||
}
|
||||
} else {
|
||||
pos, found := containsWrongPassword(&data, password)
|
||||
if found {
|
||||
data.wrong[pos].timer.Stop()
|
||||
data.wrong = data.wrong[:pos+copy(data.wrong[pos:], data.wrong[pos+1:])]
|
||||
}
|
||||
}
|
||||
|
||||
if data.correct == nil && len(data.wrong) == 0 {
|
||||
delete(passwords, username)
|
||||
}
|
||||
}
|
Reference in a new issue