Skip to content

Commit

Permalink
GODRIVER-1461 Skip mongocryptd spawning if bypassAutoEncryption is tr…
Browse files Browse the repository at this point in the history
…ue (#280)
  • Loading branch information
Divjot Arora authored Jan 22, 2020
1 parent c898612 commit 7a2d1a7
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 7 deletions.
2 changes: 1 addition & 1 deletion mongo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ func (c *Client) configureKeyVault(opts *options.AutoEncryptionOptions) error {

func (c *Client) configureMongocryptd(opts *options.AutoEncryptionOptions) error {
var err error
c.mongocryptd, err = newMcryptClient(opts.ExtraOptions)
c.mongocryptd, err = newMcryptClient(opts)
return err
}

Expand Down
78 changes: 78 additions & 0 deletions mongo/integration/client_side_encryption_prose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"runtime"
"strings"
"testing"
"time"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
Expand Down Expand Up @@ -630,6 +631,83 @@ func TestClientSideEncryptionProse(t *testing.T) {
})
}
})
mt.RunOpts("bypass mongocryptd spawning", noClientOpts, func(mt *mtest.T) {
kmsProviders := map[string]map[string]interface{}{
"local": {
"key": localMasterKey,
},
}
schemaMap := map[string]interface{}{
"db.coll": readJSONFile(mt, "external-schema.json"),
}

// All mongocryptd options use port 27021 instead of the default 27020 to avoid interference with mongocryptd
// instances spawned by previous tests.
mongocryptdBypassSpawnTrue := map[string]interface{}{
"mongocryptdBypassSpawn": true,
"mongocryptdURI": "mongodb://localhost:27021/db?serverSelectionTimeoutMS=1000",
"mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
}
mongocryptdBypassSpawnFalse := map[string]interface{}{
"mongocryptdBypassSpawn": false,
"mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
}
mongocryptdBypassSpawnNotSet := map[string]interface{}{
"mongocryptdSpawnArgs": []string{"--pidfilepath=bypass-spawning-mongocryptd.pid", "--port=27021"},
}

testCases := []struct {
name string
mongocryptdOpts map[string]interface{}
setBypassAutoEncryption bool
bypassAutoEncryption bool
}{
{"mongocryptdBypassSpawn only", mongocryptdBypassSpawnTrue, false, false},
{"bypassAutoEncryption only", mongocryptdBypassSpawnNotSet, true, true},
{"mongocryptdBypassSpawn false, bypassAutoEncryption true", mongocryptdBypassSpawnFalse, true, true},
{"mongocryptdBypassSpawn true, bypassAutoEncryption false", mongocryptdBypassSpawnTrue, true, false},
}
for _, tc := range testCases {
mt.Run(tc.name, func(mt *mtest.T) {
aeo := options.AutoEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(kvNamespace).
SetSchemaMap(schemaMap).
SetExtraOptions(tc.mongocryptdOpts)
if tc.setBypassAutoEncryption {
aeo.SetBypassAutoEncryption(tc.bypassAutoEncryption)
}
cpt := setup(mt, aeo, nil, nil)
defer cpt.teardown(mt)

_, err := cpt.cseColl.InsertOne(mtest.Background, bson.D{{"unencrypted", "test"}})

// Check for mongocryptd server selection error if auto encryption was not bypassed.
if !(tc.setBypassAutoEncryption && tc.bypassAutoEncryption) {
assert.NotNil(mt, err, "expected InsertOne error, got nil")
mcryptErr, ok := err.(mongo.MongocryptdError)
assert.True(mt, ok, "expected error type %T, got %v of type %T", mongo.MongocryptdError{}, err, err)
assert.True(mt, strings.Contains(mcryptErr.Error(), "server selection error"),
"expected mongocryptd server selection error, got %v", err)
return
}

// If auto encryption is bypassed, the command should succeed. Create a new client to connect to
// mongocryptd and verify it is not running.
assert.Nil(mt, err, "InsertOne error: %v", err)

mcryptOpts := options.Client().ApplyURI("mongodb://localhost:27021").
SetServerSelectionTimeout(1 * time.Second)
mcryptClient, err := mongo.Connect(mtest.Background, mcryptOpts)
assert.Nil(mt, err, "mongocryptd Connect error: %v", err)

err = mcryptClient.Database("admin").RunCommand(mtest.Background, bson.D{{"ismaster", 1}}).Err()
assert.NotNil(mt, err, "expected mongocryptd ismaster error, got nil")
assert.True(mt, strings.Contains(err.Error(), "server selection error"),
"expected mongocryptd server selection error, got %v", err)
})
}
})
}

type cseProseTest struct {
Expand Down
22 changes: 16 additions & 6 deletions mongo/mongocryptd.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,33 @@ type mcryptClient struct {
spawnArgs []string
}

func newMcryptClient(opts map[string]interface{}) (*mcryptClient, error) {
func newMcryptClient(opts *options.AutoEncryptionOptions) (*mcryptClient, error) {
// create mcryptClient instance and spawn process if necessary
mc := &mcryptClient{}
if bypass, ok := opts["mongocryptdBypassSpawn"]; ok {
mc.bypassSpawn = bypass.(bool)
var bypassSpawn bool
var bypassAutoEncryption bool
if bypass, ok := opts.ExtraOptions["mongocryptdBypassSpawn"]; ok {
bypassSpawn = bypass.(bool)
}
if opts.BypassAutoEncryption != nil {
bypassAutoEncryption = *opts.BypassAutoEncryption
}

mc := &mcryptClient{
// mongocryptd should not be spawned if mongocryptdBypassSpawn is passed or if bypassAutoEncryption is
// specified because it is not used during decryption
bypassSpawn: bypassSpawn || bypassAutoEncryption,
}

if !mc.bypassSpawn {
mc.path, mc.spawnArgs = createSpawnArgs(opts)
mc.path, mc.spawnArgs = createSpawnArgs(opts.ExtraOptions)
if err := mc.spawnProcess(); err != nil {
return nil, err
}
}

// get connection string
uri := defaultURI
if u, ok := opts["mongocryptdURI"]; ok {
if u, ok := opts.ExtraOptions["mongocryptdURI"]; ok {
uri = u.(string)
}

Expand Down

0 comments on commit 7a2d1a7

Please sign in to comment.