Skip to content

Commit

Permalink
Merge branch 'master' into patch-pg
Browse files Browse the repository at this point in the history
  • Loading branch information
BradleyBoutcher authored Jan 16, 2020
2 parents 2a37666 + fe90e35 commit fb83930
Show file tree
Hide file tree
Showing 8 changed files with 552 additions and 89 deletions.
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ require (
github.com/joho/godotenv v1.2.0
github.com/json-iterator/go v1.1.8 // indirect
github.com/lib/pq v0.0.0-20180123210206-19c8e9ad0095
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/pkg/errors v0.8.1
Expand All @@ -34,7 +33,6 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/yaml.v2 v2.2.2
k8s.io/api v0.0.0-20180712090710-2d6f90ab1293
k8s.io/apiextensions-apiserver v0.0.0-20180808065829-408db4a50408
Expand Down
80 changes: 26 additions & 54 deletions internal/plugin/connectors/tcp/mssql/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,35 +100,30 @@ Overview of the connection process
type SingleUseConnector struct {
clientConn net.Conn
clientBuff io.ReadWriteCloser
logger log.Logger
// Note: We're following standard ctor naming practices with this field.
newMSSQLConnector types.MSSQLConnectorCtor
readPreloginRequest types.ReadPreloginRequestFunc
writePreloginResponse types.WritePreloginResponseFunc
readLoginRequest types.ReadLoginRequestFunc
writeLoginResponse types.WriteLoginResponseFunc
writeError types.WriteErrorFunc
newTdsBuffer types.TdsBufferCtor

types.ConnectorOptions
}

// NewSingleUseConnector creates a new production SingleUseConnector.
// This uses the production version of the dependencies, which delegate to the actual 3rd
// party driver.
func NewSingleUseConnector(logger log.Logger) *SingleUseConnector {
return NewSingleUseConnectorWithOptions(
logger,
NewMSSQLConnector,
mssql.ReadPreloginRequest,
mssql.WritePreloginResponse,
mssql.ReadLoginRequest,
mssql.WriteLoginResponse,
mssql.WriteError72,
// NewIdempotentDefaultTdsBuffer is wrapped so that it conforms to the
// types.TdsBufferCtor func signature
func(transport io.ReadWriteCloser) io.ReadWriteCloser {
return mssql.NewIdempotentDefaultTdsBuffer(transport)
return &SingleUseConnector{
ConnectorOptions: types.ConnectorOptions{
Logger: logger,
NewMSSQLConnector: NewMSSQLConnector,
ReadPreloginRequest: mssql.ReadPreloginRequest,
WritePreloginResponse: mssql.WritePreloginResponse,
ReadLoginRequest: mssql.ReadLoginRequest,
WriteLoginResponse: mssql.WriteLoginResponse,
WriteError: mssql.WriteError72,
// NewIdempotentDefaultTdsBuffer is wrapped so that it conforms to the
// types.TdsBufferCtor func signature
NewTdsBuffer: func(transport io.ReadWriteCloser) io.ReadWriteCloser {
return mssql.NewIdempotentDefaultTdsBuffer(transport)
},
},
)
}
}

// NewMSSQLConnector is the production implementation of MSSQLConnectorCtor,
Expand All @@ -149,31 +144,6 @@ func NewMSSQLConnector(dsn string) (types.MSSQLConnector, error) {
return types.MSSQLConnectorFunc(fn), err
}

// NewSingleUseConnectorWithOptions creates a new SingleUseConnector, and allows
// you to specify the newMSSQLConnector explicitly. Intended to be used in unit
// tests only.
func NewSingleUseConnectorWithOptions(
logger log.Logger,
newMSSQLConnector types.MSSQLConnectorCtor,
readPreloginRequest types.ReadPreloginRequestFunc,
writePreloginResponse types.WritePreloginResponseFunc,
readLoginRequest types.ReadLoginRequestFunc,
writeLoginRequest types.WriteLoginResponseFunc,
writeError types.WriteErrorFunc,
newTdsBuffer types.TdsBufferCtor,
) *SingleUseConnector {
return &SingleUseConnector{
logger: logger,
newMSSQLConnector: newMSSQLConnector,
readPreloginRequest: readPreloginRequest,
writePreloginResponse: writePreloginResponse,
readLoginRequest: readLoginRequest,
writeLoginResponse: writeLoginRequest,
writeError: writeError,
newTdsBuffer: newTdsBuffer,
}
}

type connectResult struct {
conn net.Conn
err error
Expand Down Expand Up @@ -210,15 +180,17 @@ func (connector *SingleUseConnector) Connect(
// client can advance to the next stage of the process. Otherwise the
// client would block forever waiting for its pre-login handshake to be
// read.
connector.clientBuff = connector.newTdsBuffer(connector.clientConn)
_, err := connector.readPreloginRequest(connector.clientBuff)
connector.clientBuff = connector.NewTdsBuffer(connector.clientConn)
_, err := connector.ReadPreloginRequest(connector.clientBuff)
if err != nil {
wrappedError := errors.Wrap(err, "failed to read prelogin request from client")
connector.writeErrorToClient(wrappedError)
return nil, wrappedError
}

// Prepare connection details from the client, formatted for MSSQL
// TODO: find out if it is possible to send errors during prelogin-phase
// TODO: send error to client on failed credential validation
connDetails := NewConnectionDetails(credentialValuesByID)

// Create a new MSSQL connector
Expand All @@ -227,7 +199,7 @@ func (connector *SingleUseConnector) Connect(
// NOTE: Secretless has some unfortunate naming collisions with the
// go-mssqldb driver package. The driver package has its own concept of a
// "connector", and its connectors also have a "Connect" method.
driverConnector, err := connector.newMSSQLConnector(dataSourceName(connDetails))
driverConnector, err := connector.NewMSSQLConnector(dataSourceName(connDetails))
if err != nil {
wrappedError := errors.Wrap(err, "failed to create a go-mssqldb connector")
connector.writeErrorToClient(wrappedError)
Expand Down Expand Up @@ -262,7 +234,7 @@ func (connector *SingleUseConnector) Connect(
return nil, err
}

if err = connector.writeLoginResponse(connector.clientBuff, *loginResp); err != nil {
if err = connector.WriteLoginResponse(connector.clientBuff, loginResp); err != nil {
wrappedError := errors.Wrap(
err,
"failed to send a successful authentication response to client",
Expand Down Expand Up @@ -316,7 +288,7 @@ func (connector *SingleUseConnector) waitForServerConnection(
preloginResponse[mssql.PreloginENCRYPTION] = []byte{mssql.EncryptNotSup}

// Write the prelogin packet back to the user
err = connector.writePreloginResponse(connector.clientBuff, preloginResponse)
err = connector.WritePreloginResponse(connector.clientBuff, preloginResponse)
if err != nil {
wrappedError := errors.Wrap(
err,
Expand All @@ -326,7 +298,7 @@ func (connector *SingleUseConnector) waitForServerConnection(

// We parse the client's LoginRequest packet so that we can pass on params to the
// server.
clientLoginRequest, err := connector.readLoginRequest(connector.clientBuff)
clientLoginRequest, err := connector.ReadLoginRequest(connector.clientBuff)
if err != nil {
wrappedError := errors.Wrap(err, "failed to handle login from client")
return nil, nil, wrappedError
Expand Down Expand Up @@ -375,7 +347,7 @@ func (connector *SingleUseConnector) waitForServerConnection(
}

func (connector *SingleUseConnector) writeErrorToClient(err error) {
_ = connector.writeError(connector.clientBuff, protocolError(err))
_ = connector.WriteError(connector.clientBuff, protocolError(err))
}

func dataSourceName(connDetails *ConnectionDetails) string {
Expand Down
Loading

0 comments on commit fb83930

Please sign in to comment.