|
1 | 1 | package login
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "crypto/tls" |
| 5 | + "fmt" |
4 | 6 | "net/http"
|
5 | 7 | "net/http/httptest"
|
| 8 | + "regexp" |
6 | 9 | "strings"
|
7 | 10 | "testing"
|
8 | 11 |
|
| 12 | + "github.com/MakeNowJust/heredoc" |
| 13 | + |
9 | 14 | "github.com/openshift/origin/pkg/cmd/cli/config"
|
10 | 15 | "github.com/openshift/origin/pkg/cmd/util/clientcmd"
|
11 | 16 |
|
12 | 17 | "k8s.io/kubernetes/pkg/client/restclient"
|
| 18 | + kclientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" |
13 | 19 | )
|
14 | 20 |
|
15 | 21 | func TestNormalizeServerURL(t *testing.T) {
|
@@ -55,6 +61,163 @@ func TestNormalizeServerURL(t *testing.T) {
|
55 | 61 | }
|
56 | 62 | }
|
57 | 63 |
|
| 64 | +func TestTLSWithCertificateNotMatchingHostname(t *testing.T) { |
| 65 | + // generated by 'go run src/crypto/tls/generate_cert.go --rsa-bits 1024 --host invalidhost.com,8.8.8.8 --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h' |
| 66 | + invalidHostCert := heredoc.Doc(` |
| 67 | + -----BEGIN CERTIFICATE----- |
| 68 | + MIICBjCCAW+gAwIBAgIRALOIWXyeLzunaiVkP2itHAEwDQYJKoZIhvcNAQELBQAw |
| 69 | + EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2 |
| 70 | + MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw |
| 71 | + gYkCgYEAuKDlC4aMBbHaXgS+MFud5h3zeE4boSqKgFI6HceySF/a+qg0v+ID6EwQ |
| 72 | + DpJ2W5AdJGEBfixo+tym6q3oKWHJUX0hInkJ6dXIdUbVOeO5dIsGG0fZmRD7DDDx |
| 73 | + snkXrDB/E0JglHNckRbIh/jvznbDfbddIcdgZ7JVIfnNpigtHZECAwEAAaNaMFgw |
| 74 | + DgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQF |
| 75 | + MAMBAf8wIAYDVR0RBBkwF4IPaW52YWxpZGhvc3QuY29thwQICAgIMA0GCSqGSIb3 |
| 76 | + DQEBCwUAA4GBAAkPU044aFkBl4f/muwSh/oPGinnA4fp8ei0KMnLk+0/CjNb3Waa |
| 77 | + GtuRVIudRTK2M/RzdpUrwfWlVmkezV4BR1K/aOH9a29zqDTkEjnkIbWwe+piAs+w |
| 78 | + VxIxrTqM8rqq8qxeWS54AyF/OaLJgXzDpCFnCb7kY3iyHv6lcmCjluLW |
| 79 | + -----END CERTIFICATE-----`) |
| 80 | + invalidHostKey := heredoc.Doc(` |
| 81 | + -----BEGIN RSA PRIVATE KEY----- |
| 82 | + MIICXQIBAAKBgQC4oOULhowFsdpeBL4wW53mHfN4ThuhKoqAUjodx7JIX9r6qDS/ |
| 83 | + 4gPoTBAOknZbkB0kYQF+LGj63KbqregpYclRfSEieQnp1ch1RtU547l0iwYbR9mZ |
| 84 | + EPsMMPGyeResMH8TQmCUc1yRFsiH+O/OdsN9t10hx2BnslUh+c2mKC0dkQIDAQAB |
| 85 | + AoGAZ0ZAuNC7NFhHEL5QcJZe3aC1Vv9B/0XfkWXtckkJFejggcNjNk5D50Xc2Xnd |
| 86 | + 0NvtITNN9Xj8BA83IyDCM5uqUwDbOLIc6qYgAGWzxZZSDAQg1iOAAZoXmMTNS6Zf |
| 87 | + hQhNUIwB68ELGvbcq7cxQL7L9n4GfISz7PKOOUKTZp0Q8G0CQQD07K7NES340c3I |
| 88 | + QVkCW5/ygNK0GuQ8nTcG5yC8R5SDS47N8YzPp17Pajah8+wawYiemY1fUmD7P/bq |
| 89 | + Cjl2RtIHAkEAwPo1GzJubN7PSYgPir3TxUGtMJoyc3jfdjblXyGJHwTu2YxeRjd2 |
| 90 | + YUPVRpu9JvNjZc+GONvTbTZeNWCvy0JNpwJBAKEsi49JCd6eefOZBTDnCKd1nLKG |
| 91 | + q8Ezl/2D5WfhFtsbwrrFhOs1cc++Tnte3/VvfC8aTwz2UfmkyyCSX+P0kMsCQCIL |
| 92 | + glb7/LNEU7mbQXKurq+8OHu8mG36wyGt6aVw2yoXyrOiqfclTcM3HmdIjoRSqBSM |
| 93 | + Ghfp4FECKHiuSBVJ6z0CQQDF37CRpdQRDPnAedhyApLcIxSbYo1oUm7FxBLyVb7V |
| 94 | + HQjFvsOylsSCABXz0FyC7zXQxkEo6CiSahVI/PHz6Zta |
| 95 | + -----END RSA PRIVATE KEY-----`) |
| 96 | + |
| 97 | + server, err := newTLSServer(invalidHostCert, invalidHostKey) |
| 98 | + if err != nil { |
| 99 | + t.Errorf(err.Error()) |
| 100 | + } |
| 101 | + server.StartTLS() |
| 102 | + defer server.Close() |
| 103 | + |
| 104 | + testCases := map[string]struct { |
| 105 | + serverURL string |
| 106 | + skipTLSVerify bool |
| 107 | + expectedErrMsg *regexp.Regexp |
| 108 | + }{ |
| 109 | + "succeed skipping tls": { |
| 110 | + serverURL: server.URL, |
| 111 | + skipTLSVerify: true, |
| 112 | + }, |
| 113 | + "certificate hostname doesn't match": { |
| 114 | + serverURL: server.URL, |
| 115 | + expectedErrMsg: regexp.MustCompile(`The server is using a certificate that does not match its hostname(.*)is valid for 8\.8\.8\.8`), |
| 116 | + }, |
| 117 | + } |
| 118 | + |
| 119 | + for name, test := range testCases { |
| 120 | + t.Logf("evaluating test: %s", name) |
| 121 | + options := &LoginOptions{ |
| 122 | + Server: test.serverURL, |
| 123 | + InsecureTLS: test.skipTLSVerify, |
| 124 | + StartingKubeConfig: &kclientcmdapi.Config{}, |
| 125 | + } |
| 126 | + |
| 127 | + if _, err = options.getClientConfig(); err != nil { |
| 128 | + if !test.expectedErrMsg.MatchString(err.Error()) { |
| 129 | + t.Errorf("%s: expected error %q but got %q", name, test.expectedErrMsg, err) |
| 130 | + } |
| 131 | + if test.expectedErrMsg == nil { |
| 132 | + t.Errorf("%s: unexpected error: %v", name, err) |
| 133 | + } |
| 134 | + } else { |
| 135 | + if test.expectedErrMsg != nil { |
| 136 | + t.Errorf("%s: expected error but got nothing", name) |
| 137 | + } |
| 138 | + } |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +func TestTLSWithExpiredCertificate(t *testing.T) { |
| 143 | + // generated by 'go run src/crypto/tls/generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1h' |
| 144 | + expiredCert := heredoc.Doc(` |
| 145 | + -----BEGIN CERTIFICATE----- |
| 146 | + MIICEjCCAXugAwIBAgIRALf82bYpro/jQS8fP74dG5EwDQYJKoZIhvcNAQELBQAw |
| 147 | + EjEQMA4GA1UEChMHQWNtZSBDbzAeFw03MDAxMDEwMDAwMDBaFw03MDAxMDEwMTAw |
| 148 | + MDBaMBIxEDAOBgNVBAoTB0FjbWUgQ28wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ |
| 149 | + AoGBAONNgDXBk2Q1i/aJjTwt03KpQ3nQblMS3IX/H9JWw6ta6UublKBOaD/2o5Xt |
| 150 | + FM+Q7XDEnzYw88CK5KHdyejkJo5IBpUjQYJZFzUJ1BC8Lw7yy6dXWYBJboRR1S+1 |
| 151 | + JhkMJOtpPecv+4cTaynplYj0WMBjcQthg2RM7tdpyUYpsp2rAgMBAAGjaDBmMA4G |
| 152 | + A1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTAD |
| 153 | + AQH/MC4GA1UdEQQnMCWCC2V4YW1wbGUuY29thwR/AAABhxAAAAAAAAAAAAAAAAAA |
| 154 | + AAABMA0GCSqGSIb3DQEBCwUAA4GBAFpdiiM5YAQQN0H5ZMNuHWGlprjp7qVilO8/ |
| 155 | + WFePZRWY2vQF8g7/c1cX4bPqG+qFJd+9j2UZNjhadNfMCxvu6BY7NCupOHVHmnRQ |
| 156 | + ocvkPoSqobE7qDPfiUuU1J+61Libu6b2IjV3/K9pvZkLiBrqn0YhoXXa0PG+rG1L |
| 157 | + 9X7+mb5z |
| 158 | + -----END CERTIFICATE-----`) |
| 159 | + expiredKey := heredoc.Doc(` |
| 160 | + -----BEGIN RSA PRIVATE KEY----- |
| 161 | + MIICXQIBAAKBgQDjTYA1wZNkNYv2iY08LdNyqUN50G5TEtyF/x/SVsOrWulLm5Sg |
| 162 | + Tmg/9qOV7RTPkO1wxJ82MPPAiuSh3cno5CaOSAaVI0GCWRc1CdQQvC8O8sunV1mA |
| 163 | + SW6EUdUvtSYZDCTraT3nL/uHE2sp6ZWI9FjAY3ELYYNkTO7XaclGKbKdqwIDAQAB |
| 164 | + AoGBAJPFWKqZ9CZboWhfuE/9Qs/yNonE9VRQmMkMOTXXblHCQpUCyjcFgkTDJUpc |
| 165 | + 3QCsKZD8Yr0qSe1M3qJUu+UKHf18LqwiL/ynnalYggxIFS5/SidWCngKvIuEfkLK |
| 166 | + VsnCK3jt5qx21iljGHU6bQZHnHB9IGEiBYcnQlvvw/WdvRDBAkEA8/KMpJVwnI1W |
| 167 | + 7fzcZ1+mbMeSJoAVIa9u7MgI+LIRZMokDRYeAMvEjm3GYpZDqA5l1dp7KochMep/ |
| 168 | + 0vSSTHt7ewJBAO6IbcUIDhXuh2qdxR/Xk5DdDCoxaD1o4ivyj9JsSlGa9JWD7kKN |
| 169 | + 6ZFFrn8i7uQuniC1Rwc/4yHhs6OqbiF695ECQQCBwVKzvFUwwDEr1yK4zXStSZ3g |
| 170 | + YqJaz4CV63RyK+z6ilaQq2H8FGaRR6yNBdYozre1/0ciAMxUS6H/6Fzk141/AkBe |
| 171 | + SguqIP8AaGObH3Z2mc65KsfOPe2IqNcOrDlx4mCWVXxtRdN+933mcPcDRpnMFSlo |
| 172 | + oH/NO9Ha6M8L2SjjjyohAkBJHU61+OWz/TAy1nxsMbFsISLn/JrdEZIf2uFORlDN |
| 173 | + Z3/XIQ+yeg4Jk1VbTMZ0/fHf9xMFR8acC/7n7jxnzQau |
| 174 | + -----END RSA PRIVATE KEY-----`) |
| 175 | + |
| 176 | + server, err := newTLSServer(expiredCert, expiredKey) |
| 177 | + if err != nil { |
| 178 | + t.Errorf(err.Error()) |
| 179 | + } |
| 180 | + server.StartTLS() |
| 181 | + defer server.Close() |
| 182 | + |
| 183 | + testCases := map[string]struct { |
| 184 | + serverURL string |
| 185 | + skipTLSVerify bool |
| 186 | + expectedErrMsg *regexp.Regexp |
| 187 | + }{ |
| 188 | + "succeed skipping tls": { |
| 189 | + serverURL: server.URL, |
| 190 | + skipTLSVerify: true, |
| 191 | + }, |
| 192 | + "certificate expired": { |
| 193 | + serverURL: server.URL, |
| 194 | + expectedErrMsg: regexp.MustCompile(`The server is using an invalid certificate(.*)has expired`), |
| 195 | + }, |
| 196 | + } |
| 197 | + |
| 198 | + for name, test := range testCases { |
| 199 | + t.Logf("evaluating test: %s", name) |
| 200 | + options := &LoginOptions{ |
| 201 | + Server: test.serverURL, |
| 202 | + InsecureTLS: test.skipTLSVerify, |
| 203 | + StartingKubeConfig: &kclientcmdapi.Config{}, |
| 204 | + } |
| 205 | + |
| 206 | + if _, err = options.getClientConfig(); err != nil { |
| 207 | + if !test.expectedErrMsg.MatchString(err.Error()) { |
| 208 | + t.Errorf("%s: expected error %q but got %q", name, test.expectedErrMsg, err) |
| 209 | + } |
| 210 | + if test.expectedErrMsg == nil { |
| 211 | + t.Errorf("%s: unexpected error: %v", name, err) |
| 212 | + } |
| 213 | + } else { |
| 214 | + if test.expectedErrMsg != nil { |
| 215 | + t.Errorf("%s: expected error but got nothing", name) |
| 216 | + } |
| 217 | + } |
| 218 | + } |
| 219 | +} |
| 220 | + |
58 | 221 | func TestDialToHTTPServer(t *testing.T) {
|
59 | 222 | invoked := make(chan struct{}, 1)
|
60 | 223 | server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
@@ -92,3 +255,60 @@ func TestDialToHTTPServer(t *testing.T) {
|
92 | 255 | }
|
93 | 256 | }
|
94 | 257 | }
|
| 258 | + |
| 259 | +func TestDialToHTTPSServer(t *testing.T) { |
| 260 | + invoked := make(chan struct{}, 1) |
| 261 | + server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 262 | + invoked <- struct{}{} |
| 263 | + w.WriteHeader(http.StatusOK) |
| 264 | + })) |
| 265 | + defer server.Close() |
| 266 | + |
| 267 | + testCases := map[string]struct { |
| 268 | + serverURL string |
| 269 | + skipTLSVerify bool |
| 270 | + evalExpectedErr func(error) bool |
| 271 | + }{ |
| 272 | + "succeed dialing": { |
| 273 | + serverURL: server.URL, |
| 274 | + skipTLSVerify: true, |
| 275 | + }, |
| 276 | + "certificate unknown": { |
| 277 | + serverURL: server.URL, |
| 278 | + evalExpectedErr: clientcmd.IsCertificateAuthorityUnknown, |
| 279 | + }, |
| 280 | + } |
| 281 | + |
| 282 | + for name, test := range testCases { |
| 283 | + t.Logf("evaluating test: %s", name) |
| 284 | + clientConfig := &restclient.Config{ |
| 285 | + Host: test.serverURL, |
| 286 | + Insecure: test.skipTLSVerify, |
| 287 | + } |
| 288 | + if err := dialToServer(*clientConfig); err != nil { |
| 289 | + if test.evalExpectedErr == nil || !test.evalExpectedErr(err) { |
| 290 | + t.Errorf("%s: unexpected error: %v", name, err) |
| 291 | + } |
| 292 | + } else { |
| 293 | + if test.evalExpectedErr != nil { |
| 294 | + t.Errorf("%s: expected error but got nothing", name) |
| 295 | + } |
| 296 | + } |
| 297 | + } |
| 298 | +} |
| 299 | + |
| 300 | +func newTLSServer(certString, keyString string) (*httptest.Server, error) { |
| 301 | + invoked := make(chan struct{}, 1) |
| 302 | + server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 303 | + invoked <- struct{}{} |
| 304 | + w.WriteHeader(http.StatusOK) |
| 305 | + })) |
| 306 | + cert, err := tls.X509KeyPair([]byte(certString), []byte(keyString)) |
| 307 | + if err != nil { |
| 308 | + return nil, fmt.Errorf("error configuring server cert: %s", err) |
| 309 | + } |
| 310 | + server.TLS = &tls.Config{ |
| 311 | + Certificates: []tls.Certificate{cert}, |
| 312 | + } |
| 313 | + return server, nil |
| 314 | +} |
0 commit comments