From e4c6424d0914fac4ab899be5c6396b44b714769b Mon Sep 17 00:00:00 2001 From: petoju Date: Fri, 30 Aug 2024 20:05:51 +0200 Subject: [PATCH] Fix finding grant conflicts for EXECUTE grants (#171) We forgot about one case - this was changed so it works in such cases. Tests will come later. --- mysql/resource_grant.go | 63 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/mysql/resource_grant.go b/mysql/resource_grant.go index 98466b24..9ff12c5d 100644 --- a/mysql/resource_grant.go +++ b/mysql/resource_grant.go @@ -33,6 +33,8 @@ type MySQLGrant interface { SQLRevokeStatement() string GetUserOrRole() UserOrRole GrantOption() bool + + ConflictsWithGrant(otherGrant MySQLGrant) bool } type MySQLGrantWithDatabase interface { @@ -57,35 +59,6 @@ type MySQLGrantWithRoles interface { AppendRoles([]string) } -func grantsConflict(grantA MySQLGrant, grantB MySQLGrant) bool { - if reflect.TypeOf(grantA) != reflect.TypeOf(grantB) { - return false - } - grantAWithDatabase, aOk := grantA.(MySQLGrantWithDatabase) - grantBWithDatabase, bOk := grantB.(MySQLGrantWithDatabase) - if aOk != bOk { - return false - } - if aOk && bOk { - if grantAWithDatabase.GetDatabase() != grantBWithDatabase.GetDatabase() { - return false - } - } - - grantAWithTable, aOk := grantA.(MySQLGrantWithTable) - grantBWithTable, bOk := grantB.(MySQLGrantWithTable) - if aOk != bOk { - return false - } - if aOk && bOk { - if grantAWithTable.GetTable() != grantBWithTable.GetTable() { - return false - } - } - - return true -} - type PrivilegesPartiallyRevocable interface { SQLPartialRevokePrivilegesStatement(privilegesToRevoke []string) string } @@ -175,6 +148,15 @@ func (t *TablePrivilegeGrant) SQLGrantStatement() string { return stmtSql } +func (t *TablePrivilegeGrant) ConflictsWithGrant(other MySQLGrant) bool { + otherTyped, ok := other.(*TablePrivilegeGrant) + if !ok { + return false + } + return otherTyped.GetDatabase() == t.GetDatabase() && + otherTyped.GetTable() == t.GetTable() +} + // containsAllPrivilege returns true if the privileges list contains an ALL PRIVILEGES grant // this is used because there is special case behavior for ALL PRIVILEGES grants. In particular, // if a user has ALL PRIVILEGES, we _cannot_ revoke ALL PRIVILEGES, GRANT OPTION because this is @@ -273,6 +255,15 @@ func (t *ProcedurePrivilegeGrant) SQLPartialRevokePrivilegesStatement(privileges return fmt.Sprintf("REVOKE %s ON %s %s.%s FROM %s", strings.Join(privs, ", "), t.ObjectT, t.GetDatabase(), t.GetCallableName(), t.UserOrRole.SQLString()) } +func (t *ProcedurePrivilegeGrant) ConflictsWithGrant(other MySQLGrant) bool { + otherTyped, ok := other.(*ProcedurePrivilegeGrant) + if !ok { + return false + } + return otherTyped.GetDatabase() == t.GetDatabase() && + otherTyped.GetCallableName() == t.GetCallableName() +} + type RoleGrant struct { Roles []string Grant bool @@ -315,6 +306,14 @@ func (t *RoleGrant) AppendRoles(roles []string) { t.Roles = append(t.Roles, roles...) } +func (t *RoleGrant) ConflictsWithGrant(other MySQLGrant) bool { + otherTyped, ok := other.(*RoleGrant) + if !ok { + return false + } + return otherTyped.GetUserOrRole() == t.GetUserOrRole() +} + func resourceGrant() *schema.Resource { return &schema.Resource{ CreateContext: CreateGrant, @@ -698,7 +697,7 @@ func ImportGrant(ctx context.Context, d *schema.ResourceData, meta interface{}) return nil, fmt.Errorf("failed to showUserGrants in import: %w", err) } for _, foundGrant := range grants { - if grantsConflict(desiredGrant, foundGrant) { + if foundGrant.ConflictsWithGrant(desiredGrant) { res := resourceGrant().Data(nil) setDataFromGrant(foundGrant, res) return []*schema.ResourceData{res}, nil @@ -769,7 +768,7 @@ func setDataFromGrant(grant MySQLGrant, d *schema.ResourceData) *schema.Resource func combineGrants(grantA MySQLGrant, grantB MySQLGrant) (MySQLGrant, error) { // Check if the grants cover the same user, table, database // If not, throw an error because they are unmergeable - if !grantsConflict(grantA, grantB) { + if !grantA.ConflictsWithGrant(grantB) { return nil, fmt.Errorf("unable to combine MySQLGrant %s with %s because they don't cover the same table/database/user", grantA, grantB) } @@ -802,7 +801,7 @@ func getMatchingGrant(ctx context.Context, db *sql.DB, desiredGrant MySQLGrant) // Check if the grants cover the same user, table, database // If not, continue - if !grantsConflict(desiredGrant, dbGrant) { + if !desiredGrant.ConflictsWithGrant(dbGrant) { log.Printf("[DEBUG] Skipping grant %#v as it doesn't match %#v", dbGrant, desiredGrant) continue }