Lint / golangci-lint (push) Waiting to run
Lint / semgrep (push) Waiting to run
Release / Release (push) Waiting to run
Scan for secrets / test (push) Waiting to run
Test / test (push) Waiting to run
Test / test-community (push) Waiting to run
* Fix jdbc detector detecting incomplete conn string and fixed invalid parsing of sql server string * [INS-165] Jdbc detector integration tests fix (#4637) * [INS-165] Fix Jdbc tests and updated the deprecated code
259 lines
6.8 KiB
Go
259 lines
6.8 KiB
Go
package jdbc
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
|
)
|
|
|
|
func TestParseSqlServerMissingCredentials(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
subname string
|
|
shouldBeNil bool
|
|
reason string
|
|
}{
|
|
{
|
|
name: "no password - should return nil (nothing to verify)",
|
|
subname: "//examplehost.net;databaseName=QRG1;sendStringParametersAsUnicode=false",
|
|
shouldBeNil: true,
|
|
reason: "no password present",
|
|
},
|
|
{
|
|
name: "no host - should return nil (invalid connection)",
|
|
subname: "//;password=secret123",
|
|
shouldBeNil: true,
|
|
reason: "no host present",
|
|
},
|
|
{
|
|
name: "no host and no password - should return nil",
|
|
subname: "//;databaseName=QRG1",
|
|
shouldBeNil: true,
|
|
reason: "no host or password present",
|
|
},
|
|
{
|
|
name: "csm-1584-example",
|
|
subname: "//examplehost.net;databaseName=QRG1;sendStringParametersAsUnicode=false;loginTimeout=4;applicationName=pdal-cat-hierarchy-loader-v1;",
|
|
shouldBeNil: true,
|
|
reason: "no password present",
|
|
},
|
|
{
|
|
name: "valid with both host and password - should succeed",
|
|
subname: "//examplehost.net;password=secret123",
|
|
shouldBeNil: false,
|
|
},
|
|
{
|
|
name: "valid with host:port and password - should succeed",
|
|
subname: "//examplehost.net:1433;password=secret123",
|
|
shouldBeNil: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctx := logContext.AddLogger(context.Background())
|
|
|
|
j, err := parseSqlServer(ctx, tt.subname)
|
|
|
|
if tt.shouldBeNil {
|
|
if j != nil {
|
|
t.Errorf("parseSqlServer() expected nil (%s), but got connection: %v",
|
|
tt.reason, j)
|
|
}
|
|
} else {
|
|
if j == nil {
|
|
t.Errorf("parseSqlServer() returned nil, expected valid connection. err = %v", err)
|
|
}
|
|
if err != nil {
|
|
t.Errorf("parseSqlServer() unexpected error = %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// This test demonstrates the username is ignored when parsing the JDBC URL. Instead the default username "sa" is always used.
|
|
func TestParseSqlServerUserIgnoredBug2(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
subname string // the part after "jdbc:sqlserver:"
|
|
wantUsername string
|
|
}{
|
|
{
|
|
name: "user parameter specified",
|
|
subname: "//localhost:1433;user=myuser;password=mypass",
|
|
wantUsername: "myuser",
|
|
},
|
|
{
|
|
name: "user id parameter specified",
|
|
subname: "//localhost:1433;user id=admin;password=secret",
|
|
wantUsername: "admin",
|
|
},
|
|
{
|
|
name: "no user specified - should default to sa",
|
|
subname: "//localhost:1433;password=mypass",
|
|
wantUsername: "sa",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctx := logContext.AddLogger(context.Background())
|
|
|
|
j, err := parseSqlServer(ctx, tt.subname)
|
|
if err != nil {
|
|
t.Fatalf("parseSqlServer() error = %v", err)
|
|
}
|
|
|
|
sqlServerConn := j.(*SqlServerJDBC)
|
|
|
|
if sqlServerConn.User != tt.wantUsername {
|
|
t.Errorf("Connection string does not contain expected username '%s'\nGot: %s\nExpected to contain: %s",
|
|
tt.wantUsername, sqlServerConn.User, tt.wantUsername)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseSqlServerWithJdbcAndOdbcBridgeString(t *testing.T) {
|
|
subname := "//odbc:server=localhost;port=1433;database=testdb;password=testpassword"
|
|
|
|
wantHost := "localhost"
|
|
wantPort := "1433"
|
|
wantPassword := "testpassword"
|
|
wantDatabase := "testdb"
|
|
|
|
ctx := logContext.AddLogger(context.Background())
|
|
|
|
j, err := parseSqlServer(ctx, subname)
|
|
if err != nil {
|
|
t.Fatalf("parseSqlServer() error = %v", err)
|
|
}
|
|
|
|
if j == nil {
|
|
t.Fatalf("parseSqlServer() returned nil, expected valid connection.")
|
|
}
|
|
|
|
sqlServerConn, ok := j.(*SqlServerJDBC)
|
|
if !ok {
|
|
t.Fatalf("parseSqlServer() returned unexpected type %T, expected *SqlServerJDBC", j)
|
|
}
|
|
|
|
if sqlServerConn.Host != wantHost+":"+wantPort {
|
|
t.Errorf("Host mismatch. Got: %s, Want: %s", sqlServerConn.Host, wantHost+":"+wantPort)
|
|
}
|
|
|
|
if sqlServerConn.Password != wantPassword {
|
|
t.Errorf("Password mismatch. Got: %s, Want: %s", sqlServerConn.Password, wantPassword)
|
|
}
|
|
|
|
if sqlServerConn.Database != wantDatabase {
|
|
t.Errorf("Database mismatch. Got: %s, Want: %s", sqlServerConn.Database, wantDatabase)
|
|
}
|
|
}
|
|
func TestSQLServerHandler_ParseJDBCURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
jdbcURL string
|
|
wantHost string
|
|
wantDB string
|
|
wantUser string
|
|
wantPass string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "basic URL with semicolon params",
|
|
jdbcURL: "jdbc:sqlserver://localhost:1433;database=testdb;user=sa;password=Pass123",
|
|
wantHost: "localhost:1433",
|
|
wantDB: "testdb",
|
|
wantUser: "sa",
|
|
wantPass: "Pass123",
|
|
},
|
|
{
|
|
name: "URL with default port and database",
|
|
jdbcURL: "jdbc:sqlserver://dbhost;user=testuser;password=secret",
|
|
wantHost: "dbhost:1433",
|
|
wantDB: "master",
|
|
wantUser: "testuser",
|
|
wantPass: "secret",
|
|
},
|
|
{
|
|
name: "URL with port in host",
|
|
jdbcURL: "jdbc:sqlserver://server.example.com:1434;databaseName=mydb;userId=admin;pwd=admin123",
|
|
wantHost: "server.example.com:1434",
|
|
wantDB: "mydb",
|
|
wantUser: "admin",
|
|
wantPass: "admin123",
|
|
},
|
|
{
|
|
name: "invalid URL - missing jdbc:sqlserver prefix",
|
|
jdbcURL: "jdbc:mysql://localhost/db",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "invalid URL - missing //",
|
|
jdbcURL: "jdbc:sqlserver:localhost;database=test",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
jdbc, err := NewJDBC(logContext.Background(), tt.jdbcURL)
|
|
if tt.wantErr {
|
|
assert.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
info := jdbc.GetConnectionInfo()
|
|
assert.Equal(t, tt.wantHost, info.Host)
|
|
assert.Equal(t, tt.wantDB, info.Database)
|
|
assert.Equal(t, tt.wantUser, info.User)
|
|
assert.Equal(t, tt.wantPass, info.Password)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSQLServerHandler_BuildNativeConnectionString(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
info *ConnectionInfo
|
|
wantUser string
|
|
wantPass string
|
|
wantHost string
|
|
wantDB string
|
|
}{
|
|
{
|
|
name: "basic connection",
|
|
info: &ConnectionInfo{
|
|
Host: "localhost",
|
|
Database: "testdb",
|
|
User: "sa",
|
|
Password: "Pass123",
|
|
},
|
|
wantUser: "sa",
|
|
wantPass: "Pass123",
|
|
wantHost: "localhost",
|
|
wantDB: "testdb",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
jdbc := &SqlServerJDBC{
|
|
ConnectionInfo: *tt.info,
|
|
}
|
|
connStr := jdbc.BuildConnectionString()
|
|
|
|
// SQL Server format: sqlserver://user:password@host:port?database=db&connection+timeout=10
|
|
assert.Contains(t, connStr, tt.wantUser)
|
|
assert.Contains(t, connStr, tt.wantPass)
|
|
assert.Contains(t, connStr, tt.wantHost)
|
|
assert.Contains(t, connStr, "database="+tt.wantDB)
|
|
})
|
|
}
|
|
}
|