// Copyright 2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package testlib import ( "net" "net/url" "testing" "time" "github.com/stretchr/testify/require" "go.pinniped.dev/internal/certauthority" ) type SupervisorIssuer struct { issuerURL *url.URL ip net.IP alternativeNames []string } func NewSupervisorIssuer(t *testing.T, issuer string) *SupervisorIssuer { t.Helper() t.Logf("NewSupervisorIssuer: %s", issuer) issuerURL, err := url.Parse(issuer) require.NoError(t, err) require.NotEmpty(t, issuerURL.Hostname(), "hostname cannot be empty, usually this happens when the scheme is empty. issuer=%q", issuer) ip := net.ParseIP(issuerURL.Hostname()) return &SupervisorIssuer{ issuerURL: issuerURL, ip: ip, } } func (s *SupervisorIssuer) AddPathSuffix(path string) { s.issuerURL.Path += path } // AddAlternativeName adds a SAN for the cert. It is not intended to take an IP address as its argument. func (s *SupervisorIssuer) AddAlternativeName(san string) { s.alternativeNames = append(s.alternativeNames, san) } func (s *SupervisorIssuer) Issuer() string { return s.issuerURL.String() } func (s *SupervisorIssuer) Address() string { return s.issuerURL.Host } func (s *SupervisorIssuer) Hostname() string { return s.issuerURL.Hostname() } func (s *SupervisorIssuer) Port(defaultPort string) string { port := s.issuerURL.Port() if port == "" { return defaultPort } return s.issuerURL.Port() } func (s *SupervisorIssuer) hostnamesForCert() []string { var hostnames []string if !s.IsIPAddress() { hostnames = append(hostnames, s.issuerURL.Hostname()) } if s.alternativeNames != nil { hostnames = append(hostnames, s.alternativeNames...) } return hostnames } func (s *SupervisorIssuer) ipsForCert() []net.IP { if !s.IsIPAddress() { return nil } return []net.IP{s.ip} } func (s *SupervisorIssuer) IssuerServerCert( t *testing.T, ca *certauthority.CA, ) ([]byte, []byte) { t.Helper() cert, err := ca.IssueServerCert(s.hostnamesForCert(), s.ipsForCert(), 24*time.Hour) require.NoError(t, err) certPEM, keyPEM, err := certauthority.ToPEM(cert) require.NoError(t, err) t.Logf("issued server cert for Supervisor: hostname=%+v, ips=%+v\n%s", s.hostnamesForCert(), s.ipsForCert(), certPEM) return certPEM, keyPEM } func (s *SupervisorIssuer) IsIPAddress() bool { return s.ip != nil }