github.com/dolthub/go-mysql-server@v0.18.0/sql/privileges.go (about)

     1  // Copyright 2022-2023 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package sql
    16  
    17  // PrivilegedOperation represents an operation that requires privileges to execute.
    18  type PrivilegedOperation struct {
    19  	Database          string
    20  	Table             string
    21  	Column            string
    22  	Routine           string
    23  	IsProcedure       bool // true if the routine is a procedure, false if it's a function
    24  	StaticPrivileges  []PrivilegeType
    25  	DynamicPrivileges []string
    26  }
    27  
    28  // PrivilegeCheckSubject is a struct that contains the entity information for an access check. It's specifically what
    29  // is being accessed - but not what operation is being attempted.
    30  type PrivilegeCheckSubject struct {
    31  	Database    string
    32  	Table       string
    33  	Column      string
    34  	Routine     string
    35  	IsProcedure bool // true if the routine is a procedure, false if it's a function
    36  }
    37  
    38  // NewPrivilegedOperation returns a new PrivilegedOperation with the given parameters.
    39  func NewPrivilegedOperation(subject PrivilegeCheckSubject, privs ...PrivilegeType) PrivilegedOperation {
    40  	return PrivilegedOperation{
    41  		Database:         subject.Database,
    42  		Table:            subject.Table,
    43  		Column:           subject.Column,
    44  		Routine:          subject.Routine,
    45  		IsProcedure:      subject.IsProcedure,
    46  		StaticPrivileges: privs,
    47  	}
    48  }
    49  
    50  // NewDynamicPrivilegedOperation returns a new PrivilegedOperation for the specified dynamic privileges. Dynamic
    51  // privileges may only be applied globally, so you cannot specify a database, table, or column.
    52  func NewDynamicPrivilegedOperation(privs ...string) PrivilegedOperation {
    53  	return PrivilegedOperation{
    54  		DynamicPrivileges: privs,
    55  	}
    56  }
    57  
    58  // PrivilegedOperationChecker contains the necessary data to check whether the operation should succeed based on the
    59  // privileges contained by the user. The user is retrieved from the context, along with their active roles.
    60  type PrivilegedOperationChecker interface {
    61  	// UserHasPrivileges fetches the User, and returns whether they have the desired privileges necessary to perform the
    62  	// privileged operation(s). This takes into account the active roles, which are set in the context, therefore both
    63  	// the user and the active roles are pulled from the context. This method is sufficient for all MySQL behaviors.
    64  	// The one exception, currently, is for stored procedures and functions, which have a more fine-grained permission
    65  	// due to Dolt's use of the AdminOnly flag in procedure definitions.
    66  	UserHasPrivileges(ctx *Context, operations ...PrivilegedOperation) bool
    67  	// RoutineAdminCheck fetches the User from the context, and specifically evaluates, the permission check
    68  	// assuming the operation is for a stored procedure or function. This allows us to have more fine grain control over
    69  	// permissions for stored procedures (many of which are critical to Dolt). This method specifically checks exists
    70  	// for the use of AdminOnly procedures which require more fine-grained access control. For procedures which are
    71  	// not AdminOnly, then |UserHasPrivileges| should be used instead.
    72  	RoutineAdminCheck(ctx *Context, operations ...PrivilegedOperation) bool
    73  }
    74  
    75  // PrivilegeSet is a set containing privileges. Integrators should not implement this interface.
    76  type PrivilegeSet interface {
    77  	// Has returns whether the given global privilege(s) exists.
    78  	Has(privileges ...PrivilegeType) bool
    79  	// HasPrivileges returns whether this PrivilegeSet has any privileges at any level.
    80  	HasPrivileges() bool
    81  	// Count returns the number of global privileges.
    82  	Count() int
    83  	// Database returns the set of privileges for the given database. Returns an empty set if the database does not exist.
    84  	Database(dbName string) PrivilegeSetDatabase
    85  	// GetDatabases returns all databases.
    86  	GetDatabases() []PrivilegeSetDatabase
    87  	// Equals returns whether the given set of privileges is equivalent to the calling set.
    88  	Equals(otherPs PrivilegeSet) bool
    89  	// ToSlice returns all of the global privileges contained as a sorted slice.
    90  	ToSlice() []PrivilegeType
    91  }
    92  
    93  // PrivilegeSetDatabase is a set containing database-level privileges. Integrators should not implement this interface.
    94  type PrivilegeSetDatabase interface {
    95  	// Name returns the name of the database that this privilege set belongs to.
    96  	Name() string
    97  	// Has returns whether the given database privilege(s) exists.
    98  	Has(privileges ...PrivilegeType) bool
    99  	// HasPrivileges returns whether this database has either database-level privileges, or privileges on a table or
   100  	// column contained within this database.
   101  	HasPrivileges() bool
   102  	// Count returns the number of database privileges.
   103  	Count() int
   104  	// Table returns the set of privileges for the given table. Returns an empty set if the table does not exist.
   105  	Table(tblName string) PrivilegeSetTable
   106  	// GetTables returns all tables.
   107  	GetTables() []PrivilegeSetTable
   108  	// Routine returns the set of privileges for the given routine. Returns an empty set if the routine does not exist.
   109  	Routine(routineName string, isProcedure bool) PrivilegeSetRoutine
   110  	// GetRoutines returns all routines.
   111  	GetRoutines() []PrivilegeSetRoutine
   112  	// Equals returns whether the given set of privileges is equivalent to the calling set.
   113  	Equals(otherPs PrivilegeSetDatabase) bool
   114  	// ToSlice returns all of the database privileges contained as a sorted slice.
   115  	ToSlice() []PrivilegeType
   116  }
   117  
   118  // AliasedDatabase is a database that has an alias: a name that is different from the name to be used system
   119  // tables such as information_schema, or the mysql grant tables. This is the case when an integrator supports multiple
   120  // ways to address a single physical database, but all such names should resolve to the same underlying name for
   121  // permission checks.
   122  type AliasedDatabase interface {
   123  	Database
   124  
   125  	// AliasedName returns the alias (the underlying name for information_schema, privileges) for this database.
   126  	AliasedName() string
   127  }
   128  
   129  // PrivilegeSetTable is a set containing table-level privileges. Integrators should not implement this interface.
   130  type PrivilegeSetTable interface {
   131  	// Name returns the name of the table that this privilege set belongs to.
   132  	Name() string
   133  	// Has returns whether the given table privilege(s) exists.
   134  	Has(privileges ...PrivilegeType) bool
   135  	// HasPrivileges returns whether this table has either table-level privileges, or privileges on a column contained
   136  	// within this table.
   137  	HasPrivileges() bool
   138  	// Count returns the number of table privileges.
   139  	Count() int
   140  	// Column returns the set of privileges for the given column. Returns an empty set if the column does not exist.
   141  	Column(colName string) PrivilegeSetColumn
   142  	// GetColumns returns all columns.
   143  	GetColumns() []PrivilegeSetColumn
   144  	// Equals returns whether the given set of privileges is equivalent to the calling set.
   145  	Equals(otherPs PrivilegeSetTable) bool
   146  	// ToSlice returns all of the table privileges contained as a sorted slice.
   147  	ToSlice() []PrivilegeType
   148  }
   149  
   150  // PrivilegeSetColumn is a set containing column privileges. Integrators should not implement this interface.
   151  type PrivilegeSetColumn interface {
   152  	// Name returns the name of the column that this privilege set belongs to.
   153  	Name() string
   154  	// Has returns whether the given column privilege(s) exists.
   155  	Has(privileges ...PrivilegeType) bool
   156  	// Count returns the number of column privileges.
   157  	Count() int
   158  	// Equals returns whether the given set of privileges is equivalent to the calling set.
   159  	Equals(otherPs PrivilegeSetColumn) bool
   160  	// ToSlice returns all of the column privileges contained as a sorted slice.
   161  	ToSlice() []PrivilegeType
   162  }
   163  
   164  // PrivilegeSetRoutine is a set containing routine privileges. Routines are either functions or procedures, and permissions
   165  // for them are handled identically.
   166  type PrivilegeSetRoutine interface {
   167  	// RoutineName returns the name of the routine that this privilege set belongs to.
   168  	RoutineName() string
   169  	// RoutineType returns "FUNCTION" or "PROCEDURE".
   170  	RoutineType() string
   171  	// Has returns true if all PrivilegeTypes are present in the PrivilegeSet.
   172  	Has(privileges ...PrivilegeType) bool
   173  	// HasPrivileges returns whether this routine has any privileges.
   174  	HasPrivileges() bool
   175  	// Count returns the number of privileges on the routine
   176  	Count() int
   177  	// Equals returns whether the given set of privileges is equivalent to the calling set.
   178  	Equals(otherPs PrivilegeSetRoutine) bool
   179  	// ToSlice returns all of the routines privileges as a sorted slice.
   180  	ToSlice() []PrivilegeType
   181  }
   182  
   183  // PrivilegeType represents a privilege.
   184  type PrivilegeType int
   185  
   186  const (
   187  	PrivilegeType_Select PrivilegeType = iota
   188  	PrivilegeType_Insert
   189  	PrivilegeType_Update
   190  	PrivilegeType_Delete
   191  	PrivilegeType_Create
   192  	PrivilegeType_Drop
   193  	PrivilegeType_Reload
   194  	PrivilegeType_Shutdown
   195  	PrivilegeType_Process
   196  	PrivilegeType_File
   197  	PrivilegeType_GrantOption
   198  	PrivilegeType_References
   199  	PrivilegeType_Index
   200  	PrivilegeType_Alter
   201  	PrivilegeType_ShowDB
   202  	PrivilegeType_Super
   203  	PrivilegeType_CreateTempTable
   204  	PrivilegeType_LockTables
   205  	PrivilegeType_Execute
   206  	PrivilegeType_ReplicationSlave
   207  	PrivilegeType_ReplicationClient
   208  	PrivilegeType_CreateView
   209  	PrivilegeType_ShowView
   210  	PrivilegeType_CreateRoutine
   211  	PrivilegeType_AlterRoutine
   212  	PrivilegeType_CreateUser
   213  	PrivilegeType_Event
   214  	PrivilegeType_Trigger
   215  	PrivilegeType_CreateTablespace
   216  	PrivilegeType_CreateRole
   217  	PrivilegeType_DropRole
   218  )
   219  
   220  // privilegeTypeStrings are in the same order as the enumerations above, so that it's a simple index access.
   221  var privilegeTypeStrings = []string{
   222  	"SELECT",
   223  	"INSERT",
   224  	"UPDATE",
   225  	"DELETE",
   226  	"CREATE",
   227  	"DROP",
   228  	"RELOAD",
   229  	"SHUTDOWN",
   230  	"PROCESS",
   231  	"FILE",
   232  	"GRANT OPTION",
   233  	"REFERENCES",
   234  	"INDEX",
   235  	"ALTER",
   236  	"SHOW DATABASES",
   237  	"SUPER",
   238  	"CREATE TEMPORARY TABLES",
   239  	"LOCK TABLES",
   240  	"EXECUTE",
   241  	"REPLICATION SLAVE",
   242  	"REPLICATION CLIENT",
   243  	"CREATE VIEW",
   244  	"SHOW VIEW",
   245  	"CREATE ROUTINE",
   246  	"ALTER ROUTINE",
   247  	"CREATE USER",
   248  	"EVENT",
   249  	"TRIGGER",
   250  	"CREATE TABLESPACE",
   251  	"CREATE ROLE",
   252  	"DROP ROLE",
   253  }
   254  
   255  // String returns the sql.PrivilegeType as a string, for display in places such as "SHOW GRANTS".
   256  func (pt PrivilegeType) String() string {
   257  	return privilegeTypeStrings[pt]
   258  }
   259  
   260  // privilegeTypeStringMap map each string (same ones in privilegeTypeStrings) to their appropriate PrivilegeType.
   261  var privilegeTypeStringMap = map[string]PrivilegeType{
   262  	"SELECT":                  PrivilegeType_Select,
   263  	"INSERT":                  PrivilegeType_Insert,
   264  	"UPDATE":                  PrivilegeType_Update,
   265  	"DELETE":                  PrivilegeType_Delete,
   266  	"CREATE":                  PrivilegeType_Create,
   267  	"DROP":                    PrivilegeType_Drop,
   268  	"RELOAD":                  PrivilegeType_Reload,
   269  	"SHUTDOWN":                PrivilegeType_Shutdown,
   270  	"PROCESS":                 PrivilegeType_Process,
   271  	"FILE":                    PrivilegeType_File,
   272  	"GRANT OPTION":            PrivilegeType_GrantOption,
   273  	"REFERENCES":              PrivilegeType_References,
   274  	"INDEX":                   PrivilegeType_Index,
   275  	"ALTER":                   PrivilegeType_Alter,
   276  	"SHOW DATABASES":          PrivilegeType_ShowDB,
   277  	"SUPER":                   PrivilegeType_Super,
   278  	"CREATE TEMPORARY TABLES": PrivilegeType_CreateTempTable,
   279  	"LOCK TABLES":             PrivilegeType_LockTables,
   280  	"EXECUTE":                 PrivilegeType_Execute,
   281  	"REPLICATION SLAVE":       PrivilegeType_ReplicationSlave,
   282  	"REPLICATION CLIENT":      PrivilegeType_ReplicationClient,
   283  	"CREATE VIEW":             PrivilegeType_CreateView,
   284  	"SHOW VIEW":               PrivilegeType_ShowView,
   285  	"CREATE ROUTINE":          PrivilegeType_CreateRoutine,
   286  	"ALTER ROUTINE":           PrivilegeType_AlterRoutine,
   287  	"CREATE USER":             PrivilegeType_CreateUser,
   288  	"EVENT":                   PrivilegeType_Event,
   289  	"TRIGGER":                 PrivilegeType_Trigger,
   290  	"CREATE TABLESPACE":       PrivilegeType_CreateTablespace,
   291  	"CREATE ROLE":             PrivilegeType_CreateRole,
   292  	"DROP ROLE":               PrivilegeType_DropRole,
   293  }
   294  
   295  // PrivilegeTypeFromString returns the matching PrivilegeType for the given string. If there is no match, returns false.
   296  func PrivilegeTypeFromString(privilegeType string) (PrivilegeType, bool) {
   297  	match, ok := privilegeTypeStringMap[privilegeType]
   298  	return match, ok
   299  }