github.com/matrixorigin/matrixone@v1.2.0/pkg/frontend/authenticate2.go (about)

     1  // Copyright 2021 Matrix Origin
     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 frontend
    16  
    17  import (
    18  	"context"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    21  	plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan"
    22  )
    23  
    24  // verifyAccountCanOperateClusterTable determines the account can operate
    25  // the cluster table
    26  func verifyAccountCanOperateClusterTable(account *TenantInfo,
    27  	dbName string,
    28  	clusterTableOperation clusterTableOperationType) bool {
    29  	if account.IsSysTenant() {
    30  		//sys account can do anything on the cluster table.
    31  		if dbName == moCatalog {
    32  			return true
    33  		}
    34  	} else {
    35  		//the general account can only read the cluster table
    36  		if dbName == moCatalog {
    37  			switch clusterTableOperation {
    38  			case clusterTableNone, clusterTableSelect:
    39  				return true
    40  			}
    41  		}
    42  	}
    43  	return false
    44  }
    45  
    46  // verifyLightPrivilege checks the privilege that does not need to
    47  // access the privilege tables.
    48  // case1 : checks if a real user from client is modifying the catalog databases (mo_catalog,information_schema,system,
    49  // system_metric,mysql).
    50  // case2 : checks if the user operates the cluster table.
    51  func verifyLightPrivilege(ses *Session,
    52  	dbName string,
    53  	writeDBTableDirect bool,
    54  	isClusterTable bool,
    55  	clusterTableOperation clusterTableOperationType) bool {
    56  	var ok bool
    57  	if ses.GetFromRealUser() && writeDBTableDirect {
    58  		if len(dbName) == 0 {
    59  			dbName = ses.GetDatabaseName()
    60  		}
    61  		if ok2 := isBannedDatabase(dbName); ok2 {
    62  			if isClusterTable {
    63  				ok = verifyAccountCanOperateClusterTable(ses.GetTenantInfo(), dbName, clusterTableOperation)
    64  			} else {
    65  				ok = false
    66  			}
    67  		} else {
    68  			ok = !isClusterTable
    69  		}
    70  	} else {
    71  		ok = true
    72  	}
    73  	return ok
    74  }
    75  
    76  // getDefaultAccount returns the internal account
    77  func getDefaultAccount() *TenantInfo {
    78  	return &TenantInfo{
    79  		Tenant:        sysAccountName,
    80  		User:          rootName,
    81  		DefaultRole:   moAdminRoleName,
    82  		TenantID:      sysAccountID,
    83  		UserID:        rootID,
    84  		DefaultRoleID: moAdminRoleID,
    85  		delimiter:     ':',
    86  	}
    87  }
    88  
    89  // verifyPrivilegeEntryInMultiPrivilegeLevelsInCache checks privilege entry
    90  // in the cache only.
    91  func verifyPrivilegeEntryInMultiPrivilegeLevelsInCache(
    92  	ses *Session,
    93  	cache *privilegeCache,
    94  	entry privilegeEntry,
    95  	pls []privilegeLevelType) (bool, error) {
    96  	var yes bool
    97  	dbName := entry.databaseName
    98  	if len(dbName) == 0 {
    99  		dbName = ses.GetDatabaseName()
   100  	}
   101  	if cache != nil {
   102  		for _, pl := range pls {
   103  			yes = cache.has(entry.objType, pl, dbName, entry.tableName, entry.privilegeId)
   104  			if yes {
   105  				return true, nil
   106  			}
   107  		}
   108  	}
   109  	return false, nil
   110  }
   111  
   112  // checkPrivilegeInCache checks the privilege in the cache first.
   113  func checkPrivilegeInCache(ctx context.Context, ses *Session, priv *privilege, enableCache bool) (bool, error) {
   114  	var err error
   115  	var pls []privilegeLevelType
   116  	var yes2, yes bool
   117  	cache := ses.GetPrivilegeCache()
   118  	if cache != nil && enableCache {
   119  		for _, entry := range priv.entries {
   120  			if entry.privilegeEntryTyp == privilegeEntryTypeGeneral {
   121  				pls, err = getPrivilegeLevelsOfObjectType(ctx, entry.objType)
   122  				if err != nil {
   123  					return false, err
   124  				}
   125  
   126  				yes2 = verifyLightPrivilege(ses,
   127  					entry.databaseName,
   128  					priv.writeDatabaseAndTableDirectly,
   129  					priv.isClusterTable,
   130  					priv.clusterTableOperation)
   131  
   132  				if yes2 {
   133  					yes, err = verifyPrivilegeEntryInMultiPrivilegeLevelsInCache(ses, cache, entry, pls)
   134  					if err != nil {
   135  						return false, err
   136  					}
   137  				}
   138  
   139  				if yes {
   140  					return true, nil
   141  				}
   142  			} else if entry.privilegeEntryTyp == privilegeEntryTypeCompound {
   143  				if entry.compound != nil {
   144  					allTrue := true
   145  					//multi privileges take effect together
   146  					for _, mi := range entry.compound.items {
   147  						if mi.privilegeTyp == PrivilegeTypeCanGrantRoleToOthersInCreateUser {
   148  							//TODO: normalize the name
   149  							//TODO: simplify the logic
   150  							//yes, err = determineUserCanGrantRolesToOthersInternal(ctx, bh, ses, []*tree.Role{mi.role})
   151  							//if err != nil {
   152  							//	return false, err
   153  							//}
   154  							//if yes {
   155  							//	from := &verifiedRole{
   156  							//		typ:  roleType,
   157  							//		name: mi.role.UserName,
   158  							//	}
   159  							//	for _, user := range mi.users {
   160  							//		to := &verifiedRole{
   161  							//			typ:  userType,
   162  							//			name: user.Username,
   163  							//		}
   164  							//		err = verifySpecialRolesInGrant(ctx, ses.GetTenantInfo(), from, to)
   165  							//		if err != nil {
   166  							//			return false, err
   167  							//		}
   168  							//	}
   169  							//}
   170  						} else {
   171  							tempEntry := privilegeEntriesMap[mi.privilegeTyp]
   172  							tempEntry.databaseName = mi.dbName
   173  							tempEntry.tableName = mi.tableName
   174  							tempEntry.privilegeEntryTyp = privilegeEntryTypeGeneral
   175  							tempEntry.compound = nil
   176  							pls, err = getPrivilegeLevelsOfObjectType(ctx, tempEntry.objType)
   177  							if err != nil {
   178  								return false, err
   179  							}
   180  
   181  							yes2 = verifyLightPrivilege(ses,
   182  								tempEntry.databaseName,
   183  								priv.writeDatabaseAndTableDirectly,
   184  								mi.isClusterTable,
   185  								mi.clusterTableOperation)
   186  
   187  							if yes2 {
   188  								//At least there is one success
   189  								yes, err = verifyPrivilegeEntryInMultiPrivilegeLevelsInCache(ses, cache, tempEntry, pls)
   190  								if err != nil {
   191  									return false, err
   192  								}
   193  							}
   194  						}
   195  						if !yes {
   196  							allTrue = false
   197  							break
   198  						}
   199  					}
   200  
   201  					if allTrue {
   202  						return allTrue, nil
   203  					}
   204  				}
   205  			}
   206  		}
   207  	}
   208  	return false, nil
   209  }
   210  
   211  // privilegeCacheIsEnabled checks if the privilege cache is enabled.
   212  func privilegeCacheIsEnabled(ctx context.Context, ses *Session) (bool, error) {
   213  	var err error
   214  	var value interface{}
   215  	var newValue bool
   216  	value, err = ses.GetSessionVar(ctx, "enable_privilege_cache")
   217  	if err != nil {
   218  		return false, err
   219  	}
   220  
   221  	newValue, err = valueIsBoolTrue(value)
   222  	if err != nil {
   223  		return false, err
   224  	}
   225  
   226  	return newValue, err
   227  }
   228  
   229  // hasMoCtrl checks whether the plan has mo_ctrl
   230  func hasMoCtrl(p *plan2.Plan) bool {
   231  	if p != nil && p.GetQuery() != nil { //select,insert select, update, delete
   232  		q := p.GetQuery()
   233  		if q.StmtType == plan.Query_INSERT || q.StmtType == plan.Query_SELECT {
   234  			for _, node := range q.Nodes {
   235  				if node != nil && node.NodeType == plan.Node_PROJECT {
   236  					//restrict :
   237  					//	select mo_ctrl ...
   238  					//	insert into ... select mo_ctrl ...
   239  					for _, proj := range node.ProjectList {
   240  						if plan2.HasMoCtrl(proj) {
   241  							return true
   242  						}
   243  					}
   244  				}
   245  			}
   246  		}
   247  	}
   248  	return false
   249  }
   250  
   251  // verifyAccountCanExecMoCtrl only sys account and moadmin role.
   252  func verifyAccountCanExecMoCtrl(account *TenantInfo) bool {
   253  	return account.IsSysTenant() && account.IsMoAdminRole()
   254  }