init
This commit is contained in:
155
auth.go
Normal file
155
auth.go
Normal file
@ -0,0 +1,155 @@
|
||||
package gost
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Authenticator is an interface for user authentication.
|
||||
type Authenticator interface {
|
||||
Authenticate(user, password string) bool
|
||||
}
|
||||
|
||||
// LocalAuthenticator is an Authenticator that authenticates client by local key-value pairs.
|
||||
type LocalAuthenticator struct {
|
||||
kvs map[string]string
|
||||
period time.Duration
|
||||
stopped chan struct{}
|
||||
mux sync.RWMutex
|
||||
}
|
||||
|
||||
// NewLocalAuthenticator creates an Authenticator that authenticates client by local infos.
|
||||
func NewLocalAuthenticator(kvs map[string]string) *LocalAuthenticator {
|
||||
return &LocalAuthenticator{
|
||||
kvs: kvs,
|
||||
stopped: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate checks the validity of the provided user-password pair.
|
||||
func (au *LocalAuthenticator) Authenticate(user, password string) bool {
|
||||
if au == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
au.mux.RLock()
|
||||
defer au.mux.RUnlock()
|
||||
|
||||
if len(au.kvs) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
v, ok := au.kvs[user]
|
||||
return ok && (v == "" || password == v)
|
||||
}
|
||||
|
||||
// Add adds a key-value pair to the Authenticator.
|
||||
func (au *LocalAuthenticator) Add(k, v string) {
|
||||
au.mux.Lock()
|
||||
defer au.mux.Unlock()
|
||||
if au.kvs == nil {
|
||||
au.kvs = make(map[string]string)
|
||||
}
|
||||
au.kvs[k] = v
|
||||
}
|
||||
|
||||
// Reload parses config from r, then live reloads the Authenticator.
|
||||
func (au *LocalAuthenticator) Reload(r io.Reader) error {
|
||||
var period time.Duration
|
||||
kvs := make(map[string]string)
|
||||
|
||||
if r == nil || au.Stopped() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// splitLine splits a line text by white space.
|
||||
// A line started with '#' will be ignored, otherwise it is valid.
|
||||
split := func(line string) []string {
|
||||
if line == "" {
|
||||
return nil
|
||||
}
|
||||
line = strings.Replace(line, "\t", " ", -1)
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
if strings.IndexByte(line, '#') == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ss []string
|
||||
for _, s := range strings.Split(line, " ") {
|
||||
if s = strings.TrimSpace(s); s != "" {
|
||||
ss = append(ss, s)
|
||||
}
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
ss := split(line)
|
||||
if len(ss) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch ss[0] {
|
||||
case "reload": // reload option
|
||||
if len(ss) > 1 {
|
||||
period, _ = time.ParseDuration(ss[1])
|
||||
}
|
||||
default:
|
||||
var k, v string
|
||||
k = ss[0]
|
||||
if len(ss) > 1 {
|
||||
v = ss[1]
|
||||
}
|
||||
kvs[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
au.mux.Lock()
|
||||
defer au.mux.Unlock()
|
||||
|
||||
au.period = period
|
||||
au.kvs = kvs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Period returns the reload period.
|
||||
func (au *LocalAuthenticator) Period() time.Duration {
|
||||
if au.Stopped() {
|
||||
return -1
|
||||
}
|
||||
|
||||
au.mux.RLock()
|
||||
defer au.mux.RUnlock()
|
||||
|
||||
return au.period
|
||||
}
|
||||
|
||||
// Stop stops reloading.
|
||||
func (au *LocalAuthenticator) Stop() {
|
||||
select {
|
||||
case <-au.stopped:
|
||||
default:
|
||||
close(au.stopped)
|
||||
}
|
||||
}
|
||||
|
||||
// Stopped checks whether the reloader is stopped.
|
||||
func (au *LocalAuthenticator) Stopped() bool {
|
||||
select {
|
||||
case <-au.stopped:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user