github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/api/certpool_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api_test 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/juju/loggo" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/api" 17 "github.com/juju/juju/pki" 18 "github.com/juju/juju/testing" 19 ) 20 21 type certPoolSuite struct { 22 testing.BaseSuite 23 logs *certLogs 24 } 25 26 var _ = gc.Suite(&certPoolSuite{}) 27 28 func (s *certPoolSuite) SetUpTest(c *gc.C) { 29 s.BaseSuite.SetUpTest(c) 30 s.logs = &certLogs{} 31 loggo.GetLogger("juju.api").SetLogLevel(loggo.TRACE) 32 loggo.RegisterWriter("api-certs", s.logs) 33 } 34 35 func (*certPoolSuite) TestCreateCertPoolNoCert(c *gc.C) { 36 pool, err := api.CreateCertPool("") 37 c.Assert(err, jc.ErrorIsNil) 38 c.Assert(pool.Subjects(), gc.HasLen, 0) 39 } 40 41 func (*certPoolSuite) TestCreateCertPoolTestCert(c *gc.C) { 42 pool, err := api.CreateCertPool(testing.CACert) 43 c.Assert(err, jc.ErrorIsNil) 44 c.Assert(pool.Subjects(), gc.HasLen, 1) 45 } 46 47 func (s *certPoolSuite) TestCreateCertPoolNoDir(c *gc.C) { 48 certDir := filepath.Join(c.MkDir(), "missing") 49 s.PatchValue(api.CertDir, certDir) 50 51 pool, err := api.CreateCertPool("") 52 c.Assert(err, jc.ErrorIsNil) 53 c.Assert(pool.Subjects(), gc.HasLen, 0) 54 55 c.Assert(s.logs.messages, gc.HasLen, 1) 56 // The directory not existing is likely to happen a lot, so it is only 57 // logged out at trace to help be explicit in the case where detailed 58 // debugging is needed. 59 c.Assert(s.logs.messages[0], gc.Matches, `TRACE cert dir ".*" does not exist`) 60 } 61 62 func (s *certPoolSuite) TestCreateCertPoolNotADir(c *gc.C) { 63 certDir := filepath.Join(c.MkDir(), "missing") 64 s.PatchValue(api.CertDir, certDir) 65 // Make the certDir a file instead... 66 c.Assert(os.WriteFile(certDir, []byte("blah"), 0644), jc.ErrorIsNil) 67 68 pool, err := api.CreateCertPool("") 69 c.Assert(err, jc.ErrorIsNil) 70 c.Assert(pool.Subjects(), gc.HasLen, 0) 71 72 c.Assert(s.logs.messages, gc.HasLen, 1) 73 c.Assert(s.logs.messages[0], gc.Matches, `INFO cert dir ".*" is not a directory`) 74 } 75 76 func (s *certPoolSuite) TestCreateCertPoolEmptyDir(c *gc.C) { 77 certDir := c.MkDir() 78 s.PatchValue(api.CertDir, certDir) 79 80 pool, err := api.CreateCertPool("") 81 c.Assert(err, jc.ErrorIsNil) 82 c.Assert(pool.Subjects(), gc.HasLen, 0) 83 c.Assert(s.logs.messages, gc.HasLen, 1) 84 c.Assert(s.logs.messages[0], gc.Matches, `DEBUG added 0 certs to the pool from .*`) 85 } 86 87 func (s *certPoolSuite) TestCreateCertPoolLoadsPEMFiles(c *gc.C) { 88 certDir := c.MkDir() 89 s.PatchValue(api.CertDir, certDir) 90 s.addCert(c, filepath.Join(certDir, "first.pem")) 91 s.addCert(c, filepath.Join(certDir, "second.pem")) 92 s.addCert(c, filepath.Join(certDir, "third.pem")) 93 94 pool, err := api.CreateCertPool("") 95 c.Assert(err, jc.ErrorIsNil) 96 c.Assert(pool.Subjects(), gc.HasLen, 3) 97 c.Assert(s.logs.messages, gc.HasLen, 1) 98 c.Assert(s.logs.messages[0], gc.Matches, `DEBUG added 3 certs to the pool from .*`) 99 } 100 101 func (s *certPoolSuite) TestCreateCertPoolLoadsOnlyPEMFiles(c *gc.C) { 102 certDir := c.MkDir() 103 s.PatchValue(api.CertDir, certDir) 104 s.addCert(c, filepath.Join(certDir, "first.pem")) 105 c.Assert(os.WriteFile(filepath.Join(certDir, "second.cert"), []byte("blah"), 0644), jc.ErrorIsNil) 106 107 pool, err := api.CreateCertPool("") 108 c.Assert(err, jc.ErrorIsNil) 109 c.Assert(pool.Subjects(), gc.HasLen, 1) 110 c.Assert(s.logs.messages, gc.HasLen, 1) 111 c.Assert(s.logs.messages[0], gc.Matches, `DEBUG added 1 certs to the pool from .*`) 112 } 113 114 func (s *certPoolSuite) TestCreateCertPoolLogsBadCerts(c *gc.C) { 115 certDir := c.MkDir() 116 s.PatchValue(api.CertDir, certDir) 117 c.Assert(os.WriteFile(filepath.Join(certDir, "broken.pem"), []byte("blah"), 0644), jc.ErrorIsNil) 118 119 pool, err := api.CreateCertPool("") 120 c.Assert(err, jc.ErrorIsNil) 121 c.Assert(pool.Subjects(), gc.HasLen, 0) 122 c.Assert(s.logs.messages, gc.HasLen, 2) 123 c.Assert(s.logs.messages[0], gc.Matches, `INFO error parsing cert ".*broken.pem": .*`) 124 c.Assert(s.logs.messages[1], gc.Matches, `DEBUG added 0 certs to the pool from .*`) 125 } 126 127 func (s *certPoolSuite) addCert(c *gc.C, filename string) { 128 signer, err := pki.DefaultKeyProfile() 129 c.Assert(err, jc.ErrorIsNil) 130 131 caCert, err := pki.NewCA("random model name", signer) 132 c.Assert(err, jc.ErrorIsNil) 133 134 caCertPem, err := pki.CertificateToPemString(pki.DefaultPemHeaders, caCert) 135 c.Assert(err, jc.ErrorIsNil) 136 137 c.Assert(err, jc.ErrorIsNil) 138 err = os.WriteFile(filename, []byte(caCertPem), 0644) 139 c.Assert(err, jc.ErrorIsNil) 140 } 141 142 type certLogs struct { 143 messages []string 144 } 145 146 func (c *certLogs) Write(entry loggo.Entry) { 147 if strings.HasSuffix(entry.Filename, "certpool.go") { 148 c.messages = append(c.messages, fmt.Sprintf("%s %s", entry.Level, entry.Message)) 149 } 150 }