github.com/Venafi/vcert/v5@v5.10.2/pkg/venafi/cloud/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 cloud 18 19 import ( 20 "encoding/json" 21 "testing" 22 "time" 23 24 "github.com/Venafi/vcert/v5/pkg/certificate" 25 "github.com/Venafi/vcert/v5/pkg/util" 26 ) 27 28 func TestSearchRequest(t *testing.T) { 29 30 // encoding to JSON 31 req := &SearchRequest{ 32 Expression: &Expression{ 33 Operands: []Operand{ 34 { 35 Field: "fingerprint", 36 Operator: MATCH, 37 Value: "A7BDECDA0B67D5CEF28D6C8C7D7CFA882E3DC9D6", 38 }, 39 }, 40 }, 41 Paging: &Paging{10, 10}, 42 } 43 var expectedJson = `{"expression":{"operands":[{"field":"fingerprint","operator":"MATCH","value":"A7BDECDA0B67D5CEF28D6C8C7D7CFA882E3DC9D6"}]},"paging":{"pageNumber":10,"pageSize":10}}` 44 45 data, err := json.Marshal(req) 46 if err != nil { 47 t.Fatal(err) 48 } 49 if string(data) != expectedJson { 50 t.Fatalf("expected different JSON:\nhave: %s\nexpected: %s", data, expectedJson) 51 } 52 t.Logf("%s\n", data) 53 54 // decoding from JSON 55 var req2 = &SearchRequest{} 56 err = json.Unmarshal(data, req2) 57 if err != nil { 58 t.Fatal(err) 59 } 60 t.Logf("%+v\n", req2) 61 data2, err := json.Marshal(req2) 62 if err != nil { 63 t.Fatal(err) 64 } 65 if string(data) != string(data2) { 66 t.Fatalf("one expected to be the same as another:\none: %s\nother: %s", data, data2) 67 } 68 69 // if Paging is not specified, it should not be included to JSON 70 req = &SearchRequest{ 71 Expression: &Expression{ 72 Operands: []Operand{ 73 { 74 Field: "fingerprint", 75 Operator: MATCH, 76 Value: "A7BDECDA0B67D5CEF28D6C8C7D7CFA882E3DC9D6", 77 }, 78 }, 79 }, 80 } 81 expectedJson = `{"expression":{"operands":[{"field":"fingerprint","operator":"MATCH","value":"A7BDECDA0B67D5CEF28D6C8C7D7CFA882E3DC9D6"}]}}` 82 83 data, err = json.Marshal(req) 84 if err != nil { 85 t.Fatal(err) 86 } 87 if string(data) != expectedJson { 88 t.Fatalf("expected different JSON:\nhave: %s\nexpected: %s", data, expectedJson) 89 } 90 } 91 92 func TestParseCertificateSearchResponse(t *testing.T) { 93 var code int 94 var body []byte 95 var searchResult *CertificateSearchResponse 96 var err error 97 98 code = 200 99 body = []byte(` 100 { 101 "count": 1, 102 "certificates": [ 103 { 104 "id": "ab239880-5de9-11e8-bb9b-8d6e819a14f1", 105 "companyId": "b5ed6d60-22c4-11e7-ac27-035f0608fd2c", 106 "managedCertificateId": "ab239881-5de9-11e8-bb9b-8d6e819a14f1", 107 "fingerprint": "73CF2CC98C7DEC4045EDB93151750F5B9609FF44", 108 "issuerCertificateIds": [ 109 "828a2b70-22ce-11e7-ba19-0da4a5ff6335", 110 "82734810-22ce-11e7-ba19-0da4a5ff6335" 111 ], 112 "certificateRequestId": "8ceb8ad0-5de9-11e8-9c7a-e596bbf80f56", 113 "certificateSource": "USER_PROVIDED", 114 "certificateStatuses": [ 115 "NONE" 116 ], 117 "certificateType": "END_ENTITY", 118 "ownerUsername": "alexander.tarasenko@venafi.com", 119 "creationDate": "2018-05-22T17:58:01.480+00:00", 120 "modificationDate": "2018-05-22T17:58:01.480+00:00", 121 "totalInstanceCount": 0, 122 "validityStart": "2018-05-22T00:00:00.000+00:00", 123 "validityEnd": "2018-08-20T12:00:00.000+00:00", 124 "validityPeriodDays": 90, 125 "validityPeriodRange": "GT_30_DAYS_LTE_2_YEARS", 126 "selfSigned": false, 127 "signatureAlgorithm": "SHA256_WITH_RSA_ENCRYPTION", 128 "signatureHashAlgorithm": "SHA256", 129 "encryptionType": "RSA", 130 "keyStrength": 2048, 131 "publicKeyHash": "0048AA1D7E2F0017F9CA2E687D8776A1A340553D", 132 "subjectKeyIdentifierHash": "C6E7C18CADE684CB420CA4764A6469086536D08E", 133 "authorityKeyIdentifierHash": "AC90A22B9320CE93369173BC3074121005D7F909", 134 "serialNumber": "07F3FE39F4E1A4B6075633ECFB748D84", 135 "subjectCN": [ 136 "renew-test.venafi.example.com" 137 ], 138 "subjectOU": [ 139 "SerialNumber" 140 ], 141 "subjectST": "California", 142 "subjectL": "Palo Alto", 143 "subjectC": "US", 144 "subjectAlternativeNamesByType": { 145 "otherName": [], 146 "rfc822Name": [], 147 "dNSName": [ 148 "renew-test.venafi.example.com" 149 ], 150 "x400Address": [], 151 "directoryName": [], 152 "ediPartyName": [], 153 "uniformResourceIdentifier": [], 154 "iPAddress": [], 155 "registeredID": [] 156 }, 157 "subjectAlternativeNameDns": [ 158 "renew-test.venafi.example.com" 159 ], 160 "issuerCN": [ 161 "DigiCert Test SHA2 Intermediate CA-1" 162 ], 163 "issuerC": "US", 164 "keyUsage": [ 165 "digitalSignature", 166 "keyEncipherment" 167 ], 168 "ocspNoCheck": false, 169 "compliance": { 170 "score": 0.8728395061728398 171 }, 172 "instances": [ 173 { 174 "id": "ab28c8a0-5de9-11e8-bb9b-8d6e819a14f1", 175 "certificateId": "ab239880-5de9-11e8-bb9b-8d6e819a14f1", 176 "managedCertificateId": "ab239881-5de9-11e8-bb9b-8d6e819a14f1", 177 "companyId": "b5ed6d60-22c4-11e7-ac27-035f0608fd2c", 178 "zoneId": "b5f69520-22c4-11e7-ac27-035f0608fd2c", 179 "fingerprint": "73CF2CC98C7DEC4045EDB93151750F5B9609FF44", 180 "certificateSource": "USER_PROVIDED", 181 "certificateStatuses": [ 182 "NONE" 183 ], 184 "ownerUsername": "alexander.tarasenko@venafi.com", 185 "creationDate": "2018-05-22T17:58:01.514+00:00", 186 "modificationDate": "2018-05-22T17:58:01.514+00:00", 187 "ipAddress": "254.254.254.254", 188 "ipAddressAsLong": 4278124286, 189 "hostname": " ", 190 "port": -1, 191 "sslProtocolsSecurityStatus": "UNKNOWN", 192 "cipherSuitesSecurityStatus": "UNKNOWN", 193 "compliance": { 194 "score": 0.0 195 } 196 } 197 ], 198 "applicationIds": [] 199 } 200 ] 201 } 202 `) 203 204 searchResult, err = ParseCertificateSearchResponse(code, body) 205 if err != nil { 206 t.Fatal(err) 207 } 208 if searchResult.Count != 1 { 209 t.Fatal("wrong count field") 210 } 211 if len(searchResult.Certificates) != 1 { 212 t.Fatal("wrong count") 213 } 214 if searchResult.Certificates[0].ManagedCertificateId != "ab239881-5de9-11e8-bb9b-8d6e819a14f1" { 215 t.Fatal("wrong ManagedCertificateId value") 216 } 217 218 code = 400 219 body = []byte("") 220 searchResult, err = ParseCertificateSearchResponse(code, body) 221 if err == nil { 222 t.Fatal("should trigger error") 223 } 224 225 code = 400 226 body = []byte(` 227 { 228 "errors": [ 229 { 230 "code": 1004, 231 "message": "Invalid or missing request header [SESSION, tppl-api-key]", 232 "args": [ 233 [ 234 "SESSION", 235 "tppl-api-key" 236 ] 237 ] 238 }, 239 { 240 "code": 1005, 241 "message": "Something else was wrong" 242 } 243 ] 244 } 245 `) 246 searchResult, err = ParseCertificateSearchResponse(code, body) 247 if err == nil { 248 t.Fatal("JSON body should trigger error") 249 } 250 } 251 252 func TestGetAppNameFromZone(t *testing.T) { 253 testCases := []struct { 254 name string 255 input string 256 expected string 257 }{ 258 { 259 name: "Empty", 260 input: "", 261 expected: "", 262 }, 263 { 264 name: "App", 265 input: "Just The App Name", 266 expected: "Just The App Name", 267 }, 268 { 269 name: "App+Cit", 270 input: "The application\\With Cit", 271 expected: "The application", 272 }, 273 { 274 name: "App+Cit Complex", 275 input: "The complex application\\name\\and the cit", 276 expected: "The complex application\\name", 277 }, 278 } 279 280 for _, testCase := range testCases { 281 t.Run(testCase.name, func(t *testing.T) { 282 appName := getAppNameFromZone(testCase.input) 283 if testCase.expected != appName { 284 t.Errorf("unmatched application name\nExpected:\n%v\nGot:\n%v", testCase.expected, appName) 285 } 286 }) 287 } 288 } 289 290 type FormatSearchCertificateArgumentsMock struct { 291 cn string 292 sans *certificate.Sans 293 certMinTimeLeft time.Duration 294 } 295 296 func TestFormatSearchCertificateArguments(t *testing.T) { 297 testCases := []struct { 298 name string 299 input FormatSearchCertificateArgumentsMock 300 expected *SearchRequest 301 }{ 302 { 303 // test empty arguments, should return just the validityPeriodDays 304 // argument 305 name: "Empty", 306 input: FormatSearchCertificateArgumentsMock{}, 307 expected: &SearchRequest{ 308 Expression: &Expression{ 309 Operator: AND, 310 Operands: []Operand{ 311 { 312 Field: "validityPeriodDays", 313 Operator: GTE, 314 Value: 0, 315 }, 316 }, 317 }, 318 }, 319 }, 320 { 321 // test with just CN, should return subjectCN and validityPeriodDays 322 // arguments 323 name: "CN", 324 input: FormatSearchCertificateArgumentsMock{ 325 cn: "test.example.com", 326 }, 327 expected: &SearchRequest{ 328 Expression: &Expression{ 329 Operator: AND, 330 Operands: []Operand{ 331 { 332 Field: "validityPeriodDays", 333 Operator: GTE, 334 Value: 0, 335 }, 336 { 337 Field: "subjectCN", 338 Operator: EQ, 339 Value: "test.example.com", 340 }, 341 }, 342 }, 343 }, 344 }, 345 { 346 // test with just 1 DNS, should return subjectAlternativeNameDns and 347 // validityPeriodDays arguments 348 name: "SANS_1", 349 input: FormatSearchCertificateArgumentsMock{ 350 sans: &certificate.Sans{DNS: []string{"one.example.com"}}, 351 }, 352 expected: &SearchRequest{ 353 Expression: &Expression{ 354 Operator: AND, 355 Operands: []Operand{ 356 { 357 Field: "validityPeriodDays", 358 Operator: GTE, 359 Value: 0, 360 }, 361 { 362 Field: "subjectAlternativeNameDns", 363 Operator: IN, 364 Values: []string{"one.example.com"}, 365 }, 366 }, 367 }, 368 }, 369 }, 370 { 371 // test with just 2 DNS, should return both subjectAlternativeNameDns and 372 // validityPeriodDays arguments 373 name: "SANS_2", 374 input: FormatSearchCertificateArgumentsMock{ 375 sans: &certificate.Sans{DNS: []string{"one.example.com", "two.example.com"}}, 376 }, 377 expected: &SearchRequest{ 378 Expression: &Expression{ 379 Operator: AND, 380 Operands: []Operand{ 381 { 382 Field: "validityPeriodDays", 383 Operator: GTE, 384 Value: 0, 385 }, 386 { 387 Field: "subjectAlternativeNameDns", 388 Operator: IN, 389 Values: []string{"one.example.com", "two.example.com"}, 390 }, 391 }, 392 }, 393 }, 394 }, 395 { 396 // test with CN and 1 DNS, should return the subjectCN, 1 397 // subjectAlternativeNameDns and validityPeriodDays arguments 398 name: "CN SANS_1", 399 input: FormatSearchCertificateArgumentsMock{ 400 cn: "one.example.com", 401 sans: &certificate.Sans{DNS: []string{"one.example.com"}}, 402 }, 403 expected: &SearchRequest{ 404 Expression: &Expression{ 405 Operator: AND, 406 Operands: []Operand{ 407 { 408 Field: "validityPeriodDays", 409 Operator: GTE, 410 Value: 0, 411 }, 412 { 413 Field: "subjectAlternativeNameDns", 414 Operator: IN, 415 Values: []string{"one.example.com"}, 416 }, 417 { 418 Field: "subjectCN", 419 Operator: EQ, 420 Value: "one.example.com", 421 }, 422 }, 423 }, 424 }, 425 }, 426 { 427 // test with CN and 2 DNS, should return the subjectCN, 2 428 // subjectAlternativeNameDns and validityPeriodDays arguments 429 name: "CN SANS_2", 430 input: FormatSearchCertificateArgumentsMock{ 431 cn: "one.example.com", 432 sans: &certificate.Sans{DNS: []string{"one.example.com", "two.example.com"}}, 433 }, 434 expected: &SearchRequest{ 435 Expression: &Expression{ 436 Operator: AND, 437 Operands: []Operand{ 438 { 439 Field: "validityPeriodDays", 440 Operator: GTE, 441 Value: 0, 442 }, 443 { 444 Field: "subjectAlternativeNameDns", 445 Operator: IN, 446 Values: []string{"one.example.com", "two.example.com"}, 447 }, 448 { 449 Field: "subjectCN", 450 Operator: EQ, 451 Value: "one.example.com", 452 }, 453 }, 454 }, 455 }, 456 }, 457 } 458 459 for _, testCase := range testCases { 460 t.Run(testCase.name, func(t *testing.T) { 461 req := formatSearchCertificateArguments(testCase.input.cn, testCase.input.sans, testCase.input.certMinTimeLeft) 462 // stringify the instances 463 expected := util.GetJsonAsString(testCase.expected) 464 request := util.GetJsonAsString(req) 465 // compare as string 466 matches := expected == request 467 if !matches { 468 t.Errorf("unmatched regexp\nExpected:\n%v\nGot:\n%v", expected, request) 469 } 470 }) 471 } 472 }