remove some unimportant TODOs; add a message when reverify kicks people; add a reverify test

This commit is contained in:
mik2k2 2021-12-22 15:20:18 +01:00
parent efe894e021
commit 46e2e8a812
3 changed files with 34 additions and 12 deletions

View File

@ -174,9 +174,6 @@ func (a *Auth) IsOp(key ssh.PublicKey) bool {
return a.ops.In(authkey) return a.ops.In(authkey)
} }
// TODO: the *FromFile could be replaced by a single LoadFromFile taking the function (i.e. auth.Op/auth.Whitelist)
// TODO: consider reloading on empty path
// LoadOpsFromFile reads a file in authorized_keys format and makes public keys operators // LoadOpsFromFile reads a file in authorized_keys format and makes public keys operators
func (a *Auth) LoadOpsFromFile(path string) error { func (a *Auth) LoadOpsFromFile(path string) error {
a.opFile = path a.opFile = path

14
host.go
View File

@ -801,16 +801,21 @@ func (h *Host) InitCommands(c *chat.Commands) {
return h.auth.LoadWhitelistFromFile(h.auth.whitelistFile) return h.auth.LoadWhitelistFromFile(h.auth.whitelistFile)
} }
allowlistReverify := func() []string { allowlistReverify := func(room *chat.Room) []string {
if !h.auth.WhitelistMode() { if !h.auth.WhitelistMode() {
return []string{"allowlist is disabled, so nobody will be kicked"} return []string{"allowlist is disabled, so nobody will be kicked"}
} }
var kicked []string
forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error { forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error {
if h.auth.CheckPublicKey(pk) != nil { if h.auth.CheckPublicKey(pk) != nil && !user.IsOp { // we do this check here as well for ops without keys
user.Close() // TODO: some message anywhere? kicked = append(kicked, user.Name())
user.Close()
} }
return nil return nil
}) })
if kicked != nil {
room.Send(message.NewAnnounceMsg(fmt.Sprintf("%v were kicked during pubkey reverification.", kicked)))
}
return nil return nil
} }
@ -822,7 +827,6 @@ func (h *Host) InitCommands(c *chat.Commands) {
} }
whitelistedUsers := []string{} whitelistedUsers := []string{}
whitelistedKeys := []string{} whitelistedKeys := []string{}
// TODO: this can probably be optimized
h.auth.whitelist.Each(func(key string, item set.Item) error { h.auth.whitelist.Each(func(key string, item set.Item) error {
keyFP := item.Key() keyFP := item.Key()
if forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error { if forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error {
@ -880,7 +884,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
case "reload": case "reload":
err = allowlistReload(args[1:]) err = allowlistReload(args[1:])
case "reverify": case "reverify":
replyLines = allowlistReverify() replyLines = allowlistReverify(room)
case "status": case "status":
replyLines = allowlistStatus() replyLines = allowlistStatus()
default: default:

View File

@ -211,7 +211,18 @@ func TestHostAllowlistCommand(t *testing.T) {
users <- u users <- u
} }
kickSignal := make(chan struct{})
go sshd.ConnectShell(s.Addr().String(), "toBeKicked", func(r io.Reader, w io.WriteCloser) error {
<-kickSignal
n, err := w.Write([]byte("alive and well"))
if n != 0 || err == nil {
t.Error("could write after being kicked")
}
return nil
})
sshd.ConnectShell(s.Addr().String(), "foo", func(r io.Reader, w io.WriteCloser) error { sshd.ConnectShell(s.Addr().String(), "foo", func(r io.Reader, w io.WriteCloser) error {
<-users
<-users <-users
m, ok := host.MemberByID("foo") m, ok := host.MemberByID("foo")
if !ok { if !ok {
@ -220,6 +231,7 @@ func TestHostAllowlistCommand(t *testing.T) {
scanner := bufio.NewScanner(r) scanner := bufio.NewScanner(r)
scanner.Scan() // Joined scanner.Scan() // Joined
scanner.Scan()
assertLineEq := func(expected string) { assertLineEq := func(expected string) {
if !scanner.Scan() { if !scanner.Scan() {
@ -281,9 +293,13 @@ func TestHostAllowlistCommand(t *testing.T) {
// TODO: to test the AGE arg, we need another connection and possibly a sleep // TODO: to test the AGE arg, we need another connection and possibly a sleep
sendCmd("/allowlist import") sendCmd("/allowlist import")
assertLineEq("users without a public key: [foo]\r") if !scanner.Scan() {
t.Error("no line available")
}
if actual := stripPrompt(scanner.Text()); !strings.HasSuffix(actual, "[foo toBeKicked]\r") && !strings.HasSuffix(actual, "[toBeKicked foo]\r") {
t.Errorf("expected \"foo\" and \"toBeKicked\", got %q", actual)
}
// TODO: test reload with files?
sendCmd("/allowlist reload keep") sendCmd("/allowlist reload keep")
if !host.auth.whitelist.In(testKey2FP) { if !host.auth.whitelist.In(testKey2FP) {
t.Error("cleared allowlist to be kept") t.Error("cleared allowlist to be kept")
@ -299,10 +315,15 @@ func TestHostAllowlistCommand(t *testing.T) {
sendCmd("/allowlist reverify") sendCmd("/allowlist reverify")
assertLineEq("allowlist is disabled, so nobody will be kicked\r") assertLineEq("allowlist is disabled, so nobody will be kicked\r")
sendCmd("/allowlist on")
sendCmd("/allowlist reverify")
kickSignal <- struct{}{}
assertLineEq(" * [toBeKicked] were kicked during pubkey reverification.\r")
assertLineEq(" * toBeKicked left. (After 0 seconds)\r")
sendCmd("/allowlist add " + testKey1) sendCmd("/allowlist add " + testKey1)
sendCmd("/allowlist status") sendCmd("/allowlist status")
assertLineEq("The allowlist is currently disabled.\r") assertLineEq("The allowlist is currently enabled.\r")
assertLineEq(fmt.Sprintf("The following keys of not connected users are on the allowlist: [%s]\r", testKey1FP)) assertLineEq(fmt.Sprintf("The following keys of not connected users are on the allowlist: [%s]\r", testKey1FP))
sendCmd("/allowlist invalidSubcommand") sendCmd("/allowlist invalidSubcommand")
@ -451,5 +472,5 @@ func connectUserWithConfig(t *testing.T, name string, envConfig map[string]strin
} }
} }
t.Fatalf("user %s not found in the host", name) t.Fatalf("user %s not found in the host", name)
return nil return nil
} }