package auth import ( "bufio" "bytes" "fmt" "os" "strings" "github.com/go-crypt/crypt" "golang.org/x/crypto/ssh" "git.maze.io/maze/conduit/logger" "git.maze.io/maze/conduit/ssh/sshutil" ) type passwordFile map[string]string func PasswordFile(name string) (Password, error) { f, err := os.Open(name) if err != nil { return nil, err } s := bufio.NewScanner(f) p := make(passwordFile) for s.Scan() { line := s.Text() if len(line) == 0 || line[0] == '#' || strings.HasPrefix(line, "//") { continue } if i := strings.IndexByte(line, ':'); i > 0 { p[line[:i]] = line[i+1:] } } return p, s.Err() } func (auth passwordFile) VerifyPassword(meta ssh.ConnMetadata, password string) (Principal, error) { encodedDigest := auth[meta.User()] if ok, err := crypt.CheckPasswordWithPlainText(password, encodedDigest); err != nil { return nil, err } else if !ok { return nil, ErrUnauthorized } return MakePasswordPrincipal(meta), nil } type publibKeyFile map[string][]ssh.PublicKey func PublicKeyFile(name string) (PublicKey, error) { log := logger.StandardLog.Value("path", name) log.Trace("Parsing public keys file") f, err := os.Open(name) if err != nil { return nil, err } var ( s = bufio.NewScanner(f) p = make(publibKeyFile) lineno int ) for s.Scan() { line := s.Text() lineno++ if len(line) == 0 || line[0] == '#' || strings.HasPrefix(line, "//") { continue } if i := strings.IndexByte(line, ':'); i > 0 { //k, err := ssh.ParsePublicKey([]byte(line[i+1:])) k, _, _, _, err := ssh.ParseAuthorizedKey([]byte(line[i+1:])) if err != nil { return nil, fmt.Errorf("auth: invalid public key in %s:%d: %w", name, lineno, err) } log.Values(logger.Values{ "user": line[:i], "key": k.Type(), }).Trace("Parsed authorized public key") p[line[:i]] = append(p[line[:i]], k) } } return p, s.Err() } func (auth publibKeyFile) VerifyPublicKey(meta ssh.ConnMetadata, key ssh.PublicKey) (Principal, error) { log := logger.StandardLog.Values(logger.Values{ "client": meta.RemoteAddr().String(), "key_type": sshutil.KeyType(key), "key_bits": sshutil.KeyBits(key), "user": meta.User(), "version": string(meta.ClientVersion()), }) log.Debug("Verifying user public key") blob := key.Marshal() keys := auth[meta.User()] for _, other := range keys { if bytes.Equal(other.Marshal(), blob) { return MakePublicKeyPrincipal(meta, key), nil } } return nil, ErrUnauthorized }