82 lines
2.0 KiB
Go
82 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"github.com/gliderlabs/ssh"
|
|
gossh "golang.org/x/crypto/ssh"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
func publicKeyHandler(ctx ssh.Context, key gossh.PublicKey, authorizedKey gossh.PublicKey) bool {
|
|
providedKey := gossh.MarshalAuthorizedKey(key)
|
|
|
|
if ssh.KeysEqual(key, authorizedKey) {
|
|
log.Printf("Successful login from %s", ctx.RemoteAddr())
|
|
return true
|
|
}
|
|
|
|
log.Printf("Failed login attempt from %s with key: %s", ctx.RemoteAddr(), strings.TrimSpace(string(providedKey)))
|
|
return false
|
|
}
|
|
|
|
func readSshPublicKeys(fileName string) ([]ssh.PublicKey, error) {
|
|
file, err := os.Open(fileName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Failed to open file: '%s': %s", fileName, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
res := make([]ssh.PublicKey, 10)
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
lineText := scanner.Text()
|
|
ind := strings.Index(lineText, "#")
|
|
if ind >= 0 {
|
|
lineText = lineText[:ind]
|
|
}
|
|
lineText = strings.Trim(lineText, "")
|
|
if lineText == "" {
|
|
continue
|
|
}
|
|
line := []byte(lineText)
|
|
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(line)
|
|
if err != nil {
|
|
log.Printf("Failed to parse authorized key: %v", lineText)
|
|
} else {
|
|
res = append(res, parsedKey)
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
type AuthorizedPublicKeys struct {
|
|
keys []ssh.PublicKey
|
|
}
|
|
|
|
func ParseOpenSSHAuthorizedKeysFile(authorizedKeysFile string) AuthorizedPublicKeys {
|
|
if authorizedKeysFile == "" {
|
|
return AuthorizedPublicKeys{}
|
|
}
|
|
keys, err := readSshPublicKeys(authorizedKeysFile)
|
|
if os.IsNotExist(err) {
|
|
log.Printf("Authorized keys file '%s' not found.", authorizedKeysFile)
|
|
return AuthorizedPublicKeys{}
|
|
}
|
|
if err != nil {
|
|
log.Println("Public key authentication will not work since no public keys were found.")
|
|
}
|
|
return AuthorizedPublicKeys{keys: keys}
|
|
}
|
|
|
|
func (key AuthorizedPublicKeys) authorize(ctx ssh.Context, userProvidedKey ssh.PublicKey) bool {
|
|
for _, key := range key.keys {
|
|
if publicKeyHandler(ctx, userProvidedKey, key) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|