1
1
package cluster
2
2
3
3
import (
4
+ "bufio"
5
+ "bytes"
4
6
"crypto/rand"
5
7
"encoding/base64"
6
8
"fmt"
@@ -11,49 +13,63 @@ import (
11
13
"github.com/code-ready/crc/pkg/crc/constants"
12
14
"github.com/code-ready/crc/pkg/crc/logging"
13
15
"github.com/code-ready/crc/pkg/crc/oc"
14
- crcos "github.com/code-ready/crc/pkg/os"
15
16
"golang.org/x/crypto/bcrypt"
16
17
)
17
18
18
- // UpdateKubeAdminUserPassword does following
19
- // - Create and put updated kubeadmin password to ~/.crc/machine/crc/kubeadmin-password
20
- // - Update the htpasswd secret
21
- func UpdateKubeAdminUserPassword (ocConfig oc.Config , kubeAdminPassword string ) error {
22
- var err error
19
+ // GenerateKubeAdminUserPassword creates and put updated kubeadmin password to ~/.crc/machine/crc/kubeadmin-password
20
+ func GenerateKubeAdminUserPassword () error {
21
+ logging .Infof ("Generating new password for the kubeadmin user" )
23
22
kubeAdminPasswordFile := constants .GetKubeAdminPasswordPath ()
24
- if crcos . FileExists ( kubeAdminPasswordFile ) {
25
- logging . Debugf ( "kubeadmin password has already been updated" )
26
- return nil
23
+ kubeAdminPassword , err := GenerateRandomPasswordHash ( 23 )
24
+ if err != nil {
25
+ return fmt . Errorf ( "Cannot generate the kubeadmin user password: %w" , err )
27
26
}
27
+ return ioutil .WriteFile (kubeAdminPasswordFile , []byte (kubeAdminPassword ), 0600 )
28
+ }
28
29
29
- if kubeAdminPassword == "" {
30
- logging .Infof ("Generating new password for the kubeadmin user" )
31
- kubeAdminPassword , err = GenerateRandomPasswordHash (23 )
32
- if err != nil {
33
- return fmt .Errorf ("Cannot generate the kubeadmin user password: %w" , err )
30
+ // UpdateKubeAdminUserPassword updates the htpasswd secret
31
+ func UpdateKubeAdminUserPassword (ocConfig oc.Config , newPassword string ) error {
32
+ if newPassword != "" {
33
+ logging .Infof ("Overriding password for kubeadmin user" )
34
+ if err := ioutil .WriteFile (constants .GetKubeAdminPasswordPath (), []byte (strings .TrimSpace (newPassword )), 0600 ); err != nil {
35
+ return err
34
36
}
35
37
}
36
38
37
- hashDeveloperPasswd , err := hashBcrypt ( "developer" )
39
+ kubeAdminPassword , err := GetKubeadminPassword ( )
38
40
if err != nil {
39
- return err
41
+ return fmt .Errorf ("Cannot generate the kubeadmin user password: %w" , err )
42
+ }
43
+ credentials := map [string ]string {
44
+ "developer" : "developer" ,
45
+ "kubeadmin" : kubeAdminPassword ,
40
46
}
41
47
42
- hashKubeAdminPasswd , err := hashBcrypt (kubeAdminPassword )
48
+ given , _ , err := ocConfig .RunOcCommandPrivate ("get" , "secret" , "htpass-secret" , "-n" , "openshift-config" , "-o" , `jsonpath="{.data.htpasswd}"` )
49
+ if err != nil {
50
+ return err
51
+ }
52
+ ok , err := compareHtpasswd (given , credentials )
43
53
if err != nil {
44
54
return err
45
55
}
46
- base64Data := getBase64 (hashDeveloperPasswd , hashKubeAdminPasswd )
56
+ if ok {
57
+ return nil
58
+ }
47
59
60
+ logging .Infof ("Changing the password for the kubeadmin user" )
61
+ expected , err := getHtpasswd (credentials )
62
+ if err != nil {
63
+ return err
64
+ }
48
65
cmdArgs := []string {"patch" , "secret" , "htpass-secret" , "-p" ,
49
- fmt .Sprintf (`'{"data":{"htpasswd":"%s"}}'` , base64Data ),
66
+ fmt .Sprintf (`'{"data":{"htpasswd":"%s"}}'` , expected ),
50
67
"-n" , "openshift-config" , "--type" , "merge" }
51
68
_ , stderr , err := ocConfig .RunOcCommandPrivate (cmdArgs ... )
52
69
if err != nil {
53
70
return fmt .Errorf ("Failed to update kubeadmin password %v: %s" , err , stderr )
54
71
}
55
-
56
- return ioutil .WriteFile (kubeAdminPasswordFile , []byte (kubeAdminPassword ), 0600 )
72
+ return nil
57
73
}
58
74
59
75
func GetKubeadminPassword () (string , error ) {
@@ -110,7 +126,63 @@ func hashBcrypt(password string) (hash string, err error) {
110
126
return string (passwordBytes ), nil
111
127
}
112
128
113
- func getBase64 (developerUserPassword , adminUserPassword string ) string {
114
- s := fmt .Sprintf ("developer:%s\n kubeadmin:%s" , developerUserPassword , adminUserPassword )
115
- return base64 .StdEncoding .EncodeToString ([]byte (s ))
129
+ func getHtpasswd (credentials map [string ]string ) (string , error ) {
130
+ var ret []string
131
+ for username , password := range credentials {
132
+ hash , err := hashBcrypt (password )
133
+ if err != nil {
134
+ return "" , err
135
+ }
136
+ ret = append (ret , fmt .Sprintf ("%s:%s" , username , hash ))
137
+ }
138
+ return base64 .StdEncoding .EncodeToString ([]byte (strings .Join (ret , "\n " ))), nil
139
+ }
140
+
141
+ // source https://github.com/openshift/oauth-server/blob/04985077512fec241a5170074bf767c23592d7e7/pkg/authenticator/password/htpasswd/htpasswd.go
142
+ func compareHtpasswd (given string , credentials map [string ]string ) (bool , error ) {
143
+ decoded , err := base64 .StdEncoding .DecodeString (given )
144
+ if err != nil {
145
+ return false , err
146
+ }
147
+ scanner := bufio .NewScanner (bytes .NewReader (decoded ))
148
+
149
+ found := 0
150
+ for scanner .Scan () {
151
+ line := scanner .Text ()
152
+ if len (line ) == 0 {
153
+ continue
154
+ }
155
+ parts := strings .SplitN (line , ":" , 2 )
156
+ if len (parts ) != 2 {
157
+ continue
158
+ }
159
+ username := parts [0 ]
160
+ password := parts [1 ]
161
+
162
+ if expectedPassword , ok := credentials [username ]; ok {
163
+ ok , err := testBCryptPassword (expectedPassword , password )
164
+ if err != nil {
165
+ return false , err
166
+ }
167
+ if ! ok {
168
+ return false , nil
169
+ }
170
+ found ++
171
+ }
172
+ }
173
+ if found != len (credentials ) {
174
+ return false , nil
175
+ }
176
+ return true , nil
177
+ }
178
+
179
+ func testBCryptPassword (password , hash string ) (bool , error ) {
180
+ err := bcrypt .CompareHashAndPassword ([]byte (hash ), []byte (password ))
181
+ if err == bcrypt .ErrMismatchedHashAndPassword {
182
+ return false , nil
183
+ }
184
+ if err != nil {
185
+ return false , err
186
+ }
187
+ return true , nil
116
188
}
0 commit comments