Skip to content

Commit

Permalink
Merge branch 'master' into ui/redesign-transit
Browse files Browse the repository at this point in the history
  • Loading branch information
Noelle Daley authored Feb 13, 2020
2 parents 8e6a0bf + f96f4ee commit 594db1d
Show file tree
Hide file tree
Showing 10 changed files with 808 additions and 62 deletions.
10 changes: 5 additions & 5 deletions helper/builtinplugins/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,18 @@ func newRegistry() *registry {
"alicloud": logicalAlicloud.Factory,
"aws": logicalAws.Factory,
"azure": logicalAzure.Factory,
"cassandra": logicalCass.Factory,
"cassandra": logicalCass.Factory, // Deprecated
"consul": logicalConsul.Factory,
"gcp": logicalGcp.Factory,
"gcpkms": logicalGcpKms.Factory,
"kv": logicalKv.Factory,
"mongodb": logicalMongo.Factory,
"mongodb": logicalMongo.Factory, // Deprecated
"mongodbatlas": logicalMongoAtlas.Factory,
"mssql": logicalMssql.Factory,
"mysql": logicalMysql.Factory,
"mssql": logicalMssql.Factory, // Deprecated
"mysql": logicalMysql.Factory, // Deprecated
"nomad": logicalNomad.Factory,
"pki": logicalPki.Factory,
"postgresql": logicalPostgres.Factory,
"postgresql": logicalPostgres.Factory, // Deprecated
"rabbitmq": logicalRabbit.Factory,
"ssh": logicalSsh.Factory,
"totp": logicalTotp.Factory,
Expand Down
6 changes: 3 additions & 3 deletions helper/testhelpers/mongodb/mongodbhelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func PrepareTestContainerWithDatabase(t *testing.T, version, dbName string) (cle
// exponential backoff-retry
if err = pool.Retry(func() error {
var err error
dialInfo, err := parseMongoURL(retURL)
dialInfo, err := ParseMongoURL(retURL)
if err != nil {
return err
}
Expand All @@ -75,8 +75,8 @@ func PrepareTestContainerWithDatabase(t *testing.T, version, dbName string) (cle
return
}

// parseMongoURL will parse a connection string and return a configured dialer
func parseMongoURL(rawURL string) (*mgo.DialInfo, error) {
// ParseMongoURL will parse a connection string and return a configured dialer
func ParseMongoURL(rawURL string) (*mgo.DialInfo, error) {
url, err := url.Parse(rawURL)
if err != nil {
return nil, err
Expand Down
12 changes: 12 additions & 0 deletions plugins/database/mongodb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# MongoDB Tests
The test `TestInit_clientTLS` cannot be run within CircleCI in its current form. This is because [it's not
possible to use volume mounting with the docker executor](https://support.circleci.com/hc/en-us/articles/360007324514-How-can-I-mount-volumes-to-docker-containers-).

Because of this, the test is skipped. Running this locally shouldn't present any issues as long as you have
docker set up to allow volume mounting from this directory:

```sh
go test -v -run Init_clientTLS
```

This may be able to be fixed if we mess with the entrypoint or the command arguments.
242 changes: 242 additions & 0 deletions plugins/database/mongodb/cert_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package mongodb

import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha1"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io/ioutil"
"math/big"
"os"
"strings"
"testing"
"time"
)

type certBuilder struct {
tmpl *x509.Certificate
parentTmpl *x509.Certificate

selfSign bool
parentKey *rsa.PrivateKey

isCA bool
}

type certOpt func(*certBuilder) error

func commonName(cn string) certOpt {
return func(builder *certBuilder) error {
builder.tmpl.Subject.CommonName = cn
return nil
}
}

func parent(parent certificate) certOpt {
return func(builder *certBuilder) error {
builder.parentKey = parent.privKey.privKey
builder.parentTmpl = parent.template
return nil
}
}

func isCA(isCA bool) certOpt {
return func(builder *certBuilder) error {
builder.isCA = isCA
return nil
}
}

func selfSign() certOpt {
return func(builder *certBuilder) error {
builder.selfSign = true
return nil
}
}

func dns(dns ...string) certOpt {
return func(builder *certBuilder) error {
builder.tmpl.DNSNames = dns
return nil
}
}

func newCert(t *testing.T, opts ...certOpt) (cert certificate) {
t.Helper()

builder := certBuilder{
tmpl: &x509.Certificate{
SerialNumber: makeSerial(t),
Subject: pkix.Name{
CommonName: makeCommonName(),
},
NotBefore: time.Now().Add(-1 * time.Hour),
NotAfter: time.Now().Add(1 * time.Hour),
IsCA: false,
KeyUsage: x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment |
x509.KeyUsageKeyAgreement,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
},
}

for _, opt := range opts {
err := opt(&builder)
if err != nil {
t.Fatalf("Failed to set up certificate builder: %s", err)
}
}

key := newPrivateKey(t)

builder.tmpl.SubjectKeyId = getSubjKeyID(t, key.privKey)

tmpl := builder.tmpl
parent := builder.parentTmpl
publicKey := key.privKey.Public()
signingKey := builder.parentKey

if builder.selfSign {
parent = tmpl
signingKey = key.privKey
}

if builder.isCA {
tmpl.IsCA = true
tmpl.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign
tmpl.ExtKeyUsage = nil
} else {
tmpl.KeyUsage = x509.KeyUsageDigitalSignature |
x509.KeyUsageKeyEncipherment |
x509.KeyUsageKeyAgreement
tmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
}

certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, parent, publicKey, signingKey)
if err != nil {
t.Fatalf("Unable to generate certificate: %s", err)
}
certPem := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
})

tlsCert, err := tls.X509KeyPair(certPem, key.pem)
if err != nil {
t.Fatalf("Unable to parse X509 key pair: %s", err)
}

return certificate{
template: tmpl,
privKey: key,
tlsCert: tlsCert,
rawCert: certBytes,
pem: certPem,
isCA: builder.isCA,
}
}

// ////////////////////////////////////////////////////////////////////////////
// Private Key
// ////////////////////////////////////////////////////////////////////////////
type keyWrapper struct {
privKey *rsa.PrivateKey
pem []byte
}

func newPrivateKey(t *testing.T) (key keyWrapper) {
t.Helper()

privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("Unable to generate key for cert: %s", err)
}

privKeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
},
)

key = keyWrapper{
privKey: privKey,
pem: privKeyPem,
}

return key
}

// ////////////////////////////////////////////////////////////////////////////
// Certificate
// ////////////////////////////////////////////////////////////////////////////
type certificate struct {
privKey keyWrapper
template *x509.Certificate
tlsCert tls.Certificate
rawCert []byte
pem []byte
isCA bool
}

func (cert certificate) CombinedPEM() []byte {
if cert.isCA {
return cert.pem
}
return bytes.Join([][]byte{cert.privKey.pem, cert.pem}, []byte{'\n'})
}

// ////////////////////////////////////////////////////////////////////////////
// Writing to file
// ////////////////////////////////////////////////////////////////////////////
func writeFile(t *testing.T, filename string, data []byte, perms os.FileMode) {
t.Helper()

err := ioutil.WriteFile(filename, data, perms)
if err != nil {
t.Fatalf("Unable to write to file [%s]: %s", filename, err)
}
}

// ////////////////////////////////////////////////////////////////////////////
// Helpers
// ////////////////////////////////////////////////////////////////////////////
func makeSerial(t *testing.T) *big.Int {
t.Helper()

v := &big.Int{}
serialNumberLimit := v.Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
t.Fatalf("Unable to generate serial number: %s", err)
}
return serialNumber
}

// Pulled from sdk/helper/certutil & slightly modified for test usage
func getSubjKeyID(t *testing.T, privateKey crypto.Signer) []byte {
t.Helper()

if privateKey == nil {
t.Fatalf("passed-in private key is nil")
}

marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
if err != nil {
t.Fatalf("error marshalling public key: %s", err)
}

subjKeyID := sha1.Sum(marshaledKey)

return subjKeyID[:]
}

func makeCommonName() (cn string) {
return strings.ReplaceAll(time.Now().Format("20060102T150405.000"), ".", "")
}
Loading

0 comments on commit 594db1d

Please sign in to comment.