Skip to content

Commit

Permalink
Fix finding grant conflicts for EXECUTE grants (#171)
Browse files Browse the repository at this point in the history
We forgot about one case - this was changed so it works in such cases.

Tests will come later.
  • Loading branch information
petoju authored Aug 30, 2024
1 parent a5eaadd commit e4c6424
Showing 1 changed file with 31 additions and 32 deletions.
63 changes: 31 additions & 32 deletions mysql/resource_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type MySQLGrant interface {
SQLRevokeStatement() string
GetUserOrRole() UserOrRole
GrantOption() bool

ConflictsWithGrant(otherGrant MySQLGrant) bool
}

type MySQLGrantWithDatabase interface {
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit e4c6424

Please sign in to comment.