This repository has been archived by the owner on Oct 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
TestUser.go
135 lines (118 loc) · 3.75 KB
/
TestUser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package sshserver
import (
"bytes"
cryptoRand "crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"math/rand"
"strings"
"time"
"golang.org/x/crypto/ssh"
)
// TestUser is a container for a username, a password and public keys
type TestUser struct {
username string
password string
keyboardInteractive map[string]string
privateKeys []*rsa.PrivateKey
authorizedKeys []string
}
// Username returns the username of this user.
func (u *TestUser) Username() string {
return u.username
}
// Password returns the current password for this user.
func (u *TestUser) Password() string {
return u.password
}
// SetPassword sets a specific password for this user.
func (u *TestUser) SetPassword(password string) {
u.password = password
}
// AddKeyboardInteractiveChallengeResponse adds a challenge with an expected response for keyboard-interactive
// authentication.
func (u *TestUser) AddKeyboardInteractiveChallengeResponse(challenge string, expectedResponse string) {
u.keyboardInteractive[challenge] = expectedResponse
}
// KeyboardInteractiveChallengeResponse returns a construct of KeyboardInteractiveQuestions
func (u *TestUser) KeyboardInteractiveChallengeResponse() (questions KeyboardInteractiveQuestions) {
for question := range u.keyboardInteractive {
questions = append(questions, KeyboardInteractiveQuestion{
Question: question,
EchoResponse: false,
})
}
return
}
// RandomPassword generates a random password for this user.
func (u *TestUser) RandomPassword() {
random := rand.New(rand.NewSource(time.Now().UnixNano()))
length := 16
runes := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789!%$#-_=+")
var passwordBuilder strings.Builder
for i := 0; i < length; i++ {
passwordBuilder.WriteRune(runes[random.Intn(len(runes))])
}
u.password = passwordBuilder.String()
}
// GenerateKey generates a public and private key pair that can be used to authenticate with this user.
func (u *TestUser) GenerateKey() (privateKeyPEM string, publicKeyAuthorizedKeys string) {
privateKey, err := rsa.GenerateKey(cryptoRand.Reader, 4096)
if err != nil {
panic(err)
}
privPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}
var privateKeyPEMBuffer bytes.Buffer
if err := pem.Encode(&privateKeyPEMBuffer, privPEM); err != nil {
panic(err)
}
privateKeyPEM = privateKeyPEMBuffer.String()
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
panic(err)
}
publicKeyAuthorizedKeys = string(ssh.MarshalAuthorizedKey(pub))
u.privateKeys = append(u.privateKeys, privateKey)
u.authorizedKeys = append(u.authorizedKeys, privateKeyPEM)
return privateKeyPEM, publicKeyAuthorizedKeys
}
// GetAuthorizedKeys returns a slice of the authorized keys of this user.
func (u *TestUser) GetAuthorizedKeys() []string {
return u.authorizedKeys
}
func (u *TestUser) getAuthMethods() []ssh.AuthMethod {
var result []ssh.AuthMethod
if u.password != "" {
result = append(result, ssh.Password(u.password))
}
var pubKeys []ssh.Signer
for _, privateKey := range u.privateKeys {
signer, err := ssh.NewSignerFromKey(privateKey)
if err != nil {
panic(err)
}
pubKeys = append(pubKeys, signer)
}
result = append(result, ssh.PublicKeys(pubKeys...))
if len(u.keyboardInteractive) > 0 {
result = append(result, ssh.KeyboardInteractive(
func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
for _, question := range questions {
if answer, ok := u.keyboardInteractive[question]; ok {
answers = append(answers, answer)
} else {
return nil, fmt.Errorf("unexpected keybord-interactive challenge: %s", question)
}
}
return answers, nil
}))
}
return result
}