package managementaccess import ( "bytes" "context" "crypto/tls" "fmt" "io" "net" "net/http" "os" "path/filepath" "testing" "time" "tera-clone/services/tera-api/internal/domain" ) func TestRuntimeAppliesHTTPAndHTTPSListeners(t *testing.T) { httpPort := unusedTCPPort(t) httpsPort := unusedTCPPort(t) tlsRoot := t.TempDir() runtime, err := NewRuntime(RuntimeOptions{ BindHost: "127.0.0.1", Handler: http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { _, _ = io.WriteString(response, "tera-access-ok") }), CertFile: filepath.Join(tlsRoot, "server.crt"), KeyFile: filepath.Join(tlsRoot, "server.key"), TLSHosts: []string{"127.0.0.1"}, }) if err != nil { t.Fatal(err) } defer runtime.Close() settings := domain.ManagementAccessSettings{ HTTPEnabled: true, HTTPPort: httpPort, HTTPSEnabled: true, HTTPSPort: httpsPort, SSHPort: 22, TelnetPort: unusedTCPPort(t), SerialConsoleEnabled: true, IdleTimeoutMinutes: 15, } if err := runtime.Apply(context.Background(), settings); err != nil { t.Fatalf("Apply() error = %v", err) } assertHTTPBody(t, "http://127.0.0.1:"+portString(httpPort), http.DefaultClient) tlsClient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, Timeout: 3 * time.Second} // #nosec G402 -- generated test certificate. assertHTTPBody(t, "https://127.0.0.1:"+portString(httpsPort), tlsClient) } func TestValidateRejectsOutOfRangeLoginProtection(t *testing.T) { base := domain.ManagementAccessSettings{HTTPSEnabled: true, HTTPSPort: 443, HTTPPort: 80, IdleTimeoutMinutes: 15} base.LoginDetectionMinutes = 1441 if err := Validate(base); err == nil { t.Fatal("expected out-of-range login detection time to fail") } base.LoginDetectionMinutes = 0 base.LoginSecurityHitCount = 101 if err := Validate(base); err == nil { t.Fatal("expected out-of-range login security hit count to fail") } } func TestHTTPSListenerReloadsReplacedCertificateForNewConnections(t *testing.T) { httpsPort := unusedTCPPort(t) tlsRoot := t.TempDir() certPath := filepath.Join(tlsRoot, "active.crt") keyPath := filepath.Join(tlsRoot, "active.key") runtime, err := NewRuntime(RuntimeOptions{ BindHost: "127.0.0.1", Handler: http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { response.WriteHeader(http.StatusNoContent) }), CertFile: certPath, KeyFile: keyPath, TLSHosts: []string{"127.0.0.1"}, }) if err != nil { t.Fatal(err) } defer runtime.Close() settings := domain.ManagementAccessSettings{HTTPSEnabled: true, HTTPSPort: httpsPort, HTTPPort: unusedTCPPort(t), IdleTimeoutMinutes: 15} if err := runtime.Apply(context.Background(), settings); err != nil { t.Fatal(err) } first := peerCertificate(t, httpsPort) replacementRoot := t.TempDir() replacementCert := filepath.Join(replacementRoot, "replacement.crt") replacementKey := filepath.Join(replacementRoot, "replacement.key") if _, err := ensureTLSCertificate(replacementCert, replacementKey, []string{"replacement.local"}); err != nil { t.Fatal(err) } certPEM, err := os.ReadFile(replacementCert) if err != nil { t.Fatal(err) } keyPEM, err := os.ReadFile(replacementKey) if err != nil { t.Fatal(err) } if err := os.WriteFile(certPath, certPEM, 0o644); err != nil { t.Fatal(err) } if err := os.WriteFile(keyPath, keyPEM, 0o600); err != nil { t.Fatal(err) } future := time.Now().Add(2 * time.Second) if err := os.Chtimes(certPath, future, future); err != nil { t.Fatal(err) } if err := os.Chtimes(keyPath, future, future); err != nil { t.Fatal(err) } second := peerCertificate(t, httpsPort) if bytes.Equal(first, second) { t.Fatal("new HTTPS connection still received the replaced certificate's predecessor") } } func peerCertificate(t *testing.T, port int) []byte { t.Helper() connection, err := tls.Dial("tcp", "127.0.0.1:"+portString(port), &tls.Config{InsecureSkipVerify: true, MinVersion: tls.VersionTLS12}) // #nosec G402 -- local generated test certificates. if err != nil { t.Fatal(err) } defer connection.Close() certificates := connection.ConnectionState().PeerCertificates if len(certificates) == 0 { t.Fatal("HTTPS peer did not provide a certificate") } return append([]byte(nil), certificates[0].Raw...) } func unusedTCPPort(t *testing.T) int { t.Helper() listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } port := listener.Addr().(*net.TCPAddr).Port _ = listener.Close() return port } func portString(port int) string { return fmt.Sprintf("%d", port) } func assertHTTPBody(t *testing.T, address string, client *http.Client) { t.Helper() response, err := client.Get(address) if err != nil { t.Fatal(err) } defer response.Body.Close() payload, err := io.ReadAll(response.Body) if err != nil { t.Fatal(err) } if string(payload) != "tera-access-ok" { t.Fatalf("body = %q", payload) } }