From e9744a7c2fabd322fb37f1f67cd28a1f913cf95c Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Tue, 6 Aug 2024 22:28:34 +0200 Subject: [PATCH] better messages when the user modifies the .authorized_keys file from within the session. --- cmd/agent/agent.go | 7 +++-- cmd/agent/sshauthorizedkeys.go | 50 +++++++++++++++++++--------------- go.mod | 2 +- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 6fc2070..20d03b5 100755 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -329,9 +329,12 @@ func main() { // Authentiocation - authorizedKeys := NewAuthorizedPublicKeys(authorizedKeysFile) + authorizedKeys, err := NewAuthorizedPublicKeys(authorizedKeysFile) + if err != nil { + os.Exit(1) + } // initial check - pubkeys := authorizedKeys.Parse() + pubkeys, _ := authorizedKeys.Parse() if len(pubkeys) == 0 { log.Printf("No public keys found in '%s', exiting", authorizedKeysFile) os.Exit(1) diff --git a/cmd/agent/sshauthorizedkeys.go b/cmd/agent/sshauthorizedkeys.go index 7f49362..a433d8d 100644 --- a/cmd/agent/sshauthorizedkeys.go +++ b/cmd/agent/sshauthorizedkeys.go @@ -26,15 +26,16 @@ func publicKeyHandler(ctx ssh.Context, key gossh.PublicKey, authorizedKey gossh. return false } -func readSshPublicKeys(fileName string) ([]ssh.PublicKey, error) { +func readSshPublicKeys(fileName string) ([]ssh.PublicKey, []string, error) { file, err := os.Open(fileName) if err != nil { - return nil, fmt.Errorf("Failed to open file: '%s': %s", fileName, err) + return nil, nil, fmt.Errorf("Failed to open file: '%s': %s", fileName, err) } defer file.Close() res := make([]ssh.PublicKey, 0) scanner := bufio.NewScanner(file) + var errorKeys []string for scanner.Scan() { lineText := scanner.Text() ind := strings.Index(lineText, "#") @@ -49,12 +50,13 @@ func readSshPublicKeys(fileName string) ([]ssh.PublicKey, error) { line := []byte(lineText) parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(line) if err != nil { + errorKeys = append(errorKeys, lineText) log.Printf("Failed to parse authorized key: %v", lineText) } else { res = append(res, parsedKey) } } - return res, nil + return res, errorKeys, nil } type AuthorizedPublicKeys struct { @@ -63,18 +65,18 @@ type AuthorizedPublicKeys struct { publicKeys []ssh.PublicKey } -func NewAuthorizedPublicKeys(authorizedKeysFile string) *AuthorizedPublicKeys { +func NewAuthorizedPublicKeys(authorizedKeysFile string) (*AuthorizedPublicKeys, error) { pubkeys := AuthorizedPublicKeys{ authorizedKeysFile: authorizedKeysFile, mutex: sync.Mutex{}, publicKeys: nil, } + pubkeys.publicKeys, _ = pubkeys.Parse() + if len(pubkeys.publicKeys) == 0 { + return nil, fmt.Errorf("No valid public keys found, login is impossible, exiting") + } go pubkeys.monitorAuthorizedKeysFile(authorizedKeysFile) - return &pubkeys -} - -func (pubkeys *AuthorizedPublicKeys) notifyUsers(message string) { - session.MessageUsers(message) + return &pubkeys, nil } func (pubkeys *AuthorizedPublicKeys) setPubKeys(keys []ssh.PublicKey) { @@ -106,30 +108,34 @@ func (pubkeys *AuthorizedPublicKeys) monitorAuthorizedKeysFile(authorizedPublicK select { case event, ok := <-watcher.Events: if !ok { - pubkeys.notifyUsers( + session.MessageUsers( fmt.Sprintf("Watching authorized keys file '%s' stopped", authorizedPublicKeysFile)) return } base := filepath.Base(event.Name) log.Println("CHANGE " + base + " " + authorizedPublicKeysFile + " " + filepath.Base(authorizedPublicKeysFile)) if base == filepath.Base(authorizedPublicKeysFile) { - keys := pubkeys.Parse() + keys, errorKeys := pubkeys.Parse() + for _, errorKey := range errorKeys { + session.MessageUsers(fmt.Sprintf("Public key '%s' is invalid", errorKey)) + } + if len(keys) == 0 { - pubkeys.notifyUsers( - fmt.Sprintf("Authorized keys file '%s' does not contain any valid keys, using last known configuration", authorizedPublicKeysFile)) + session.MessageUsers( + fmt.Sprintf("Authorized keys file '%s' does not exist or does not contain any valid keys, using last known configuration", authorizedPublicKeysFile)) } else { - pubkeys.notifyUsers(fmt.Sprintf("Updated authorized keys, now %d valid keys", len(keys))) + session.MessageUsers(fmt.Sprintf("Updated authorized keys, now %d valid key(s)", len(keys))) pubkeys.setPubKeys(keys) } } case err, ok := <-watcher.Errors: if ok { - pubkeys.notifyUsers(fmt.Sprintf( + session.MessageUsers(fmt.Sprintf( "Watching authorized keys file '%s' stopped", pubkeys.authorizedKeysFile)) } - pubkeys.notifyUsers(fmt.Sprintf( + session.MessageUsers(fmt.Sprintf( "Watching authorized keys file '%s' stopped: %v", pubkeys.authorizedKeysFile, err)) return @@ -137,24 +143,24 @@ func (pubkeys *AuthorizedPublicKeys) monitorAuthorizedKeysFile(authorizedPublicK } } -func (pubkeys *AuthorizedPublicKeys) Parse() []ssh.PublicKey { +func (pubkeys *AuthorizedPublicKeys) Parse() ([]ssh.PublicKey, []string) { if pubkeys.authorizedKeysFile == "" { - return nil + return nil, nil } - keys, err := readSshPublicKeys(pubkeys.authorizedKeysFile) + keys, errorKeys, err := readSshPublicKeys(pubkeys.authorizedKeysFile) if os.IsNotExist(err) { log.Printf("Authorized keys file '%s' not found.", pubkeys.authorizedKeysFile) - return nil + return nil, nil } if err != nil { log.Println("Public key authentication will not work since no public keys were found.") } - return keys + return keys, errorKeys } func (key *AuthorizedPublicKeys) authorize(ctx ssh.Context, userProvidedKey ssh.PublicKey) bool { // - keys := key.Parse() + keys, _ := key.Parse() if len(keys) == 0 { keys = key.getPubKeys() } diff --git a/go.mod b/go.mod index 4406438..8969114 100755 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module converge -go 1.22.5 +go 1.21.9 require ( github.com/ActiveState/termtest/conpty v0.5.0