Add basic ACL support

This commit is contained in:
Manfred Touron 2017-11-13 10:13:17 +01:00
parent 15d3379c71
commit b96bccbba2
4 changed files with 118 additions and 1 deletions

View file

@ -6,3 +6,8 @@ install:
dev:
-go get github.com/githubnemo/CompileDaemon
CompileDaemon -exclude-dir=.git -exclude=".#*" -color=true -command="./sshportal --demo --debug" .
.PHONY: test
test:
go test -i .
go test -v .

40
acl.go Normal file
View file

@ -0,0 +1,40 @@
package main
import "sort"
type ByWeight []ACL
func (a ByWeight) Len() int { return len(a) }
func (a ByWeight) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByWeight) Less(i, j int) bool { return a[i].Weight < a[j].Weight }
func CheckACLs(user User, host Host) (string, error) {
// shared ACLs between user and host
aclMap := map[uint]ACL{}
for _, userGroup := range user.Groups {
for _, userGroupACL := range userGroup.ACLs {
for _, hostGroup := range host.Groups {
for _, hostGroupACL := range hostGroup.ACLs {
if userGroupACL.ID == hostGroupACL.ID {
aclMap[userGroupACL.ID] = userGroupACL
}
}
}
}
}
// FIXME: add ACLs that match host pattern
// deny by default if no shared ACL
if len(aclMap) == 0 {
return "deny", nil // default action
}
// transofrm map to slice and sort it
acls := []ACL{}
for _, acl := range aclMap {
acls = append(acls, acl)
}
sort.Sort(ByWeight(acls))
return acls[0].Action, nil
}

43
acl_test.go Normal file
View file

@ -0,0 +1,43 @@
package main
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/jinzhu/gorm"
. "github.com/smartystreets/goconvey/convey"
)
func TestCheckACLs(t *testing.T) {
Convey("Testing CheckACLs", t, func() {
// create tmp dir
tempDir, err := ioutil.TempDir("", "sshportal")
So(err, ShouldBeNil)
defer os.RemoveAll(tempDir)
// create sqlite db
db, err := gorm.Open("sqlite3", filepath.Join(tempDir, "sshportal.db"))
db.LogMode(false)
So(dbInit(db), ShouldBeNil)
// create dummy objects
hostGroup, err := FindHostGroupByIdOrName(db, "default")
So(err, ShouldBeNil)
db.Create(&Host{Groups: []HostGroup{*hostGroup}})
//. load db
var (
hosts []Host
users []User
)
db.Preload("Groups").Preload("Groups.ACLs").Find(&hosts)
db.Preload("Groups").Preload("Groups.ACLs").Find(&users)
// test
action, err := CheckACLs(users[0], hosts[0])
So(err, ShouldBeNil)
So(action, ShouldEqual, "allow")
})
}

31
main.go
View file

@ -75,6 +75,7 @@ func server(c *cli.Context) error {
return err
}
defer db.Close()
if c.Bool("debug") {
db.LogMode(true)
}
@ -113,9 +114,37 @@ func server(c *cli.Context) error {
// FIXME: print available hosts
return
}
if err := proxy(s, host); err != nil {
// load up-to-date objects
// FIXME: cache them or try not to load them
var tmpUser User
if err := db.Preload("Groups").Preload("Groups.ACLs").Where("id = ?", currentUser.ID).First(&tmpUser).Error; err != nil {
fmt.Fprintf(s, "error: %v\n", err)
return
}
var tmpHost Host
if err := db.Preload("Groups").Preload("Groups.ACLs").Where("id = ?", host.ID).First(&tmpHost).Error; err != nil {
fmt.Fprintf(s, "error: %v\n", err)
return
}
action, err := CheckACLs(tmpUser, tmpHost)
if err != nil {
fmt.Fprintf(s, "error: %v\n", err)
return
}
switch action {
case "allow":
if err := proxy(s, host); err != nil {
fmt.Fprintf(s, "error: %v\n", err)
}
case "deny":
fmt.Fprintf(s, "You don't have permission to that host.\n")
default:
fmt.Fprintf(s, "error: %v\n", err)
}
}
})