From 5b2ec90719e0d5dda623ffa9df20aaf985b2e81d Mon Sep 17 00:00:00 2001 From: korween Date: Mon, 25 Apr 2022 23:39:01 +0200 Subject: [PATCH] Add 'user kick' and 'user ban' commands The former allows to terminate all active user sessions (poll-based, every 30s) The latter does the same but also removes all user keys, making him unable to login again --- pkg/bastion/shell.go | 53 ++++++++++++++++++++++++++++++++++++++++++++ pkg/bastion/ssh.go | 13 ++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/pkg/bastion/shell.go b/pkg/bastion/shell.go index 81077d8f..aae03477 100644 --- a/pkg/bastion/shell.go +++ b/pkg/bastion/shell.go @@ -1611,6 +1611,59 @@ GLOBAL OPTIONS: enc.SetIndent("", " ") return enc.Encode(users) }, + }, { + Name: "kick", + Usage: "Kills all active sessions for user(s)", + ArgsUsage: "USER...", + Action: func(c *cli.Context) error { + if c.NArg() < 1 { + return cli.ShowSubcommandHelp(c) + } + + if err := myself.CheckRoles([]string{"admin"}); err != nil { + return err + } + + var users []*dbmodels.User + if err := dbmodels.UsersByIdentifiers(db, c.Args()).Find(&users).Error; err != nil { + return err + } + + for _, user := range users { + if err := db.Model(&dbmodels.Session{}).Where(&dbmodels.Session{User: user, Status: string(dbmodels.SessionStatusActive)}).Update("status", "closed").Error; err != nil { + return err + } + } + return nil + }, + }, { + Name: "ban", + Usage: "Kills all active sessions for user(s), and wipes all his ssh keys", + ArgsUsage: "USER...", + Action: func(c *cli.Context) error { + if c.NArg() < 1 { + return cli.ShowSubcommandHelp(c) + } + + if err := myself.CheckRoles([]string{"admin"}); err != nil { + return err + } + + var users []*dbmodels.User + if err := dbmodels.UsersByIdentifiers(db, c.Args()).Find(&users).Error; err != nil { + return err + } + + for _, user := range users { + if err := db.Where("user_id = ?", user.ID).Delete(&dbmodels.UserKey{}).Error; err != nil { + return err + } + if err := db.Model(&dbmodels.Session{}).Where(&dbmodels.Session{User: user, Status: string(dbmodels.SessionStatusActive)}).Update("status", "closed").Error; err != nil { + return err + } + } + return nil + }, }, { Name: "invite", ArgsUsage: "", diff --git a/pkg/bastion/ssh.go b/pkg/bastion/ssh.go index 58150ec1..33eb6bcd 100644 --- a/pkg/bastion/ssh.go +++ b/pkg/bastion/ssh.go @@ -169,10 +169,21 @@ func ChannelHandler(srv *ssh.Server, conn *gossh.ServerConn, newChan gossh.NewCh _ = ch.Close() return } + go func(cnx *gossh.ServerConn, dbConn *gorm.DB, sessionID uint) { + for { + sess := dbmodels.Session{Model: gorm.Model{ID: sessionID}, Status: string(dbmodels.SessionStatusActive)} + if err := dbConn.First(&sess).Error; err != nil || sess.Status != string(dbmodels.SessionStatusActive) { + log.Println("Session should be closed", sessionID, "closing connection") + conn.Close() + break + } + time.Sleep(30 * time.Second) // TODO: VDO: make configurable + } + }(conn, actx.db, sess.ID) go func() { err = multiChannelHandler(conn, newChan, ctx, sessionConfigs, sess.ID) if err != nil { - log.Printf("Error: %v", err) + log.Printf("Error on session %v: %v", sess.ID, err) } now := time.Now()