package validation import ( "io/ioutil" "os" "strings" "testing" "github.com/openshift/origin/pkg/cmd/server/api" ) func TestValidateServingInfo(t *testing.T) { certFile, err := ioutil.TempFile("", "cert.crt") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(certFile.Name()) certFileName := certFile.Name() ioutil.WriteFile(certFile.Name(), localhostCert, os.FileMode(0755)) keyFile, err := ioutil.TempFile("", "cert.key") if err != nil { t.Fatalf("unexpected error: %v", err) } defer os.Remove(keyFile.Name()) keyFileName := keyFile.Name() ioutil.WriteFile(keyFile.Name(), localhostKey, os.FileMode(0755)) testcases := map[string]struct { ServingInfo api.ServingInfo ExpectedErrors []string ExpectedWarnings []string }{ "basic": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", }, }, "missing key": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{ CertFile: certFileName, }, }, ExpectedErrors: []string{"keyFile: Required value"}, }, "namedCertificates valid": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"example.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, }, "namedCertificates without default cert": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", //ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"example.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedErrors: []string{"namedCertificates: Invalid value"}, }, "namedCertificates with missing names": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{ /*"example.com"*/ }, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedErrors: []string{"namedCertificates[0].names: Required value"}, }, "namedCertificates with missing key": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"example.com"}, CertInfo: api.CertInfo{CertFile: certFileName /*, KeyFile: keyFileName*/}}, }, }, ExpectedErrors: []string{"namedCertificates[0].keyFile: Required value"}, }, "namedCertificates with duplicate names": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"example.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, {Names: []string{"example.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedErrors: []string{"namedCertificates[1].names[0]: Invalid value"}, }, "namedCertificates with empty name": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{""}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedErrors: []string{"namedCertificates[0].names[0]: Required value"}, }, "namedCertificates with unmatched DNS name": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"badexample.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedWarnings: []string{"namedCertificates[0].names[0]: Invalid value"}, }, "namedCertificates with non-DNS names": { ServingInfo: api.ServingInfo{ BindAddress: "0.0.0.0:1234", BindNetwork: "tcp", ServerCert: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}, NamedCertificates: []api.NamedCertificate{ {Names: []string{"foo bar.com"}, CertInfo: api.CertInfo{CertFile: certFileName, KeyFile: keyFileName}}, }, }, ExpectedErrors: []string{ `namedCertificates[0].names[0]: Invalid value: "foo bar.com": must be a valid DNS name`, }, }, } for k, tc := range testcases { result := ValidateServingInfo(tc.ServingInfo, nil) if len(tc.ExpectedErrors) != len(result.Errors) { t.Errorf("%s: Expected %d errors, got %d", k, len(tc.ExpectedErrors), len(result.Errors)) for _, e := range tc.ExpectedErrors { t.Logf("\tExpected error: %s", e) } for _, r := range result.Errors { t.Logf("\tActual error: %s", r.Error()) } continue } for i, r := range result.Errors { if !strings.Contains(r.Error(), tc.ExpectedErrors[i]) { t.Errorf("%s: Expected error containing %s, got %s", k, tc.ExpectedErrors[i], r.Error()) } } if len(tc.ExpectedWarnings) != len(result.Warnings) { t.Errorf("%s: Expected %d warning, got %d", k, len(tc.ExpectedWarnings), len(result.Warnings)) for _, e := range tc.ExpectedErrors { t.Logf("\tExpected warning: %s", e) } for _, r := range result.Warnings { t.Logf("\tActual warning: %s", r.Error()) } continue } for i, r := range result.Warnings { if !strings.Contains(r.Error(), tc.ExpectedWarnings[i]) { t.Errorf("%s: Expected warning containing %s, got %s", k, tc.ExpectedWarnings[i], r.Error()) } } } } // localhostCert is a PEM-encoded TLS cert with SAN IPs // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end // of ASN.1 time). // generated from src/crypto/tls: // go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h var localhostCert = []byte(`-----BEGIN CERTIFICATE----- MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== -----END CERTIFICATE-----`) // localhostKey is the private key for localhostCert. var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA 1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= -----END RSA PRIVATE KEY-----`)