Add 'listhosts' role (fix #5)

This commit is contained in:
Manfred Touron 2017-11-23 18:59:59 +01:00
parent a36bb68957
commit beeba0551b
5 changed files with 163 additions and 10 deletions

View file

@ -6,7 +6,8 @@
* Add 'host update' command (fix [#2](https://github.com/moul/sshportal/issues/2))
* Add 'user update' command (fix [#3](https://github.com/moul/sshportal/issues/3))
* Add 'acl update' command (fix [#4](https://github.com/moul/sshportal/issues/4))
* Allow connecting to the shell mode with the registered username or email
* Allow connecting to the shell mode with the registered username or email (fix [#5](https://github.com/moul/sshportal/issues/5))
* Add 'listhosts' role (fix [#5](https://github.com/moul/sshportal/issues/5))
## v1.2.0 (2017-11-22)

13
db.go
View file

@ -207,6 +207,19 @@ func UserHasRole(user User, name string) bool {
}
return false
}
func UserCheckRoles(user User, names []string) error {
ok := false
for _, name := range names {
if UserHasRole(user, name) {
ok = true
break
}
}
if ok {
return nil
}
return fmt.Errorf("you don't have permission to access this feature (requires any of these roles: '%s')", strings.Join(names, "', '"))
}
// ACL helpers
func ACLsPreload(db *gorm.DB) *gorm.DB {

View file

@ -284,6 +284,14 @@ func dbInit(db *gorm.DB) error {
Rollback: func(tx *gorm.DB) error {
return fmt.Errorf("not implemented")
},
}, {
ID: "20",
Migrate: func(tx *gorm.DB) error {
return tx.Create(&UserRole{Name: "listhosts"}).Error
},
Rollback: func(tx *gorm.DB) error {
return tx.Where("name = ?", "listhosts").Delete(&UserRole{}).Error
},
},
})
if err := m.Migrate(); err != nil {

View file

@ -120,10 +120,6 @@ func server(c *cli.Context) error {
switch username := s.User(); {
case username == currentUser.Name || username == currentUser.Email || username == c.String("config-user"):
if !UserHasRole(currentUser, "admin") {
fmt.Fprintf(s, "You are not an administrator, permission denied.\n")
return
}
if err := shell(c, s, s.Command(), db); err != nil {
fmt.Fprintf(s, "error: %v\n", err)
}

145
shell.go
View file

@ -53,6 +53,8 @@ GLOBAL OPTIONS:
app := cli.NewApp()
app.Writer = s
app.HideVersion = true
myself := s.Context().Value(userContextKey).(User)
app.Commands = []cli.Command{
{
Name: "acl",
@ -71,6 +73,9 @@ GLOBAL OPTIONS:
cli.UintFlag{Name: "weight, w", Usage: "Assigns the ACL weight (priority)"},
},
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
acl := ACL{
Comment: c.String("comment"),
HostPattern: c.String("pattern"),
@ -118,6 +123,9 @@ GLOBAL OPTIONS:
if c.NArg() < 1 {
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var acls []ACL
if err := ACLsPreload(ACLsByIdentifiers(db, c.Args())).Find(&acls).Error; err != nil {
@ -132,6 +140,9 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists acls",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var acls []ACL
if err := db.Preload("UserGroups").Preload("HostGroups").Find(&acls).Error; err != nil {
return err
@ -171,6 +182,9 @@ GLOBAL OPTIONS:
if c.NArg() < 1 {
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return ACLsByIdentifiers(db, c.Args()).Delete(&ACL{}).Error
},
@ -192,6 +206,9 @@ GLOBAL OPTIONS:
if c.NArg() < 1 {
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var acls []ACL
if err := ACLsByIdentifiers(db, c.Args()).Find(&acls).Error; err != nil {
@ -260,6 +277,10 @@ GLOBAL OPTIONS:
},
Description: "ssh admin@portal config backup > sshportal.bkp",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
config := Config{}
if err := db.Find(&config.Hosts).Error; err != nil {
return err
@ -303,6 +324,10 @@ GLOBAL OPTIONS:
cli.BoolFlag{Name: "confirm", Usage: "yes, I want to replace everything with this backup!"},
},
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
config := Config{}
dec := json.NewDecoder(s)
@ -413,6 +438,11 @@ GLOBAL OPTIONS:
if c.NArg() != 1 {
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
host, err := NewHostFromURL(c.Args().First())
if err != nil {
return err
@ -469,8 +499,16 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin", "listhosts"}); err != nil {
return err
}
var hosts []Host
if err := HostsPreload(HostsByIdentifiers(db, c.Args())).Find(&hosts).Error; err != nil {
db = db.Preload("Groups")
if UserHasRole(myself, "admin") {
db = db.Preload("SSHKey")
}
if err := HostsByIdentifiers(db, c.Args()).Find(&hosts).Error; err != nil {
return err
}
@ -482,6 +520,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists hosts",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin", "listhosts"}); err != nil {
return err
}
var hosts []*Host
if err := db.Preload("Groups").Find(&hosts).Error; err != nil {
return err
@ -528,6 +570,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return HostsByIdentifiers(db, c.Args()).Delete(&Host{}).Error
},
}, {
@ -548,6 +594,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var hosts []Host
if err := HostsByIdentifiers(db, c.Args()).Find(&hosts).Error; err != nil {
return err
@ -615,6 +665,10 @@ GLOBAL OPTIONS:
cli.StringFlag{Name: "comment", Usage: "Adds a comment"},
},
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
hostGroup := HostGroup{
Name: c.String("name"),
Comment: c.String("comment"),
@ -642,6 +696,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var hostGroups []HostGroup
if err := HostGroupsPreload(HostGroupsByIdentifiers(db, c.Args())).Find(&hostGroups).Error; err != nil {
return err
@ -655,6 +713,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists host groups",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var hostGroups []*HostGroup
if err := db.Preload("ACLs").Preload("Hosts").Find(&hostGroups).Error; err != nil {
return err
@ -685,6 +747,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return HostGroupsByIdentifiers(db, c.Args()).Delete(&HostGroup{}).Error
},
},
@ -693,6 +759,10 @@ GLOBAL OPTIONS:
Name: "info",
Usage: "Shows system-wide information",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
fmt.Fprintf(s, "Debug mode (server): %v\n", globalContext.Bool("debug"))
hostname, _ := os.Hostname()
fmt.Fprintf(s, "Hostname: %s\n", hostname)
@ -708,7 +778,6 @@ GLOBAL OPTIONS:
fmt.Fprintf(s, "Go version (build): %v\n", runtime.Version())
fmt.Fprintf(s, "Uptime: %v\n", time.Since(startTime))
myself := s.Context().Value(userContextKey).(User)
fmt.Fprintf(s, "User email: %v\n", myself.ID)
fmt.Fprintf(s, "User email: %s\n", myself.Email)
fmt.Fprintf(s, "Version: %s\n", VERSION)
@ -737,6 +806,10 @@ GLOBAL OPTIONS:
cli.StringFlag{Name: "comment", Usage: "Adds a comment"},
},
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
name := namesgenerator.GetRandomName(0)
if c.String("name") != "" {
name = c.String("name")
@ -770,6 +843,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var keys []SSHKey
if err := SSHKeysByIdentifiers(db, c.Args()).Find(&keys).Error; err != nil {
return err
@ -783,6 +860,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists keys",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var keys []SSHKey
if err := db.Preload("Hosts").Find(&keys).Error; err != nil {
return err
@ -816,6 +897,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return SSHKeysByIdentifiers(db, c.Args()).Delete(&SSHKey{}).Error
},
},
@ -833,6 +918,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var users []User
if err := UsersPreload(UsersByIdentifiers(db, c.Args())).Find(&users).Error; err != nil {
return err
@ -857,6 +946,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
// FIXME: validate email
email := c.Args().First()
@ -896,6 +989,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists users",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var users []User
if err := db.Preload("Groups").Preload("Roles").Preload("Keys").Find(&users).Error; err != nil {
return err
@ -937,6 +1034,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return UsersByIdentifiers(db, c.Args()).Delete(&User{}).Error
},
}, {
@ -956,6 +1057,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
// FIXME: check if unset-admin + user == myself
var users []User
if err := UsersByIdentifiers(db, c.Args()).Find(&users).Error; err != nil {
@ -1032,6 +1137,10 @@ GLOBAL OPTIONS:
cli.StringFlag{Name: "comment", Usage: "Adds a comment"},
},
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
userGroup := UserGroup{
Name: c.String("name"),
Comment: c.String("comment"),
@ -1044,10 +1153,8 @@ GLOBAL OPTIONS:
return err
}
// FIXME: check if name already exists
// FIXME: add myself to the new group
// add myself to the new group
myself := s.Context().Value(userContextKey).(User)
// FIXME: use foreign key with ID to avoid updating the user with the context
userGroup.Users = []*User{&myself}
if err := db.Create(&userGroup).Error; err != nil {
@ -1065,6 +1172,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var userGroups []UserGroup
if err := UserGroupsPreload(UserGroupsByIdentifiers(db, c.Args())).Find(&userGroups).Error; err != nil {
return err
@ -1078,6 +1189,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists user groups",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var userGroups []*UserGroup
if err := db.Preload("ACLs").Preload("Users").Find(&userGroups).Error; err != nil {
return err
@ -1108,6 +1223,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return UserGroupsByIdentifiers(db, c.Args()).Delete(&UserGroup{}).Error
},
},
@ -1129,6 +1248,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var user User
if err := UsersByIdentifiers(db, c.Args()).First(&user).Error; err != nil {
return err
@ -1172,6 +1295,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var userKeys []UserKey
if err := UserKeysPreload(UserKeysByIdentifiers(db, c.Args())).Find(&userKeys).Error; err != nil {
return err
@ -1185,6 +1312,10 @@ GLOBAL OPTIONS:
Name: "ls",
Usage: "Lists userkeys",
Action: func(c *cli.Context) error {
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
var userkeys []UserKey
if err := db.Preload("User").Find(&userkeys).Error; err != nil {
return err
@ -1213,6 +1344,10 @@ GLOBAL OPTIONS:
return cli.ShowSubcommandHelp(c)
}
if err := UserCheckRoles(myself, []string{"admin"}); err != nil {
return err
}
return UserKeysByIdentifiers(db, c.Args()).Delete(&UserKey{}).Error
},
},