diff --git a/handlers/middleware/middleware.go b/handlers/middleware/middleware.go index 3b9357f9a..f5a420886 100644 --- a/handlers/middleware/middleware.go +++ b/handlers/middleware/middleware.go @@ -21,11 +21,26 @@ type Emitter interface { func LogWrap(logger, accessLogger lager.Logger, loggableHandlerFunc LoggableHandlerFunc) http.HandlerFunc { lagerDataFromReq := func(r *http.Request) lager.Data { - return lager.Data{ + lagerData := lager.Data{ "method": r.Method, "remote_addr": r.RemoteAddr, "request": r.URL.String(), } + + if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + indexLeafCertConnectionIsVerifiedAgainst := 0 // see also https://github.com/golang/go/blob/e929fb78e47dc191a402d34ca949d2e0c67e31b8/src/crypto/tls/common.go#L281-L282 + cert := r.TLS.PeerCertificates[indexLeafCertConnectionIsVerifiedAgainst] + + lagerData["peer_cert_subject_common_name"] = cert.Subject.CommonName + lagerData["peer_cert_subject_organizational_unit"] = cert.Subject.OrganizationalUnit + lagerData["peer_cert_subject_organization"] = cert.Subject.Organization + + lagerData["peer_cert_issuer_common_name"] = cert.Issuer.CommonName + lagerData["peer_cert_issuer_organizational_unit"] = cert.Issuer.OrganizationalUnit + lagerData["peer_cert_issuer_organization"] = cert.Issuer.Organization + } + + return lagerData } if accessLogger != nil { diff --git a/handlers/middleware/middleware_test.go b/handlers/middleware/middleware_test.go index c877d00ff..cb4534f8b 100644 --- a/handlers/middleware/middleware_test.go +++ b/handlers/middleware/middleware_test.go @@ -2,6 +2,9 @@ package middleware_test import ( "code.cloudfoundry.org/bbs/cmd/bbs/config" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" "net/http" "time" @@ -308,6 +311,44 @@ var _ = Describe("Test Middleware", func() { Expect(accessLogger.Buffer()).To(gbytes.Say("remote_addr\":\"127.0.0.1:8080\"")) Expect(accessLogger.Buffer()).To(gbytes.Say("request\":\"http://example.com\"")) }) + + When("request has TLS peer certificates", func() { + BeforeEach(func() { + accessLogger = lagertest.NewTestLogger("") + accessLogger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.INFO)) // peer cert information should be logged at INFO level + + handler := middleware.LogWrap(logger, accessLogger, loggableHandlerFunc) + req, err := http.NewRequest("", "", nil) + Expect(err).NotTo(HaveOccurred()) + req.TLS = &tls.ConnectionState{ + PeerCertificates: []*x509.Certificate{ + { + Subject: pkix.Name{ + CommonName: "subject-cn", + OrganizationalUnit: []string{"subject-ou"}, + Organization: []string{"subject-o"}, + }, + Issuer: pkix.Name{ + CommonName: "issuer-cn", + OrganizationalUnit: []string{"issuer-ou"}, + Organization: []string{"issuer-o"}, + }, + }, + }, + } + + handler.ServeHTTP(nil, req) + }) + + It("logs peer certificate information", func() { + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_subject_common_name\":\"subject-cn\"")) + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_subject_organization\":\\[\"subject-o\"\\]")) + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_subject_organizational_unit\":\\[\"subject-ou\"\\]")) + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_issuer_common_name\":\"issuer-cn\"")) + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_issuer_organization\":\\[\"issuer-o\"\\]")) + Expect(logger.Buffer()).To(gbytes.Say("peer_cert_issuer_organizational_unit\":\\[\"issuer-ou\"\\]")) + }) + }) }) }) })