better messages when the user modifies the .authorized_keys file from

within the session.
This commit is contained in:
Erik Brakkee 2024-08-06 22:28:34 +02:00
parent d109c72f66
commit d134f1e944
3 changed files with 34 additions and 25 deletions

View File

@ -329,9 +329,12 @@ func main() {
// Authentiocation // Authentiocation
authorizedKeys := NewAuthorizedPublicKeys(authorizedKeysFile) authorizedKeys, err := NewAuthorizedPublicKeys(authorizedKeysFile)
if err != nil {
os.Exit(1)
}
// initial check // initial check
pubkeys := authorizedKeys.Parse() pubkeys, _ := authorizedKeys.Parse()
if len(pubkeys) == 0 { if len(pubkeys) == 0 {
log.Printf("No public keys found in '%s', exiting", authorizedKeysFile) log.Printf("No public keys found in '%s', exiting", authorizedKeysFile)
os.Exit(1) os.Exit(1)

View File

@ -26,15 +26,16 @@ func publicKeyHandler(ctx ssh.Context, key gossh.PublicKey, authorizedKey gossh.
return false return false
} }
func readSshPublicKeys(fileName string) ([]ssh.PublicKey, error) { func readSshPublicKeys(fileName string) ([]ssh.PublicKey, []string, error) {
file, err := os.Open(fileName) file, err := os.Open(fileName)
if err != nil { 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() defer file.Close()
res := make([]ssh.PublicKey, 0) res := make([]ssh.PublicKey, 0)
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
var errorKeys []string
for scanner.Scan() { for scanner.Scan() {
lineText := scanner.Text() lineText := scanner.Text()
ind := strings.Index(lineText, "#") ind := strings.Index(lineText, "#")
@ -49,12 +50,13 @@ func readSshPublicKeys(fileName string) ([]ssh.PublicKey, error) {
line := []byte(lineText) line := []byte(lineText)
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(line) parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(line)
if err != nil { if err != nil {
errorKeys = append(errorKeys, lineText)
log.Printf("Failed to parse authorized key: %v", lineText) log.Printf("Failed to parse authorized key: %v", lineText)
} else { } else {
res = append(res, parsedKey) res = append(res, parsedKey)
} }
} }
return res, nil return res, errorKeys, nil
} }
type AuthorizedPublicKeys struct { type AuthorizedPublicKeys struct {
@ -63,18 +65,18 @@ type AuthorizedPublicKeys struct {
publicKeys []ssh.PublicKey publicKeys []ssh.PublicKey
} }
func NewAuthorizedPublicKeys(authorizedKeysFile string) *AuthorizedPublicKeys { func NewAuthorizedPublicKeys(authorizedKeysFile string) (*AuthorizedPublicKeys, error) {
pubkeys := AuthorizedPublicKeys{ pubkeys := AuthorizedPublicKeys{
authorizedKeysFile: authorizedKeysFile, authorizedKeysFile: authorizedKeysFile,
mutex: sync.Mutex{}, mutex: sync.Mutex{},
publicKeys: nil, 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) go pubkeys.monitorAuthorizedKeysFile(authorizedKeysFile)
return &pubkeys return &pubkeys, nil
}
func (pubkeys *AuthorizedPublicKeys) notifyUsers(message string) {
session.MessageUsers(message)
} }
func (pubkeys *AuthorizedPublicKeys) setPubKeys(keys []ssh.PublicKey) { func (pubkeys *AuthorizedPublicKeys) setPubKeys(keys []ssh.PublicKey) {
@ -106,30 +108,34 @@ func (pubkeys *AuthorizedPublicKeys) monitorAuthorizedKeysFile(authorizedPublicK
select { select {
case event, ok := <-watcher.Events: case event, ok := <-watcher.Events:
if !ok { if !ok {
pubkeys.notifyUsers( session.MessageUsers(
fmt.Sprintf("Watching authorized keys file '%s' stopped", authorizedPublicKeysFile)) fmt.Sprintf("Watching authorized keys file '%s' stopped", authorizedPublicKeysFile))
return return
} }
base := filepath.Base(event.Name) base := filepath.Base(event.Name)
log.Println("CHANGE " + base + " " + authorizedPublicKeysFile + " " + filepath.Base(authorizedPublicKeysFile)) log.Println("CHANGE " + base + " " + authorizedPublicKeysFile + " " + filepath.Base(authorizedPublicKeysFile))
if base == 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 { if len(keys) == 0 {
pubkeys.notifyUsers( session.MessageUsers(
fmt.Sprintf("Authorized keys file '%s' does not contain any valid keys, using last known configuration", authorizedPublicKeysFile)) fmt.Sprintf("Authorized keys file '%s' does not exist or does not contain any valid keys, using last known configuration", authorizedPublicKeysFile))
} else { } 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) pubkeys.setPubKeys(keys)
} }
} }
case err, ok := <-watcher.Errors: case err, ok := <-watcher.Errors:
if ok { if ok {
pubkeys.notifyUsers(fmt.Sprintf( session.MessageUsers(fmt.Sprintf(
"Watching authorized keys file '%s' stopped", "Watching authorized keys file '%s' stopped",
pubkeys.authorizedKeysFile)) pubkeys.authorizedKeysFile))
} }
pubkeys.notifyUsers(fmt.Sprintf( session.MessageUsers(fmt.Sprintf(
"Watching authorized keys file '%s' stopped: %v", "Watching authorized keys file '%s' stopped: %v",
pubkeys.authorizedKeysFile, err)) pubkeys.authorizedKeysFile, err))
return 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 == "" { if pubkeys.authorizedKeysFile == "" {
return nil return nil, nil
} }
keys, err := readSshPublicKeys(pubkeys.authorizedKeysFile) keys, errorKeys, err := readSshPublicKeys(pubkeys.authorizedKeysFile)
if os.IsNotExist(err) { if os.IsNotExist(err) {
log.Printf("Authorized keys file '%s' not found.", pubkeys.authorizedKeysFile) log.Printf("Authorized keys file '%s' not found.", pubkeys.authorizedKeysFile)
return nil return nil, nil
} }
if err != nil { if err != nil {
log.Println("Public key authentication will not work since no public keys were found.") 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 { func (key *AuthorizedPublicKeys) authorize(ctx ssh.Context, userProvidedKey ssh.PublicKey) bool {
// //
keys := key.Parse() keys, _ := key.Parse()
if len(keys) == 0 { if len(keys) == 0 {
keys = key.getPubKeys() keys = key.getPubKeys()
} }

2
go.mod
View File

@ -1,6 +1,6 @@
module converge module converge
go 1.22.5 go 1.21.9
require ( require (
github.com/ActiveState/termtest/conpty v0.5.0 github.com/ActiveState/termtest/conpty v0.5.0