grim/hgkeeper

access: Refactor paths related functions
access-control
2019-04-29, Wagner Riffel
c8e556033bea
access: Refactor paths related functions
Now it's falling back to globals if nothing was read from yaml.
SetPath.* functions were merged into SetPath.
Rename some iterators to make it easier to follow.
--- a/access/access.go Sun Apr 28 02:00:26 2019 -0300
+++ b/access/access.go Mon Apr 29 01:48:57 2019 -0300
@@ -51,7 +51,7 @@
// path.
paths map[string][]_key
- // global []_key
+ global [numPerms][]_key
}
// parse calls inderectly UnmarshalYAML, it's caller's duty to control the access to a.
@@ -79,23 +79,23 @@
return err
}
groups := make(map[string][]_key)
- for i, v := range dummy.Groups {
- if isPublic([]byte(i)) {
- log.Errorf("access: %q group is reserved, ignored", i)
+ for name, v := range dummy.Groups {
+ if isPublic([]byte(name)) {
+ log.Errorf("access: %q group is reserved, ignored", name)
continue
}
- if _, exists := groups[i]; exists {
- log.Errorf("access: group %q registered twice", i)
+ if _, exists := groups[name]; exists {
+ log.Errorf("access: group %q registered twice", name)
continue
}
for _, keyFile := range v {
- k, err := loadKey(keyFile)
+ k, err := loadKeys(keyFile)
if err != nil {
log.Errorf("%v", err)
- if _, ok := groups[i]; !ok {
- // if group "i" fail to load every key, this stops
+ if _, ok := groups[name]; !ok {
+ // if group "name" fail to load every key, this stops
// setPath routines to load group names as keys
- groups[i] = nil
+ groups[name] = nil
}
continue
}
@@ -103,9 +103,11 @@
for _, v := range k {
keys = append(keys, _key{fprint: v})
}
- groups[i] = append(groups[i], keys...)
+ groups[name] = append(groups[name], keys...)
}
}
+ gperms := [numPerms][]string{dummy.Global.Init, dummy.Global.Read, dummy.Global.Write}
+ a.setGlobals(groups, gperms)
for i, v := range dummy.Patterns {
globs, err := filepath.Glob(filepath.Join(reposDir, i))
@@ -113,11 +115,9 @@
log.Errorf("malformed pattern %q: %v", i, err)
continue
}
-
for _, path := range globs {
- a.setPathInit(path, v.Init, groups)
- a.setPathRead(path, v.Read, groups)
- a.setPathWrite(path, v.Write, groups)
+ perms := [numPerms][]string{v.Init, v.Read, v.Write}
+ a.setPath(path, perms, groups)
}
}
return nil
@@ -136,75 +136,80 @@
}
}
-func (a *Access) setPathInit(path string, init []string, groups map[string][]_key) {
- for _, key := range init {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
- k := groups[key][i]
+func (a *Access) setPath(path string, perms [numPerms][]string, groups map[string][]_key) {
+ for p, yamlPerm := range perms {
+ // casting p is not required as of current Go tip (1.13)
+ // see: http://golang.org/issues/19113
+ perm := Perm(1 << uint32(p))
- a.addToPath(path, Init, k)
- }
+ if len(yamlPerm) == 0 {
+ // use defaults
+ a.addToPath(path, perm, a.global[0]...)
continue
}
- ks, err := loadKey(key)
- if err != nil {
- log.Errorf("%v", err)
- continue
+ for _, keyOrGroup := range yamlPerm {
+ // if it's a group, just copy what we already loaded
+ if _, ok := groups[keyOrGroup]; ok {
+ // set permissions on groups key
+ for i := range groups[keyOrGroup] {
+ k := groups[keyOrGroup][i]
+
+ a.addToPath(path, perm, k)
+ }
+ continue
+ }
+ // this is likely to change, it's here just to remember later.
+ if keyOrGroup == "public" {
+ a.addToPath(path, perm, a.global[p]...)
+ continue
+ }
+ ks, err := loadKeys(keyOrGroup)
+ if err != nil {
+ log.Errorf("%v", err)
+ continue
+ }
+ keys := make([]_key, 0, len(ks))
+ for _, v := range ks {
+ keys = append(keys, _key{fprint: v})
+ }
+ a.addToPath(path, perm, keys...)
}
- keys := make([]_key, 0, len(ks))
- for _, v := range ks {
- keys = append(keys, _key{fprint: v})
- }
- a.addToPath(path, Init, keys...)
}
}
-func (a *Access) setPathRead(path string, read []string, groups map[string][]_key) {
- for _, key := range read {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
- k := groups[key][i]
-
- a.addToPath(path, Read, k)
+func (a *Access) setGlobals(groups map[string][]_key, perms [numPerms][]string) {
+ for p, keyOrGroup := range perms {
+ // casting p is not required as of current Go tip (1.13)
+ // see: http://golang.org/issues/19113
+ var perm Perm
+ perm.set(Perm(1 << uint32(p)))
+ for _, name := range keyOrGroup {
+ // if it's a group, just copy what we already loaded
+ if _, found := groups[name]; found {
+ keys := make([]_key, 0, len(groups[name])+1)
+ for _, v := range groups[name] {
+ keys = append(keys, v)
+ }
+ a.global[p] = append(a.global[p], keys...)
+ continue
}
- continue
- }
- ks, err := loadKey(key)
- if err != nil {
- log.Errorf("%v", err)
- continue
- }
- keys := make([]_key, 0, len(ks))
- for _, v := range ks {
- keys = append(keys, _key{fprint: v})
+
+ // this is likely to change, it's here just to remember later.
+ if name == "public" {
+ a.global[p] = append(a.global[p], _key{fprint: "public", p: perm})
+ continue
+ }
+ k, err := loadKeys(name)
+ if err != nil {
+ log.Errorf("%v", err)
+ continue
+ }
+ keys := make([]_key, 0, len(k))
+ for _, v := range k {
+ keys = append(keys, _key{fprint: v, p: perm})
+ }
+ a.global[p] = append(a.global[p], keys...)
}
- a.addToPath(path, Read, keys...)
- }
-}
-
-func (a *Access) setPathWrite(path string, write []string, groups map[string][]_key) {
- for _, key := range write {
- if _, ok := groups[key]; ok {
- // set permissions on groups key
- for i := range groups[key] {
- k := groups[key][i]
-
- a.addToPath(path, Write, k)
- }
- continue
- }
- ks, err := loadKey(key)
- if err != nil {
- log.Errorf("%v", err)
- continue
- }
- keys := make([]_key, 0, len(ks))
- for _, v := range ks {
- keys = append(keys, _key{fprint: v})
- }
- a.addToPath(path, Write, keys...)
}
}
@@ -252,12 +257,12 @@
return a, a.Reset()
}
-// loadKey reads repoPath/hgkeeper/keys/name and tries to
-// parse as an authorized keys format, and returns its fingerprint
-func loadKey(name string) ([]string, error) {
- f, err := os.Open(filepath.Join(keysDir, name))
+// loadKeys reads file trying to parse it as an authorized key
+// format, returning the finger prints of all keys found
+func loadKeys(file string) ([]string, error) {
+ f, err := os.Open(filepath.Join(keysDir, file))
if err != nil {
- return nil, fmt.Errorf("loadKey %q: %v", name, err)
+ return nil, fmt.Errorf("loadKeys %q: %v", file, err)
}
defer f.Close()
keys := make([]string, 0, 20)
@@ -271,7 +276,7 @@
}
pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
if err != nil {
- log.Errorf("loadKey %q:%d: %v", name, line, err)
+ log.Errorf("loadKeys %q:%d: %v", file, line, err)
continue
}
keys = append(keys, ssh.FingerprintSHA256(pub))
--- a/access/permissions.go Sun Apr 28 02:00:26 2019 -0300
+++ b/access/permissions.go Mon Apr 29 01:48:57 2019 -0300
@@ -8,6 +8,7 @@
Init Perm = 1 << iota
Read
Write
+ numPerms = 3
)
// String returns a textual representation of the perm.
--- a/go.mod Sun Apr 28 02:00:26 2019 -0300
+++ b/go.mod Mon Apr 29 01:48:57 2019 -0300
@@ -4,7 +4,10 @@
github.com/alecthomas/kong v0.1.16
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
+ github.com/kr/pretty v0.1.0 // indirect
github.com/sirupsen/logrus v1.4.1
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
+ gopkg.in/yaml.v2 v2.2.2 // indirect
)
--- a/go.sum Sun Apr 28 02:00:26 2019 -0300
+++ b/go.sum Mon Apr 29 01:48:57 2019 -0300
@@ -8,7 +8,13 @@
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
@@ -23,3 +29,8 @@
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=