github.com/Venafi/vcert/v5@v5.10.2/pkg/venafi/tpp/search_test.go (about)

     1  /*
     2   * Copyright 2018 Venafi, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *  http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package tpp
    18  
    19  import (
    20  	"crypto/x509"
    21  	"encoding/pem"
    22  	"fmt"
    23  	"net/url"
    24  	"regexp"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/Venafi/vcert/v5/pkg/certificate"
    30  	"github.com/Venafi/vcert/v5/pkg/endpoint"
    31  	"github.com/Venafi/vcert/v5/test"
    32  )
    33  
    34  func TestParseCertificateSearchResponse(t *testing.T) {
    35  	body := `
    36  		{
    37  		  "Certificates": [
    38  			{
    39  			  "CreatedOn": "2018-06-06T12:49:11.4795797Z",
    40  			  "DN": "\\VED\\Policy\\devops\\vcert\\renx3.venafi.example.com",
    41  			  "Guid": "{f32c5cd0-9b77-47ab-bf27-65a1159ff98e}",
    42  			  "Name": "renx3.venafi.example.com",
    43  			  "ParentDn": "\\VED\\Policy\\devops\\vcert",
    44  			  "SchemaClass": "X509 Server Certificate",
    45  			  "_links": [
    46  				{
    47  				  "Details": "/vedsdk/certificates/%7bf32c5cd0-9b77-47ab-bf27-65a1159ff98e%7d"
    48  				}
    49  			  ]
    50  			}
    51  		  ],
    52  		  "DataRange": "Certificates 1 - 1",
    53  		  "TotalCount": 1
    54  		}`
    55  
    56  	res, err := ParseCertificateSearchResponse(200, []byte(body))
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	if res.Certificates[0].CertificateRequestId != "\\VED\\Policy\\devops\\vcert\\renx3.venafi.example.com" {
    62  		t.Fatal("failed to parse cert DN")
    63  	}
    64  }
    65  
    66  func TestParseCertificateDetailsResponse(t *testing.T) {
    67  	body := `
    68  		{
    69  		  "CertificateAuthorityDN": "\\VED\\Policy\\devops\\msca_template",
    70  		  "CertificateDetails": {
    71  			"AIACAIssuerURL": [
    72  			  "0:http://qavenafica.venqa.venafi.com/CertEnroll/qavenafica.venqa.venafi.com_QA%20Venafi%20CA.crt",
    73  			  "1:ldap:///CN=QA%20Venafi%20CA,CN=AIA,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=venqa,DC=venafi,DC=com?cACertificate?base?objectClass=certificationAuthority"
    74  			],
    75  			"AIAKeyIdentifier": "3CAC9CA60DA130D456A73D78BC231BECB47B4D75",
    76  			"C": "US",
    77  			"CDPURI": "0::False:http://qavenafica.venqa.venafi.com/CertEnroll/QA%20Venafi%20CA.crl",
    78  			"CN": "t1579099443-xiel.venafi.example.com",
    79  			"EnhancedKeyUsage": "Server Authentication(1.3.6.1.5.5.7.3.1)",
    80  			"Issuer": "CN=QA Venafi CA, DC=venqa, DC=venafi, DC=com",
    81  			"KeyAlgorithm": "RSA",
    82  			"KeySize": 8192,
    83  			"KeyUsage": "KeyEncipherment, DigitalSignature",
    84  			"L": "Las Vegas",
    85  			"O": "Venafi, Inc.",
    86  			"OU": [
    87  			  "Automated Tests"
    88  			],
    89  			"PublicKeyHash": "8637C052479F9C4A01CC0CEE600769597DF69DA8",
    90  			"S": "Nevada",
    91  			"SKIKeyIdentifier": "C65C994B38A5B17841C536A8C8189C6613B02C44",
    92  			"Serial": "6D007AAF80B115C1BE51B6F94E0000007AAF80",
    93  			"SignatureAlgorithm": "sha256RSA",
    94  			"SignatureAlgorithmOID": "1.2.840.113549.1.1.11",
    95  			"StoreAdded": "2020-01-15T14:47:02.0862587Z",
    96  			"Subject": "CN=t1579099443-xiel.venafi.example.com, OU=Automated Tests, O=\"Venafi, Inc.\", L=Las Vegas, S=Nevada, C=US",
    97  			"SubjectAltNameDNS": [
    98  			  "t1579099443-xiel.venafi.example.com"
    99  			],
   100  			"SubjectAltNameURI": [
   101  			  "https://example.com/test"
   102  			],
   103  			"TemplateMajorVersion": "100",
   104  			"TemplateMinorVersion": "4",
   105  			"TemplateName": "WebServer-2008(8years)",
   106  			"TemplateOID": "1.3.6.1.4.1.311.21.8.2344178.8460394.1920656.15056892.1115285.96.9686371.12506947",
   107  			"Thumbprint": "D9F8A14D6687824D2F25D1BE1C2A24697B84CF68",
   108  			"ValidFrom": "2020-01-15T14:36:29.0000000Z",
   109  			"ValidTo": "2028-01-13T14:36:29.0000000Z"
   110  		  },
   111  		  "Contact": [
   112  			"local:{f47ab62f-65d4-4a7f-8a8a-cd5440ce2d60}"
   113  		  ],
   114  		  "CreatedBy": [
   115  			"Web SDK"
   116  		  ],
   117  		  "CreatedOn": "2020-01-15T14:46:53.2296661Z",
   118  		  "CustomFields": [
   119  			{
   120  			  "Name": "custom",
   121  			  "Type": "Text",
   122  			  "Value": [
   123  				"2019-10-10"
   124  			  ]
   125  			}
   126  		  ],
   127  		  "DN": "\\VED\\Policy\\devops\\vcert\\t1579099443-xiel.venafi.example.com",
   128  		  "Guid": "{d1542a81-9268-4c62-af7e-8090fac5194d}",
   129  		  "ManagementType": "Enrollment",
   130  		  "Name": "t1579099443-xiel.venafi.example.com",
   131  		  "ParentDn": "\\VED\\Policy\\devops\\vcert",
   132  		  "ProcessingDetails": {},
   133  		  "RenewalDetails": {
   134  			"City": "Las Vegas",
   135  			"Country": "US",
   136  			"KeySize": 8192,
   137  			"Organization": "Venafi, Inc.",
   138  			"OrganizationalUnit": [
   139  			  "Automated Tests"
   140  			],
   141  			"State": "Nevada",
   142  			"Subject": "t1579099443-xiel.venafi.example.com",
   143  			"SubjectAltNameURI": [
   144  			  "https://example.com/test"
   145  			]
   146  		  },
   147  		  "SchemaClass": "X509 Server Certificate",
   148  		  "ValidationDetails": {
   149  			"LastValidationStateUpdate": "0001-01-01T00:00:00.0000000Z"
   150  		  }
   151  		}`
   152  
   153  	res, err := parseCertificateDetailsResponse(200, []byte(body))
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  
   158  	if res.CustomFields[0].Value[0] != "2019-10-10" {
   159  		t.Fatal("invalid custom field value")
   160  	}
   161  }
   162  
   163  func TestRequestAndSearchCertificate(t *testing.T) {
   164  	tpp, err := getTestConnector(ctx.TPPurl, ctx.TPPZone)
   165  	if err != nil {
   166  		t.Fatalf("err is not nil, err: %s url: %s", err, expectedURL)
   167  	}
   168  
   169  	if tpp.apiKey == "" {
   170  		err = tpp.Authenticate(&endpoint.Authentication{AccessToken: ctx.TPPaccessToken})
   171  		if err != nil {
   172  			t.Fatalf("err is not nil, err: %s", err)
   173  		}
   174  	}
   175  
   176  	config, err := tpp.ReadZoneConfiguration()
   177  	if err != nil {
   178  		t.Fatalf("err is not nil, err: %s", err)
   179  	}
   180  
   181  	cn := test.RandCN()
   182  	appInfo := "APP Info " + cn
   183  	workload := fmt.Sprintf("workload-%d", time.Now().Unix())
   184  	instance := "devops-instance"
   185  	cfValue := cn
   186  	req := &certificate.Request{Timeout: time.Second * 30}
   187  	req.Subject.CommonName = cn
   188  	req.Subject.Organization = []string{"Venafi, Inc."}
   189  	req.Subject.OrganizationalUnit = []string{"Automated Tests"}
   190  	req.Subject.Locality = []string{"Las Vegas"}
   191  	req.Subject.Province = []string{"Nevada"}
   192  	req.Subject.Country = []string{"US"}
   193  	u := url.URL{Scheme: "https", Host: "example.com", Path: "/test"}
   194  	req.URIs = []*url.URL{&u}
   195  	req.FriendlyName = cn
   196  	req.CustomFields = []certificate.CustomField{
   197  		{Name: "custom", Value: cfValue},
   198  		{Type: certificate.CustomFieldOrigin, Value: appInfo},
   199  	}
   200  	req.Location = &certificate.Location{
   201  		Instance:   instance,
   202  		Workload:   workload,
   203  		TLSAddress: "wwww.example.com:443",
   204  	}
   205  
   206  	req.KeyLength = 1024
   207  
   208  	err = tpp.GenerateRequest(config, req)
   209  	if err != nil {
   210  		t.Fatalf("err is not nil, err: %s", err)
   211  	}
   212  
   213  	req.PickupID, err = tpp.RequestCertificate(req)
   214  	if err != nil {
   215  		t.Fatalf("err is not nil, err: %s", err)
   216  	}
   217  	certCollections, err := tpp.RetrieveCertificate(req)
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	p, _ := pem.Decode([]byte(certCollections.Certificate))
   222  	cert, err := x509.ParseCertificate(p.Bytes)
   223  	if err != nil {
   224  		t.Fatalf("err is not nil, err: %s", err)
   225  	}
   226  	if cert.Subject.CommonName != cn {
   227  		t.Fatalf("mismatched common names: %v and %v", cn, cert.Subject.CommonName)
   228  	}
   229  	if cert.URIs[0].String() != u.String() {
   230  		t.Fatalf("mismatched URIs: %v and %v", u.String(), cert.URIs[0].String())
   231  	}
   232  
   233  	thumbprint := calcThumbprint(certCollections.Certificate)
   234  	searchResult, err := tpp.searchCertificatesByFingerprint(thumbprint)
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  
   239  	guid := searchResult.Certificates[0].CertificateRequestGuid
   240  	details, err := tpp.searchCertificateDetails(guid)
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	//check custom fields
   246  	if details.CustomFields[0].Value[0] != cfValue {
   247  		t.Fatalf("mismtached custom field valud: want %s but got %s", details.CustomFields[0].Value[0], cfValue)
   248  	}
   249  
   250  	//check installed location device
   251  	if !strings.HasSuffix(details.Consumers[0], instance+"\\"+workload) {
   252  		t.Fatalf("Consumer %s should end on %s", details.Consumers[0], instance+"\\"+workload)
   253  	}
   254  
   255  	configReq := ConfigReadDNRequest{
   256  		ObjectDN:      getCertificateDN(ctx.TPPZone, "", cn),
   257  		AttributeName: "Origin",
   258  	}
   259  
   260  	configResp, err := tpp.configReadDN(configReq)
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	if configResp.Values[0] != appInfo {
   265  		t.Fatalf("Origin attribute value should be %s, but it is %s", appInfo, configResp.Values[0])
   266  	}
   267  
   268  	//add one more device
   269  	req.Location = &certificate.Location{
   270  		Instance:   instance,
   271  		Workload:   workload + "-1",
   272  		TLSAddress: "wwww.example.com:443",
   273  	}
   274  
   275  	err = tpp.GenerateRequest(config, req)
   276  	if err != nil {
   277  		t.Fatalf("err is not nil, err: %s", err)
   278  	}
   279  
   280  	req.PickupID, err = tpp.RequestCertificate(req)
   281  	if err != nil {
   282  		t.Fatalf("err is not nil, err: %s", err)
   283  	}
   284  
   285  	//to wait until cert will be aprooved so we can check list of devices
   286  	_, err = tpp.RetrieveCertificate(req)
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  
   291  	details, err = tpp.searchCertificateDetails(guid)
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  
   296  	if len(details.Consumers) < 1 {
   297  		t.Fatal("There should be at least two devices in consumers")
   298  	}
   299  	//check installed location device
   300  	if !strings.HasSuffix(details.Consumers[1], instance+"\\"+workload+"-1") {
   301  		t.Fatalf("Consumer %s should end on %s", details.Consumers[1], instance+"\\"+workload+"-1")
   302  	}
   303  
   304  	//replace first device, second must be kept
   305  	req.Location = &certificate.Location{
   306  		Instance:   instance,
   307  		Workload:   workload,
   308  		TLSAddress: "wwww.example.com:443",
   309  		Replace:    true,
   310  	}
   311  
   312  	err = tpp.GenerateRequest(config, req)
   313  	if err != nil {
   314  		t.Fatalf("err is not nil, err: %s", err)
   315  	}
   316  
   317  	req.PickupID, err = tpp.RequestCertificate(req)
   318  	if err != nil {
   319  		t.Fatalf("err is not nil, err: %s", err)
   320  	}
   321  
   322  	//to wait until cert will be aprooved so we can check list of devices
   323  	_, err = tpp.RetrieveCertificate(req)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  
   328  	details, err = tpp.searchCertificateDetails(guid)
   329  	if err != nil {
   330  		t.Fatal(err)
   331  	}
   332  
   333  	if len(details.Consumers) < 1 {
   334  		t.Fatal("There should be at least two devices in consumers")
   335  	}
   336  
   337  	//check installed location device
   338  	if !strings.HasSuffix(details.Consumers[0], instance+"\\"+workload+"-1") {
   339  		t.Fatalf("Consumer %s should end on %s", details.Consumers[0], instance+"\\"+workload+"-1")
   340  	}
   341  }
   342  
   343  func TestRequestAndSearchCertificateWithFriendlyName(t *testing.T) {
   344  	tpp, err := getTestConnector(ctx.TPPurl, ctx.TPPZone)
   345  	if err != nil {
   346  		t.Fatalf("err is not nil, err: %s url: %s", err, expectedURL)
   347  	}
   348  
   349  	if tpp.apiKey == "" {
   350  		err = tpp.Authenticate(&endpoint.Authentication{AccessToken: ctx.TPPaccessToken})
   351  		if err != nil {
   352  			t.Fatalf("err is not nil, err: %s", err)
   353  		}
   354  	}
   355  
   356  	config, err := tpp.ReadZoneConfiguration()
   357  	if err != nil {
   358  		t.Fatalf("err is not nil, err: %s", err)
   359  	}
   360  
   361  	cn := test.RandCN()
   362  	appInfo := "APP Info " + cn
   363  	workload := fmt.Sprintf("workload-%d", time.Now().Unix())
   364  	instance := "devops-instance"
   365  	cfValue := cn
   366  	req := &certificate.Request{Timeout: time.Second * 30}
   367  	req.Subject.CommonName = cn
   368  	req.Subject.Organization = []string{"Venafi, Inc."}
   369  	req.Subject.OrganizationalUnit = []string{"Automated Tests"}
   370  	req.Subject.Locality = []string{"Las Vegas"}
   371  	req.Subject.Province = []string{"Nevada"}
   372  	req.Subject.Country = []string{"US"}
   373  	u := url.URL{Scheme: "https", Host: "example.com", Path: "/test"}
   374  	req.URIs = []*url.URL{&u}
   375  	req.FriendlyName = fmt.Sprintf("friendly.%s", cn)
   376  	req.CustomFields = []certificate.CustomField{
   377  		{Name: "custom", Value: cfValue},
   378  		{Type: certificate.CustomFieldOrigin, Value: appInfo},
   379  	}
   380  	req.Location = &certificate.Location{
   381  		Instance:   instance,
   382  		Workload:   workload,
   383  		TLSAddress: "wwww.example.com:443",
   384  	}
   385  
   386  	req.KeyLength = 1024
   387  
   388  	err = tpp.GenerateRequest(config, req)
   389  	if err != nil {
   390  		t.Fatalf("err is not nil, err: %s", err)
   391  	}
   392  
   393  	req.PickupID, err = tpp.RequestCertificate(req)
   394  	if err != nil {
   395  		t.Fatalf("err is not nil, err: %s", err)
   396  	}
   397  	certCollections, err := tpp.RetrieveCertificate(req)
   398  	if err != nil {
   399  		t.Fatal(err)
   400  	}
   401  	p, _ := pem.Decode([]byte(certCollections.Certificate))
   402  	cert, err := x509.ParseCertificate(p.Bytes)
   403  	if err != nil {
   404  		t.Fatalf("err is not nil, err: %s", err)
   405  	}
   406  	if cert.Subject.CommonName != cn {
   407  		t.Fatalf("mismatched common names: %v and %v", cn, cert.Subject.CommonName)
   408  	}
   409  	if cert.URIs[0].String() != u.String() {
   410  		t.Fatalf("mismatched URIs: %v and %v", u.String(), cert.URIs[0].String())
   411  	}
   412  
   413  	thumbprint := calcThumbprint(certCollections.Certificate)
   414  	searchResult, err := tpp.searchCertificatesByFingerprint(thumbprint)
   415  	if err != nil {
   416  		t.Fatal(err)
   417  	}
   418  
   419  	guid := searchResult.Certificates[0].CertificateRequestGuid
   420  	details, err := tpp.searchCertificateDetails(guid)
   421  	if err != nil {
   422  		t.Fatal(err)
   423  	}
   424  
   425  	//check custom fields
   426  	if details.CustomFields[0].Value[0] != cfValue {
   427  		t.Fatalf("mismtached custom field valud: want %s but got %s", details.CustomFields[0].Value[0], cfValue)
   428  	}
   429  
   430  	//check installed location device
   431  	if !strings.HasSuffix(details.Consumers[0], instance+"\\"+workload) {
   432  		t.Fatalf("Consumer %s should end on %s", details.Consumers[0], instance+"\\"+workload)
   433  	}
   434  
   435  	configReq := ConfigReadDNRequest{
   436  		ObjectDN:      getCertificateDN(ctx.TPPZone, req.FriendlyName, cn),
   437  		AttributeName: "Origin",
   438  	}
   439  
   440  	configResp, err := tpp.configReadDN(configReq)
   441  	if err != nil {
   442  		t.Fatal(err)
   443  	}
   444  	if configResp.Values[0] != appInfo {
   445  		t.Fatalf("Origin attribute value should be %s, but it is %s", appInfo, configResp.Values[0])
   446  	}
   447  
   448  	//add one more device
   449  	req.Location = &certificate.Location{
   450  		Instance:   instance,
   451  		Workload:   workload + "-1",
   452  		TLSAddress: "wwww.example.com:443",
   453  	}
   454  
   455  	err = tpp.GenerateRequest(config, req)
   456  	if err != nil {
   457  		t.Fatalf("err is not nil, err: %s", err)
   458  	}
   459  
   460  	req.PickupID, err = tpp.RequestCertificate(req)
   461  	if err != nil {
   462  		t.Fatalf("err is not nil, err: %s", err)
   463  	}
   464  
   465  	//to wait until cert will be aprooved so we can check list of devices
   466  	_, err = tpp.RetrieveCertificate(req)
   467  	if err != nil {
   468  		t.Fatal(err)
   469  	}
   470  
   471  	details, err = tpp.searchCertificateDetails(guid)
   472  	if err != nil {
   473  		t.Fatal(err)
   474  	}
   475  
   476  	if len(details.Consumers) < 1 {
   477  		t.Fatal("There should be at least two devices in consumers")
   478  	}
   479  	//check installed location device
   480  	if !strings.HasSuffix(details.Consumers[1], instance+"\\"+workload+"-1") {
   481  		t.Fatalf("Consumer %s should end on %s", details.Consumers[1], instance+"\\"+workload+"-1")
   482  	}
   483  
   484  	//replace first device, second must be kept
   485  	req.Location = &certificate.Location{
   486  		Instance:   instance,
   487  		Workload:   workload,
   488  		TLSAddress: "wwww.example.com:443",
   489  		Replace:    true,
   490  	}
   491  
   492  	err = tpp.GenerateRequest(config, req)
   493  	if err != nil {
   494  		t.Fatalf("err is not nil, err: %s", err)
   495  	}
   496  
   497  	req.PickupID, err = tpp.RequestCertificate(req)
   498  	if err != nil {
   499  		t.Fatalf("err is not nil, err: %s", err)
   500  	}
   501  
   502  	//to wait until cert will be aprooved so we can check list of devices
   503  	_, err = tpp.RetrieveCertificate(req)
   504  	if err != nil {
   505  		t.Fatal(err)
   506  	}
   507  
   508  	details, err = tpp.searchCertificateDetails(guid)
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  
   513  	if len(details.Consumers) < 1 {
   514  		t.Fatal("There should be at least two devices in consumers")
   515  	}
   516  
   517  	//check installed location device
   518  	if !strings.HasSuffix(details.Consumers[0], instance+"\\"+workload+"-1") {
   519  		t.Fatalf("Consumer %s should end on %s", details.Consumers[0], instance+"\\"+workload+"-1")
   520  	}
   521  }
   522  
   523  func TestSearchDevice(t *testing.T) {
   524  	t.Skip() //we don't use this method now, keep this test for future usage
   525  
   526  	tpp, err := getTestConnector(ctx.TPPurl, ctx.TPPZone)
   527  	if err != nil {
   528  		t.Fatalf("err is not nil, err: %s url: %s", err, expectedURL)
   529  	}
   530  
   531  	authResp, err := tpp.GetRefreshToken(&endpoint.Authentication{
   532  		User: ctx.TPPuser, Password: ctx.TPPPassword,
   533  		Scope: "configuration:read"})
   534  	if err != nil {
   535  		panic(err)
   536  	}
   537  
   538  	err = tpp.Authenticate(&endpoint.Authentication{
   539  		AccessToken: authResp.Access_token,
   540  	})
   541  
   542  	if err != nil {
   543  		t.Fatalf("err is not nil, err: %s", err)
   544  	}
   545  
   546  	req := ConfigReadDNRequest{
   547  		ObjectDN:      "\\VED\\Policy\\devops\\vcert\\kube-worker-1\\nginx_246",
   548  		AttributeName: "Certificate",
   549  	}
   550  
   551  	resp, err := tpp.configReadDN(req)
   552  	if err != nil {
   553  		t.Fatal(err)
   554  	}
   555  	fmt.Println(resp)
   556  }
   557  
   558  type FormatSearchCertificateArgumentsMock struct {
   559  	zone            string
   560  	cn              string
   561  	sans            *certificate.Sans
   562  	certMinTimeLeft time.Duration
   563  }
   564  
   565  // TODO: find a way to test the correct time
   566  func TestFormatSearchCertificateArguments(t *testing.T) {
   567  	timeRegex := "((?:(\\d{4}-\\d{2}-\\d{2})T(\\d{2}%3A\\d{2}%3A\\d{2}(?:\\.\\d+)?))(Z|[\\+-]\\d{2}%3A\\d{2})?)$"
   568  	testCases := []struct {
   569  		name     string
   570  		input    FormatSearchCertificateArgumentsMock
   571  		expected string
   572  	}{
   573  		{
   574  			// test empty arguments, should return just the ValidToGreater
   575  			// argument
   576  			name:     "Empty",
   577  			input:    FormatSearchCertificateArgumentsMock{},
   578  			expected: "^ValidToGreater=" + timeRegex,
   579  		},
   580  		{
   581  			// test with just CN, should return Common Name and ValidToGreater
   582  			// arguments
   583  			name: "CN",
   584  			input: FormatSearchCertificateArgumentsMock{
   585  				cn: "test.example.com",
   586  			},
   587  			expected: "^CN=test\\.example\\.com&ValidToGreater=" + timeRegex,
   588  		},
   589  		{
   590  			// test with just 1 DNS, should return SAN-DNS and ValidToGreater
   591  			// arguments
   592  			name: "SANS_1",
   593  			input: FormatSearchCertificateArgumentsMock{
   594  				sans: &certificate.Sans{DNS: []string{"one.example.com"}},
   595  			},
   596  			expected: "^SAN-DNS=one\\.example\\.com&ValidToGreater=" + timeRegex,
   597  		},
   598  		{
   599  			// test with 2 DNS, should return both SAN-DNS and ValidToGreater
   600  			// arguments
   601  			name: "SANS_2",
   602  			input: FormatSearchCertificateArgumentsMock{
   603  				sans: &certificate.Sans{DNS: []string{"one.example.com", "two.example.com"}},
   604  			},
   605  			expected: "^SAN-DNS=one\\.example\\.com,two\\.example\\.com&ValidToGreater=" + timeRegex,
   606  		},
   607  		{
   608  			// test with CN and 1 DNS, should return the Common Name, DNS and
   609  			// ValidToGreater arguments
   610  			name: "CN SANS_1",
   611  			input: FormatSearchCertificateArgumentsMock{
   612  				cn:   "test.example.com",
   613  				sans: &certificate.Sans{DNS: []string{"one.example.com"}},
   614  			},
   615  			expected: "^CN=test\\.example\\.com&SAN-DNS=one\\.example\\.com&ValidToGreater=" + timeRegex,
   616  		},
   617  		{
   618  			// test with CN and 2 DNS, should return the Common Name, 2 DNS and
   619  			// ValidToGreater arguments
   620  			name: "CN SANS_2",
   621  			input: FormatSearchCertificateArgumentsMock{
   622  				cn:   "test.example.com",
   623  				sans: &certificate.Sans{DNS: []string{"one.example.com", "two.example.com"}},
   624  			},
   625  			expected: "^CN=test\\.example\\.com&SAN-DNS=one\\.example\\.com,two\\.example\\.com&ValidToGreater=" + timeRegex,
   626  		},
   627  	}
   628  
   629  	for _, testCase := range testCases {
   630  		t.Run(testCase.name, func(t *testing.T) {
   631  			req := formatSearchCertificateArguments(testCase.input.cn, testCase.input.sans, testCase.input.certMinTimeLeft)
   632  			matches, err := regexp.MatchString(testCase.expected, req)
   633  			if err != nil {
   634  				t.Fatal(err)
   635  			}
   636  			if !matches {
   637  				// might want to send a better error message in case of failure
   638  				t.Errorf("unmatched regexp\nExpected:\n%v\nGot:\n%v", testCase.expected, req)
   639  			}
   640  		})
   641  	}
   642  }