You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.3 KiB
Go
167 lines
3.3 KiB
Go
package lql
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"gopkg.in/fsnotify.v1"
|
|
)
|
|
|
|
const usersExporterFile = `from __future__ import print_function
|
|
|
|
import json
|
|
|
|
class MultiSiteUsers(object):
|
|
def update(self, data):
|
|
print(json.dumps(data));
|
|
|
|
multisite_users = MultiSiteUsers()
|
|
|
|
eval(open("%s").read())
|
|
`
|
|
|
|
type UserData struct {
|
|
ForceAuthUserWebservice bool `json:"force_authuser_webservice"`
|
|
Looked bool `json:"locked"`
|
|
Roles []string `json:"roles"`
|
|
ForceAuthUser bool `json:"force_authuser"`
|
|
Alias string `json:"alias"`
|
|
StartUrl string `json:"start_url"`
|
|
}
|
|
|
|
type UsersWatcher struct {
|
|
usersfile string
|
|
users map[string]UserData
|
|
lock *sync.RWMutex
|
|
logger *log.Logger
|
|
isWatching bool
|
|
watcher *fsnotify.Watcher
|
|
}
|
|
|
|
func NewUsersWatcher(usersfile string) (*UsersWatcher, error) {
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
uw := &UsersWatcher{
|
|
usersfile: usersfile,
|
|
lock: &sync.RWMutex{},
|
|
isWatching: false,
|
|
watcher: watcher,
|
|
}
|
|
|
|
return uw, nil
|
|
}
|
|
|
|
func (uw *UsersWatcher) Close() {
|
|
uw.watcher.Close()
|
|
}
|
|
|
|
func (uw *UsersWatcher) SetLogger(logger *log.Logger) {
|
|
uw.logger = logger
|
|
}
|
|
|
|
func (uw *UsersWatcher) StartWatching() {
|
|
go func() {
|
|
for {
|
|
select {
|
|
case event, ok := <-uw.watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
|
uw.FetchUsers()
|
|
}
|
|
case err, ok := <-uw.watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
uw.logger.WithField("error", err).Error()
|
|
}
|
|
}
|
|
}()
|
|
|
|
uw.lock.Lock()
|
|
uw.isWatching = true
|
|
uw.lock.Unlock()
|
|
|
|
err := uw.watcher.Add(uw.usersfile)
|
|
if err != nil {
|
|
uw.logger.WithField("error", err).Error()
|
|
}
|
|
}
|
|
|
|
func (uw *UsersWatcher) IsAdmin(userName string) bool {
|
|
uw.lock.RLock()
|
|
if uw.users == nil {
|
|
uw.lock.RUnlock()
|
|
|
|
if !uw.isWatching {
|
|
uw.StartWatching()
|
|
}
|
|
|
|
uw.FetchUsers()
|
|
uw.lock.RLock()
|
|
}
|
|
defer uw.lock.RUnlock()
|
|
|
|
userData, ok := uw.users[userName]
|
|
if !ok {
|
|
uw.logger.WithField("user_name", userName).Debug("Failed to fetch user from db")
|
|
return false
|
|
}
|
|
|
|
for _, role := range userData.Roles {
|
|
if role == "admin" {
|
|
uw.logger.WithField("user_name", userName).Trace("User is admin")
|
|
return true
|
|
}
|
|
}
|
|
|
|
uw.logger.WithField("user_name", userName).Trace("User is not admin")
|
|
return false
|
|
}
|
|
|
|
func (uw *UsersWatcher) FetchUsers() error {
|
|
uw.logger.WithField("usersfile", uw.usersfile).Debug("Reading users")
|
|
|
|
dir, err := ioutil.TempDir("", "lql-api")
|
|
if err != nil {
|
|
uw.logger.WithField("error", err).Error()
|
|
return err
|
|
}
|
|
|
|
tmpfn := filepath.Join(dir, "lql-api-user-reader.py")
|
|
if err := ioutil.WriteFile(tmpfn, []byte(fmt.Sprintf(usersExporterFile, uw.usersfile)), 0700); err != nil {
|
|
uw.logger.WithField("error", err).Error()
|
|
return err
|
|
}
|
|
|
|
cmd := exec.Command("python", tmpfn)
|
|
uw.logger.WithField("args", cmd.Args).Debug("Executing")
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
uw.logger.WithField("error", err).Error()
|
|
return err
|
|
}
|
|
|
|
result := make(map[string]UserData, 1)
|
|
if err = json.Unmarshal(out, &result); err != nil {
|
|
uw.logger.WithField("error", err).Error()
|
|
return err
|
|
}
|
|
|
|
uw.lock.Lock()
|
|
uw.users = result
|
|
uw.lock.Unlock()
|
|
|
|
return nil
|
|
}
|