mirror of
https://github.com/trufflesecurity/trufflehog.git
synced 2024-09-20 06:31:57 +00:00
[analyze] Add Analyzer for MySQL (#3193)
* implement analyzer interface for mysql * add integration test for mysql analyzer * linked detectors with analyzers for jdbc and mysql validation for connection string in analyzer * refactored secretInfoToAnalyzerResult func * generated permissions for mysql analyzer * [chore] - optimization in execution flow - use test-container library for analyze test. * added host in secret info struct simplified the mysql test due to huge structure --------- Co-authored-by: Abdul Basit <abasit@folio3.com>
This commit is contained in:
parent
e89190f3ed
commit
b0318a9edb
7 changed files with 835 additions and 2 deletions
1
pkg/analyzer/analyzers/mysql/expected_output.json
Normal file
1
pkg/analyzer/analyzers/mysql/expected_output.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,5 @@
|
|||
//go:generate generate_permissions permissions.yaml permissions.go mysql
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
|
@ -17,8 +19,189 @@ import (
|
|||
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
|
||||
var _ analyzers.Analyzer = (*Analyzer)(nil)
|
||||
|
||||
type Analyzer struct {
|
||||
Cfg *config.Config
|
||||
}
|
||||
|
||||
func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_MySQL }
|
||||
|
||||
func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) {
|
||||
uri, ok := credInfo["connection_string"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing connection string")
|
||||
}
|
||||
info, err := AnalyzePermissions(a.Cfg, uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return secretInfoToAnalyzerResult(info), nil
|
||||
}
|
||||
|
||||
func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult {
|
||||
if info == nil {
|
||||
return nil
|
||||
}
|
||||
result := analyzers.AnalyzerResult{
|
||||
AnalyzerType: analyzerpb.AnalyzerType_MySQL,
|
||||
Metadata: nil,
|
||||
Bindings: []analyzers.Binding{},
|
||||
}
|
||||
|
||||
// add user priviliges to bindings
|
||||
userBindings, userResource := bakeUserBindings(info)
|
||||
result.Bindings = append(result.Bindings, userBindings...)
|
||||
|
||||
// add user's database priviliges to bindings
|
||||
databaseBindings := bakeDatabaseBindings(userResource, info)
|
||||
result.Bindings = append(result.Bindings, databaseBindings...)
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func bakeUserBindings(info *SecretInfo) ([]analyzers.Binding, *analyzers.Resource) {
|
||||
|
||||
var userBindings []analyzers.Binding
|
||||
|
||||
// add user and their priviliges to bindings
|
||||
userResource := analyzers.Resource{
|
||||
Name: info.User,
|
||||
FullyQualifiedName: info.Host + "/" + info.User,
|
||||
Type: "user",
|
||||
}
|
||||
|
||||
for _, priv := range info.GlobalPrivs.Privs {
|
||||
userBindings = append(userBindings, analyzers.Binding{
|
||||
Resource: userResource,
|
||||
Permission: analyzers.Permission{
|
||||
Value: priv,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return userBindings, &userResource
|
||||
}
|
||||
|
||||
func bakeDatabaseBindings(userResource *analyzers.Resource, info *SecretInfo) []analyzers.Binding {
|
||||
var databaseBindings []analyzers.Binding
|
||||
|
||||
for _, database := range info.Databases {
|
||||
dbResource := analyzers.Resource{
|
||||
Name: database.Name,
|
||||
FullyQualifiedName: info.Host + "/" + database.Name,
|
||||
Type: "database",
|
||||
Metadata: map[string]any{
|
||||
"default": database.Default,
|
||||
"non_existent": database.Nonexistent,
|
||||
},
|
||||
Parent: userResource,
|
||||
}
|
||||
|
||||
for _, priv := range database.Privs {
|
||||
databaseBindings = append(databaseBindings, analyzers.Binding{
|
||||
Resource: dbResource,
|
||||
Permission: analyzers.Permission{
|
||||
Value: priv,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// add this database's table privileges to bindings
|
||||
tableBindings := bakeTableBindings(&dbResource, database)
|
||||
databaseBindings = append(databaseBindings, tableBindings...)
|
||||
|
||||
// add this database's routines privileges to bindings
|
||||
routineBindings := bakeRoutineBindings(&dbResource, database)
|
||||
databaseBindings = append(databaseBindings, routineBindings...)
|
||||
}
|
||||
|
||||
return databaseBindings
|
||||
}
|
||||
|
||||
func bakeTableBindings(dbResource *analyzers.Resource, database *Database) []analyzers.Binding {
|
||||
if database.Tables == nil {
|
||||
return nil
|
||||
}
|
||||
var tableBindings []analyzers.Binding
|
||||
for _, table := range *database.Tables {
|
||||
tableResource := analyzers.Resource{
|
||||
Name: table.Name,
|
||||
FullyQualifiedName: dbResource.FullyQualifiedName + "/" + table.Name,
|
||||
Type: "table",
|
||||
Metadata: map[string]any{
|
||||
"bytes": table.Bytes,
|
||||
"non_existent": table.Nonexistent,
|
||||
},
|
||||
Parent: dbResource,
|
||||
}
|
||||
|
||||
for _, priv := range table.Privs {
|
||||
tableBindings = append(tableBindings, analyzers.Binding{
|
||||
Resource: tableResource,
|
||||
Permission: analyzers.Permission{
|
||||
Value: priv,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Add this table's column privileges to bindings
|
||||
for _, column := range table.Columns {
|
||||
columnResource := analyzers.Resource{
|
||||
Name: column.Name,
|
||||
FullyQualifiedName: tableResource.FullyQualifiedName + "/" + column.Name,
|
||||
Type: "column",
|
||||
Parent: &tableResource,
|
||||
}
|
||||
|
||||
for _, priv := range column.Privs {
|
||||
tableBindings = append(tableBindings, analyzers.Binding{
|
||||
Resource: columnResource,
|
||||
Permission: analyzers.Permission{
|
||||
Value: priv,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tableBindings
|
||||
}
|
||||
|
||||
func bakeRoutineBindings(dbResource *analyzers.Resource, database *Database) []analyzers.Binding {
|
||||
if database.Routines == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var routineBindings []analyzers.Binding
|
||||
for _, routine := range *database.Routines {
|
||||
routineResource := analyzers.Resource{
|
||||
Name: routine.Name,
|
||||
FullyQualifiedName: dbResource.FullyQualifiedName + "/" + routine.Name,
|
||||
Type: "routine",
|
||||
Metadata: map[string]any{
|
||||
"non_existent": routine.Nonexistent,
|
||||
},
|
||||
Parent: dbResource,
|
||||
}
|
||||
|
||||
for _, priv := range routine.Privs {
|
||||
routineBindings = append(routineBindings, analyzers.Binding{
|
||||
Resource: routineResource,
|
||||
Permission: analyzers.Permission{
|
||||
Value: priv,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return routineBindings
|
||||
}
|
||||
|
||||
const (
|
||||
// MySQL SSL Modes
|
||||
mysql_sslmode = "ssl-mode"
|
||||
|
@ -74,6 +257,7 @@ type Routine struct {
|
|||
// USER() returns `doadmin@localhost`
|
||||
|
||||
type SecretInfo struct {
|
||||
Host string
|
||||
User string
|
||||
Databases map[string]*Database
|
||||
GlobalPrivs GlobalPrivs
|
||||
|
@ -99,8 +283,13 @@ func AnalyzeAndPrintPermissions(cfg *config.Config, key string) {
|
|||
}
|
||||
|
||||
func AnalyzePermissions(cfg *config.Config, connectionStr string) (*SecretInfo, error) {
|
||||
// Parse the connection string
|
||||
u, err := parseConnectionStr(connectionStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing the connection string: %w", err)
|
||||
}
|
||||
|
||||
db, err := createConnection(connectionStr)
|
||||
db, err := createConnection(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("connecting to the MySQL database: %w", err)
|
||||
}
|
||||
|
@ -139,13 +328,14 @@ func AnalyzePermissions(cfg *config.Config, connectionStr string) (*SecretInfo,
|
|||
processGrants(grants, databases, &globalPrivs)
|
||||
|
||||
return &SecretInfo{
|
||||
Host: u.Hostname(),
|
||||
User: user,
|
||||
Databases: databases,
|
||||
GlobalPrivs: globalPrivs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createConnection(connection string) (*sql.DB, error) {
|
||||
func parseConnectionStr(connection string) (*dburl.URL, error) {
|
||||
// Check if the connection string starts with 'mysql://'
|
||||
if !strings.HasPrefix(connection, "mysql://") {
|
||||
color.Yellow("[i] The connection string should start with 'mysql://'. Adding it for you.")
|
||||
|
@ -163,7 +353,10 @@ func createConnection(connection string) (*sql.DB, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func createConnection(u *dburl.URL) (*sql.DB, error) {
|
||||
// Connect to the MySQL database
|
||||
db, err := sql.Open("mysql", u.DSN)
|
||||
if err != nil {
|
||||
|
|
104
pkg/analyzer/analyzers/mysql/mysql_test.go
Normal file
104
pkg/analyzer/analyzers/mysql/mysql_test.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v7"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/testcontainers/testcontainers-go/modules/mysql"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config"
|
||||
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
|
||||
)
|
||||
|
||||
//go:embed expected_output.json
|
||||
var expectedOutput []byte
|
||||
|
||||
func TestAnalyzer_Analyze(t *testing.T) {
|
||||
mysqlUser := "root"
|
||||
mysqlPass := gofakeit.Password(true, true, true, false, false, 10)
|
||||
mysqlDatabase := "mysql"
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
mysqlC, err := mysql.Run(ctx, "mysql",
|
||||
mysql.WithDatabase(mysqlDatabase),
|
||||
mysql.WithUsername(mysqlUser),
|
||||
mysql.WithPassword(mysqlPass),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() { _ = mysqlC.Terminate(ctx) }()
|
||||
|
||||
host, err := mysqlC.Host(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port, err := mysqlC.MappedPort(ctx, "3306")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
connectionString string
|
||||
want []byte // JSON string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid Mysql connection",
|
||||
connectionString: fmt.Sprintf(`root:%s@%s:%s/%s`, mysqlPass, host, port.Port(), mysqlDatabase),
|
||||
want: expectedOutput,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := Analyzer{Cfg: &config.Config{}}
|
||||
got, err := a.Analyze(context.Background(), map[string]string{"connection_string": tt.connectionString})
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Analyzer.Analyze() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
// Marshal the actual result to JSON
|
||||
gotJSON, err := json.Marshal(got)
|
||||
if err != nil {
|
||||
t.Fatalf("could not marshal got to JSON: %s", err)
|
||||
}
|
||||
|
||||
// Parse the expected JSON string
|
||||
var wantObj analyzers.AnalyzerResult
|
||||
if err := json.Unmarshal(tt.want, &wantObj); err != nil {
|
||||
t.Fatalf("could not unmarshal want JSON string: %s", err)
|
||||
}
|
||||
|
||||
// Marshal the expected result to JSON (to normalize)
|
||||
wantJSON, err := json.Marshal(wantObj)
|
||||
if err != nil {
|
||||
t.Fatalf("could not marshal want to JSON: %s", err)
|
||||
}
|
||||
|
||||
// Compare bindings separately because they are not guaranteed to be in the same order
|
||||
if len(got.Bindings) != len(wantObj.Bindings) {
|
||||
t.Errorf("Analyzer.Analyze() = %s, want %s", gotJSON, wantJSON)
|
||||
return
|
||||
}
|
||||
|
||||
got.Bindings = nil
|
||||
wantObj.Bindings = nil
|
||||
|
||||
// Compare the rest of the Object
|
||||
if diff := cmp.Diff(&wantObj, got); diff != "" {
|
||||
t.Errorf("%s: (-want +got)\n%s", tt.name, diff)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
451
pkg/analyzer/analyzers/mysql/permissions.go
Normal file
451
pkg/analyzer/analyzers/mysql/permissions.go
Normal file
|
@ -0,0 +1,451 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
package mysql
|
||||
|
||||
import "errors"
|
||||
|
||||
type Permission int
|
||||
|
||||
const (
|
||||
Invalid Permission = iota
|
||||
Alter Permission = iota
|
||||
AlterRoutine Permission = iota
|
||||
AllowNonexistentDefiner Permission = iota
|
||||
ApplicationPasswordAdmin Permission = iota
|
||||
AuditAbortExempt Permission = iota
|
||||
AuditAdmin Permission = iota
|
||||
AuthenticationPolicyAdmin Permission = iota
|
||||
BackupAdmin Permission = iota
|
||||
BinlogAdmin Permission = iota
|
||||
BinlogEncryptionAdmin Permission = iota
|
||||
CloneAdmin Permission = iota
|
||||
ConnectionAdmin Permission = iota
|
||||
Create Permission = iota
|
||||
CreateRole Permission = iota
|
||||
CreateRoutine Permission = iota
|
||||
CreateTablespace Permission = iota
|
||||
CreateTemporaryTables Permission = iota
|
||||
CreateUser Permission = iota
|
||||
CreateView Permission = iota
|
||||
Delete Permission = iota
|
||||
Drop Permission = iota
|
||||
DropRole Permission = iota
|
||||
EncryptionKeyAdmin Permission = iota
|
||||
Event Permission = iota
|
||||
Execute Permission = iota
|
||||
File Permission = iota
|
||||
FirewallAdmin Permission = iota
|
||||
FirewallExempt Permission = iota
|
||||
FirewallUser Permission = iota
|
||||
FlushOptimizerCosts Permission = iota
|
||||
FlushStatus Permission = iota
|
||||
FlushTables Permission = iota
|
||||
FlushUserResources Permission = iota
|
||||
GrantOption Permission = iota
|
||||
GroupReplicationAdmin Permission = iota
|
||||
GroupReplicationStream Permission = iota
|
||||
Index Permission = iota
|
||||
InnodbRedoLogArchive Permission = iota
|
||||
InnodbRedoLogEnable Permission = iota
|
||||
Insert Permission = iota
|
||||
LockingTables Permission = iota
|
||||
MaskingDictionariesAdmin Permission = iota
|
||||
NdbStoredUser Permission = iota
|
||||
PasswordlessUserAdmin Permission = iota
|
||||
PersistRoVariablesAdmin Permission = iota
|
||||
Process Permission = iota
|
||||
Proxy Permission = iota
|
||||
References Permission = iota
|
||||
Reload Permission = iota
|
||||
ReplicationApplier Permission = iota
|
||||
ReplicationClient Permission = iota
|
||||
ReplicationSlave Permission = iota
|
||||
ReplicationSlaveAdmin Permission = iota
|
||||
ResourceGroupAdmin Permission = iota
|
||||
ResourceGroupUser Permission = iota
|
||||
RoleAdmin Permission = iota
|
||||
Select Permission = iota
|
||||
SensitiveVariablesObserver Permission = iota
|
||||
ServiceConnectionAdmin Permission = iota
|
||||
SessionVariablesAdmin Permission = iota
|
||||
SetAnyDefiner Permission = iota
|
||||
SetUserId Permission = iota
|
||||
ShowDatabases Permission = iota
|
||||
ShowRoutine Permission = iota
|
||||
ShowView Permission = iota
|
||||
Shutdown Permission = iota
|
||||
SkipQueryRewrite Permission = iota
|
||||
Super Permission = iota
|
||||
SystemUser Permission = iota
|
||||
SystemVariablesAdmin Permission = iota
|
||||
TableEncryptionAdmin Permission = iota
|
||||
TelemetryLogAdmin Permission = iota
|
||||
TpConnectionAdmin Permission = iota
|
||||
TransactionGtidTag Permission = iota
|
||||
Trigger Permission = iota
|
||||
Update Permission = iota
|
||||
Usage Permission = iota
|
||||
VersionTokenAdmin Permission = iota
|
||||
XaRecoverAdmin Permission = iota
|
||||
)
|
||||
|
||||
var (
|
||||
PermissionStrings = map[Permission]string{
|
||||
Alter: "alter",
|
||||
AlterRoutine: "alter_routine",
|
||||
AllowNonexistentDefiner: "allow_nonexistent_definer",
|
||||
ApplicationPasswordAdmin: "application_password_admin",
|
||||
AuditAbortExempt: "audit_abort_exempt",
|
||||
AuditAdmin: "audit_admin",
|
||||
AuthenticationPolicyAdmin: "authentication_policy_admin",
|
||||
BackupAdmin: "backup_admin",
|
||||
BinlogAdmin: "binlog_admin",
|
||||
BinlogEncryptionAdmin: "binlog_encryption_admin",
|
||||
CloneAdmin: "clone_admin",
|
||||
ConnectionAdmin: "connection_admin",
|
||||
Create: "create",
|
||||
CreateRole: "create_role",
|
||||
CreateRoutine: "create_routine",
|
||||
CreateTablespace: "create_tablespace",
|
||||
CreateTemporaryTables: "create_temporary_tables",
|
||||
CreateUser: "create_user",
|
||||
CreateView: "create_view",
|
||||
Delete: "delete",
|
||||
Drop: "drop",
|
||||
DropRole: "drop_role",
|
||||
EncryptionKeyAdmin: "encryption_key_admin",
|
||||
Event: "event",
|
||||
Execute: "execute",
|
||||
File: "file",
|
||||
FirewallAdmin: "firewall_admin",
|
||||
FirewallExempt: "firewall_exempt",
|
||||
FirewallUser: "firewall_user",
|
||||
FlushOptimizerCosts: "flush_optimizer_costs",
|
||||
FlushStatus: "flush_status",
|
||||
FlushTables: "flush_tables",
|
||||
FlushUserResources: "flush_user_resources",
|
||||
GrantOption: "grant_option",
|
||||
GroupReplicationAdmin: "group_replication_admin",
|
||||
GroupReplicationStream: "group_replication_stream",
|
||||
Index: "index",
|
||||
InnodbRedoLogArchive: "innodb_redo_log_archive",
|
||||
InnodbRedoLogEnable: "innodb_redo_log_enable",
|
||||
Insert: "insert",
|
||||
LockingTables: "locking_tables",
|
||||
MaskingDictionariesAdmin: "masking_dictionaries_admin",
|
||||
NdbStoredUser: "ndb_stored_user",
|
||||
PasswordlessUserAdmin: "passwordless_user_admin",
|
||||
PersistRoVariablesAdmin: "persist_ro_variables_admin",
|
||||
Process: "process",
|
||||
Proxy: "proxy",
|
||||
References: "references",
|
||||
Reload: "reload",
|
||||
ReplicationApplier: "replication_applier",
|
||||
ReplicationClient: "replication_client",
|
||||
ReplicationSlave: "replication_slave",
|
||||
ReplicationSlaveAdmin: "replication_slave_admin",
|
||||
ResourceGroupAdmin: "resource_group_admin",
|
||||
ResourceGroupUser: "resource_group_user",
|
||||
RoleAdmin: "role_admin",
|
||||
Select: "select",
|
||||
SensitiveVariablesObserver: "sensitive_variables_observer",
|
||||
ServiceConnectionAdmin: "service_connection_admin",
|
||||
SessionVariablesAdmin: "session_variables_admin",
|
||||
SetAnyDefiner: "set_any_definer",
|
||||
SetUserId: "set_user_id",
|
||||
ShowDatabases: "show_databases",
|
||||
ShowRoutine: "show_routine",
|
||||
ShowView: "show_view",
|
||||
Shutdown: "shutdown",
|
||||
SkipQueryRewrite: "skip_query_rewrite",
|
||||
Super: "super",
|
||||
SystemUser: "system_user",
|
||||
SystemVariablesAdmin: "system_variables_admin",
|
||||
TableEncryptionAdmin: "table_encryption_admin",
|
||||
TelemetryLogAdmin: "telemetry_log_admin",
|
||||
TpConnectionAdmin: "tp_connection_admin",
|
||||
TransactionGtidTag: "transaction_gtid_tag",
|
||||
Trigger: "trigger",
|
||||
Update: "update",
|
||||
Usage: "usage",
|
||||
VersionTokenAdmin: "version_token_admin",
|
||||
XaRecoverAdmin: "xa_recover_admin",
|
||||
}
|
||||
|
||||
StringToPermission = map[string]Permission{
|
||||
"alter": Alter,
|
||||
"alter_routine": AlterRoutine,
|
||||
"allow_nonexistent_definer": AllowNonexistentDefiner,
|
||||
"application_password_admin": ApplicationPasswordAdmin,
|
||||
"audit_abort_exempt": AuditAbortExempt,
|
||||
"audit_admin": AuditAdmin,
|
||||
"authentication_policy_admin": AuthenticationPolicyAdmin,
|
||||
"backup_admin": BackupAdmin,
|
||||
"binlog_admin": BinlogAdmin,
|
||||
"binlog_encryption_admin": BinlogEncryptionAdmin,
|
||||
"clone_admin": CloneAdmin,
|
||||
"connection_admin": ConnectionAdmin,
|
||||
"create": Create,
|
||||
"create_role": CreateRole,
|
||||
"create_routine": CreateRoutine,
|
||||
"create_tablespace": CreateTablespace,
|
||||
"create_temporary_tables": CreateTemporaryTables,
|
||||
"create_user": CreateUser,
|
||||
"create_view": CreateView,
|
||||
"delete": Delete,
|
||||
"drop": Drop,
|
||||
"drop_role": DropRole,
|
||||
"encryption_key_admin": EncryptionKeyAdmin,
|
||||
"event": Event,
|
||||
"execute": Execute,
|
||||
"file": File,
|
||||
"firewall_admin": FirewallAdmin,
|
||||
"firewall_exempt": FirewallExempt,
|
||||
"firewall_user": FirewallUser,
|
||||
"flush_optimizer_costs": FlushOptimizerCosts,
|
||||
"flush_status": FlushStatus,
|
||||
"flush_tables": FlushTables,
|
||||
"flush_user_resources": FlushUserResources,
|
||||
"grant_option": GrantOption,
|
||||
"group_replication_admin": GroupReplicationAdmin,
|
||||
"group_replication_stream": GroupReplicationStream,
|
||||
"index": Index,
|
||||
"innodb_redo_log_archive": InnodbRedoLogArchive,
|
||||
"innodb_redo_log_enable": InnodbRedoLogEnable,
|
||||
"insert": Insert,
|
||||
"locking_tables": LockingTables,
|
||||
"masking_dictionaries_admin": MaskingDictionariesAdmin,
|
||||
"ndb_stored_user": NdbStoredUser,
|
||||
"passwordless_user_admin": PasswordlessUserAdmin,
|
||||
"persist_ro_variables_admin": PersistRoVariablesAdmin,
|
||||
"process": Process,
|
||||
"proxy": Proxy,
|
||||
"references": References,
|
||||
"reload": Reload,
|
||||
"replication_applier": ReplicationApplier,
|
||||
"replication_client": ReplicationClient,
|
||||
"replication_slave": ReplicationSlave,
|
||||
"replication_slave_admin": ReplicationSlaveAdmin,
|
||||
"resource_group_admin": ResourceGroupAdmin,
|
||||
"resource_group_user": ResourceGroupUser,
|
||||
"role_admin": RoleAdmin,
|
||||
"select": Select,
|
||||
"sensitive_variables_observer": SensitiveVariablesObserver,
|
||||
"service_connection_admin": ServiceConnectionAdmin,
|
||||
"session_variables_admin": SessionVariablesAdmin,
|
||||
"set_any_definer": SetAnyDefiner,
|
||||
"set_user_id": SetUserId,
|
||||
"show_databases": ShowDatabases,
|
||||
"show_routine": ShowRoutine,
|
||||
"show_view": ShowView,
|
||||
"shutdown": Shutdown,
|
||||
"skip_query_rewrite": SkipQueryRewrite,
|
||||
"super": Super,
|
||||
"system_user": SystemUser,
|
||||
"system_variables_admin": SystemVariablesAdmin,
|
||||
"table_encryption_admin": TableEncryptionAdmin,
|
||||
"telemetry_log_admin": TelemetryLogAdmin,
|
||||
"tp_connection_admin": TpConnectionAdmin,
|
||||
"transaction_gtid_tag": TransactionGtidTag,
|
||||
"trigger": Trigger,
|
||||
"update": Update,
|
||||
"usage": Usage,
|
||||
"version_token_admin": VersionTokenAdmin,
|
||||
"xa_recover_admin": XaRecoverAdmin,
|
||||
}
|
||||
|
||||
PermissionIDs = map[Permission]int{
|
||||
Alter: 1,
|
||||
AlterRoutine: 2,
|
||||
AllowNonexistentDefiner: 3,
|
||||
ApplicationPasswordAdmin: 4,
|
||||
AuditAbortExempt: 5,
|
||||
AuditAdmin: 6,
|
||||
AuthenticationPolicyAdmin: 7,
|
||||
BackupAdmin: 8,
|
||||
BinlogAdmin: 9,
|
||||
BinlogEncryptionAdmin: 10,
|
||||
CloneAdmin: 11,
|
||||
ConnectionAdmin: 12,
|
||||
Create: 13,
|
||||
CreateRole: 14,
|
||||
CreateRoutine: 15,
|
||||
CreateTablespace: 16,
|
||||
CreateTemporaryTables: 17,
|
||||
CreateUser: 18,
|
||||
CreateView: 19,
|
||||
Delete: 20,
|
||||
Drop: 21,
|
||||
DropRole: 22,
|
||||
EncryptionKeyAdmin: 23,
|
||||
Event: 24,
|
||||
Execute: 25,
|
||||
File: 26,
|
||||
FirewallAdmin: 27,
|
||||
FirewallExempt: 28,
|
||||
FirewallUser: 29,
|
||||
FlushOptimizerCosts: 30,
|
||||
FlushStatus: 31,
|
||||
FlushTables: 32,
|
||||
FlushUserResources: 33,
|
||||
GrantOption: 34,
|
||||
GroupReplicationAdmin: 35,
|
||||
GroupReplicationStream: 36,
|
||||
Index: 37,
|
||||
InnodbRedoLogArchive: 38,
|
||||
InnodbRedoLogEnable: 39,
|
||||
Insert: 40,
|
||||
LockingTables: 41,
|
||||
MaskingDictionariesAdmin: 42,
|
||||
NdbStoredUser: 43,
|
||||
PasswordlessUserAdmin: 44,
|
||||
PersistRoVariablesAdmin: 45,
|
||||
Process: 46,
|
||||
Proxy: 47,
|
||||
References: 48,
|
||||
Reload: 49,
|
||||
ReplicationApplier: 50,
|
||||
ReplicationClient: 51,
|
||||
ReplicationSlave: 52,
|
||||
ReplicationSlaveAdmin: 53,
|
||||
ResourceGroupAdmin: 54,
|
||||
ResourceGroupUser: 55,
|
||||
RoleAdmin: 56,
|
||||
Select: 57,
|
||||
SensitiveVariablesObserver: 58,
|
||||
ServiceConnectionAdmin: 59,
|
||||
SessionVariablesAdmin: 60,
|
||||
SetAnyDefiner: 61,
|
||||
SetUserId: 62,
|
||||
ShowDatabases: 63,
|
||||
ShowRoutine: 64,
|
||||
ShowView: 65,
|
||||
Shutdown: 66,
|
||||
SkipQueryRewrite: 67,
|
||||
Super: 68,
|
||||
SystemUser: 69,
|
||||
SystemVariablesAdmin: 70,
|
||||
TableEncryptionAdmin: 71,
|
||||
TelemetryLogAdmin: 72,
|
||||
TpConnectionAdmin: 73,
|
||||
TransactionGtidTag: 74,
|
||||
Trigger: 75,
|
||||
Update: 76,
|
||||
Usage: 77,
|
||||
VersionTokenAdmin: 78,
|
||||
XaRecoverAdmin: 79,
|
||||
}
|
||||
|
||||
IdToPermission = map[int]Permission{
|
||||
1: Alter,
|
||||
2: AlterRoutine,
|
||||
3: AllowNonexistentDefiner,
|
||||
4: ApplicationPasswordAdmin,
|
||||
5: AuditAbortExempt,
|
||||
6: AuditAdmin,
|
||||
7: AuthenticationPolicyAdmin,
|
||||
8: BackupAdmin,
|
||||
9: BinlogAdmin,
|
||||
10: BinlogEncryptionAdmin,
|
||||
11: CloneAdmin,
|
||||
12: ConnectionAdmin,
|
||||
13: Create,
|
||||
14: CreateRole,
|
||||
15: CreateRoutine,
|
||||
16: CreateTablespace,
|
||||
17: CreateTemporaryTables,
|
||||
18: CreateUser,
|
||||
19: CreateView,
|
||||
20: Delete,
|
||||
21: Drop,
|
||||
22: DropRole,
|
||||
23: EncryptionKeyAdmin,
|
||||
24: Event,
|
||||
25: Execute,
|
||||
26: File,
|
||||
27: FirewallAdmin,
|
||||
28: FirewallExempt,
|
||||
29: FirewallUser,
|
||||
30: FlushOptimizerCosts,
|
||||
31: FlushStatus,
|
||||
32: FlushTables,
|
||||
33: FlushUserResources,
|
||||
34: GrantOption,
|
||||
35: GroupReplicationAdmin,
|
||||
36: GroupReplicationStream,
|
||||
37: Index,
|
||||
38: InnodbRedoLogArchive,
|
||||
39: InnodbRedoLogEnable,
|
||||
40: Insert,
|
||||
41: LockingTables,
|
||||
42: MaskingDictionariesAdmin,
|
||||
43: NdbStoredUser,
|
||||
44: PasswordlessUserAdmin,
|
||||
45: PersistRoVariablesAdmin,
|
||||
46: Process,
|
||||
47: Proxy,
|
||||
48: References,
|
||||
49: Reload,
|
||||
50: ReplicationApplier,
|
||||
51: ReplicationClient,
|
||||
52: ReplicationSlave,
|
||||
53: ReplicationSlaveAdmin,
|
||||
54: ResourceGroupAdmin,
|
||||
55: ResourceGroupUser,
|
||||
56: RoleAdmin,
|
||||
57: Select,
|
||||
58: SensitiveVariablesObserver,
|
||||
59: ServiceConnectionAdmin,
|
||||
60: SessionVariablesAdmin,
|
||||
61: SetAnyDefiner,
|
||||
62: SetUserId,
|
||||
63: ShowDatabases,
|
||||
64: ShowRoutine,
|
||||
65: ShowView,
|
||||
66: Shutdown,
|
||||
67: SkipQueryRewrite,
|
||||
68: Super,
|
||||
69: SystemUser,
|
||||
70: SystemVariablesAdmin,
|
||||
71: TableEncryptionAdmin,
|
||||
72: TelemetryLogAdmin,
|
||||
73: TpConnectionAdmin,
|
||||
74: TransactionGtidTag,
|
||||
75: Trigger,
|
||||
76: Update,
|
||||
77: Usage,
|
||||
78: VersionTokenAdmin,
|
||||
79: XaRecoverAdmin,
|
||||
}
|
||||
)
|
||||
|
||||
// ToString converts a Permission enum to its string representation
|
||||
func (p Permission) ToString() (string, error) {
|
||||
if str, ok := PermissionStrings[p]; ok {
|
||||
return str, nil
|
||||
}
|
||||
return "", errors.New("invalid permission")
|
||||
}
|
||||
|
||||
// ToID converts a Permission enum to its ID
|
||||
func (p Permission) ToID() (int, error) {
|
||||
if id, ok := PermissionIDs[p]; ok {
|
||||
return id, nil
|
||||
}
|
||||
return 0, errors.New("invalid permission")
|
||||
}
|
||||
|
||||
// PermissionFromString converts a string representation to its Permission enum
|
||||
func PermissionFromString(s string) (Permission, error) {
|
||||
if p, ok := StringToPermission[s]; ok {
|
||||
return p, nil
|
||||
}
|
||||
return 0, errors.New("invalid permission string")
|
||||
}
|
||||
|
||||
// PermissionFromID converts an ID to its Permission enum
|
||||
func PermissionFromID(id int) (Permission, error) {
|
||||
if p, ok := IdToPermission[id]; ok {
|
||||
return p, nil
|
||||
}
|
||||
return 0, errors.New("invalid permission ID")
|
||||
}
|
80
pkg/analyzer/analyzers/mysql/permissions.yaml
Normal file
80
pkg/analyzer/analyzers/mysql/permissions.yaml
Normal file
|
@ -0,0 +1,80 @@
|
|||
permissions:
|
||||
- alter
|
||||
- alter_routine
|
||||
- allow_nonexistent_definer
|
||||
- application_password_admin
|
||||
- audit_abort_exempt
|
||||
- audit_admin
|
||||
- authentication_policy_admin
|
||||
- backup_admin
|
||||
- binlog_admin
|
||||
- binlog_encryption_admin
|
||||
- clone_admin
|
||||
- connection_admin
|
||||
- create
|
||||
- create_role
|
||||
- create_routine
|
||||
- create_tablespace
|
||||
- create_temporary_tables
|
||||
- create_user
|
||||
- create_view
|
||||
- delete
|
||||
- drop
|
||||
- drop_role
|
||||
- encryption_key_admin
|
||||
- event
|
||||
- execute
|
||||
- file
|
||||
- firewall_admin
|
||||
- firewall_exempt
|
||||
- firewall_user
|
||||
- flush_optimizer_costs
|
||||
- flush_status
|
||||
- flush_tables
|
||||
- flush_user_resources
|
||||
- grant_option
|
||||
- group_replication_admin
|
||||
- group_replication_stream
|
||||
- index
|
||||
- innodb_redo_log_archive
|
||||
- innodb_redo_log_enable
|
||||
- insert
|
||||
- locking_tables
|
||||
- masking_dictionaries_admin
|
||||
- ndb_stored_user
|
||||
- passwordless_user_admin
|
||||
- persist_ro_variables_admin
|
||||
- process
|
||||
- proxy
|
||||
- references
|
||||
- reload
|
||||
- replication_applier
|
||||
- replication_client
|
||||
- replication_slave
|
||||
- replication_slave_admin
|
||||
- resource_group_admin
|
||||
- resource_group_user
|
||||
- role_admin
|
||||
- select
|
||||
- sensitive_variables_observer
|
||||
- service_connection_admin
|
||||
- session_variables_admin
|
||||
- set_any_definer
|
||||
- set_user_id
|
||||
- show_databases
|
||||
- show_routine
|
||||
- show_view
|
||||
- shutdown
|
||||
- skip_query_rewrite
|
||||
- super
|
||||
- system_user
|
||||
- system_variables_admin
|
||||
- table_encryption_admin
|
||||
- telemetry_log_admin
|
||||
- tp_connection_admin
|
||||
- transaction_gtid_tag
|
||||
- trigger
|
||||
- update
|
||||
- usage
|
||||
- version_token_admin
|
||||
- xa_recover_admin
|
|
@ -97,6 +97,9 @@ matchLoop:
|
|||
err = pingRes.err
|
||||
s.SetVerificationError(err, jdbcConn)
|
||||
}
|
||||
s.AnalysisInfo = map[string]string{
|
||||
"connection_string": jdbcConn,
|
||||
}
|
||||
// TODO: specialized redaction
|
||||
}
|
||||
|
||||
|
|
|
@ -134,6 +134,7 @@ func TestJdbc_FromChunk(t *testing.T) {
|
|||
t.Fatal("no raw secret present")
|
||||
}
|
||||
got[i].Raw = nil
|
||||
got[i].AnalysisInfo = nil
|
||||
}
|
||||
if diff := pretty.Compare(got, tt.want); diff != "" {
|
||||
t.Errorf("Jdbc.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
|
||||
|
|
Loading…
Reference in a new issue