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 }