git.iko.soy/typeable/oauth2-proxy
on v2.1 help sign in
typeable/oauth2-proxy/validator.go
96 lines 2.2 kB history raw
1package main
3import (
4 "encoding/csv"
5 "fmt"
6 "log"
7 "os"
8 "strings"
9 "sync/atomic"
10 "unsafe"
13type UserMap struct {
14 usersFile string
15 m unsafe.Pointer
18func NewUserMap(usersFile string, done <-chan bool, onUpdate func()) *UserMap {
19 um := &UserMap{usersFile: usersFile}
20 m := make(map[string]bool)
21 atomic.StorePointer(&um.m, unsafe.Pointer(&m))
22 if usersFile != "" {
23 log.Printf("using authenticated emails file %s", usersFile)
24 WatchForUpdates(usersFile, done, func() {
25 um.LoadAuthenticatedEmailsFile()
26 onUpdate()
27 })
28 um.LoadAuthenticatedEmailsFile()
29 }
30 return um
33func (um *UserMap) IsValid(email string) (result bool) {
34 m := *(*map[string]bool)(atomic.LoadPointer(&um.m))
35 _, result = m[email]
36 return
39func (um *UserMap) LoadAuthenticatedEmailsFile() {
40 r, err := os.Open(um.usersFile)
41 if err != nil {
42 log.Fatalf("failed opening authenticated-emails-file=%q, %s", um.usersFile, err)
43 }
44 defer r.Close()
45 csv_reader := csv.NewReader(r)
46 csv_reader.Comma = ','
47 csv_reader.Comment = '#'
48 csv_reader.TrimLeadingSpace = true
49 records, err := csv_reader.ReadAll()
50 if err != nil {
51 log.Printf("error reading authenticated-emails-file=%q, %s", um.usersFile, err)
52 return
53 }
54 updated := make(map[string]bool)
55 for _, r := range records {
56 address := strings.ToLower(strings.TrimSpace(r[0]))
57 updated[address] = true
58 }
59 atomic.StorePointer(&um.m, unsafe.Pointer(&updated))
62func newValidatorImpl(domains []string, usersFile string,
63 done <-chan bool, onUpdate func()) func(string) bool {
64 validUsers := NewUserMap(usersFile, done, onUpdate)
66 var allowAll bool
67 for i, domain := range domains {
68 if domain == "*" {
69 allowAll = true
70 continue
71 }
72 domains[i] = fmt.Sprintf("@%s", strings.ToLower(domain))
73 }
75 validator := func(email string) (valid bool) {
76 if email == "" {
77 return
78 }
79 email = strings.ToLower(email)
80 for _, domain := range domains {
81 valid = valid || strings.HasSuffix(email, domain)
82 }
83 if !valid {
84 valid = validUsers.IsValid(email)
85 }
86 if allowAll {
87 valid = true
88 }
89 return valid
90 }
91 return validator
94func NewValidator(domains []string, usersFile string) func(string) bool {
95 return newValidatorImpl(domains, usersFile, nil, func() {})