From commits-return-8710-archive-asf-public=cust-asf.ponee.io@trafodion.apache.org Wed Oct 24 18:20:53 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id DE16F18067B for ; Wed, 24 Oct 2018 18:20:51 +0200 (CEST) Received: (qmail 56607 invoked by uid 500); 24 Oct 2018 16:20:51 -0000 Mailing-List: contact commits-help@trafodion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: commits@trafodion.apache.org Delivered-To: mailing list commits@trafodion.apache.org Received: (qmail 56591 invoked by uid 99); 24 Oct 2018 16:20:51 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 24 Oct 2018 16:20:50 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 66A73E0E1D; Wed, 24 Oct 2018 16:20:50 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: rmarton@apache.org To: commits@trafodion.apache.org Date: Wed, 24 Oct 2018 16:20:51 -0000 Message-Id: <260ac956a7ff463ea848861855b53b77@git.apache.org> In-Reply-To: <5c90643fb2ad4684979cad4f1d72222d@git.apache.org> References: <5c90643fb2ad4684979cad4f1d72222d@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/3] trafodion git commit: TRAFODION - 3218 User still has privilege after user's role has been revoked ... TRAFODION - 3218 User still has privilege after user's role has been revoked ... Partial support for column level privileges with QI support for: column select column insert column references column update Also, as part of this, updated privilege code in a couple of areas: Changed object caching code in NATable and NARoutine to store all privileges assigned to the object when the object is cached (privDescs_). During the load operation, the code creates bitmaps (privInfo_) for the current user. Privilege checks are performed against the user bitmaps (privInfo_). This is in anticipation for some performance updates when connecting to Trafodion (mxosrvr) with different users. Change getRoleList to include the roleID and the granteeID that granted the privilege. The grantee can be a user or a role. When a privilege is revoked from a role, send QI keys for every user that has been granted to role. Project: http://git-wip-us.apache.org/repos/asf/trafodion/repo Commit: http://git-wip-us.apache.org/repos/asf/trafodion/commit/adf2b8f2 Tree: http://git-wip-us.apache.org/repos/asf/trafodion/tree/adf2b8f2 Diff: http://git-wip-us.apache.org/repos/asf/trafodion/diff/adf2b8f2 Branch: refs/heads/master Commit: adf2b8f23d87bd3bdcccf64523b730a4c9b57843 Parents: c52b07c Author: Roberta Marton Authored: Wed Oct 3 17:54:39 2018 +0000 Committer: Roberta Marton Committed: Wed Oct 3 17:54:39 2018 +0000 ---------------------------------------------------------------------- core/sql/cli/Cli.cpp | 7 +- core/sql/cli/Cli.h | 7 +- core/sql/cli/CliExtern.cpp | 10 +- core/sql/cli/Context.cpp | 63 ++++-- core/sql/cli/Context.h | 8 +- core/sql/cli/SQLCLIdev.h | 5 +- core/sql/comexe/ComTdb.h | 2 +- core/sql/common/ComDistribution.cpp | 4 + core/sql/common/ComSecurityKey.cpp | 125 +++++++---- core/sql/common/ComSecurityKey.h | 16 +- core/sql/common/ComSmallDefs.h | 9 + core/sql/common/ComUser.cpp | 62 ++++- core/sql/common/ComUser.h | 5 +- core/sql/executor/ExExeUtilGet.cpp | 7 +- core/sql/generator/Generator.cpp | 15 +- core/sql/optimizer/BindRelExpr.cpp | 144 ++++++++---- core/sql/optimizer/NARoutine.cpp | 96 ++++---- core/sql/optimizer/NARoutine.h | 11 +- core/sql/optimizer/NATable.cpp | 104 ++++++--- core/sql/optimizer/NATable.h | 21 +- core/sql/optimizer/RelMisc.h | 3 +- core/sql/regress/privs1/EXPECTED120 | 15 +- core/sql/regress/privs1/TEST120 | 2 +- core/sql/regress/privs2/EXPECTED129 | 218 +++++++++++++----- core/sql/regress/privs2/TEST129 | 32 ++- core/sql/sqlcomp/CmpSeabaseDDLauth.cpp | 40 +++- core/sql/sqlcomp/CmpSeabaseDDLauth.h | 3 +- core/sql/sqlcomp/CmpSeabaseDDLtable.cpp | 15 +- core/sql/sqlcomp/PrivMgr.cpp | 37 +++ core/sql/sqlcomp/PrivMgr.h | 5 + core/sql/sqlcomp/PrivMgrCommands.cpp | 124 +++++----- core/sql/sqlcomp/PrivMgrCommands.h | 15 +- core/sql/sqlcomp/PrivMgrComponentPrivileges.cpp | 12 +- core/sql/sqlcomp/PrivMgrDesc.cpp | 1 + core/sql/sqlcomp/PrivMgrDesc.h | 30 +++ core/sql/sqlcomp/PrivMgrPrivileges.cpp | 224 ++++++------------- core/sql/sqlcomp/PrivMgrPrivileges.h | 21 +- core/sql/sqlcomp/PrivMgrRoles.cpp | 92 ++++---- core/sql/sqlcomp/PrivMgrRoles.h | 18 +- core/sql/sqlcomp/PrivMgrUserPrivs.cpp | 174 ++++++++------ core/sql/sqlcomp/PrivMgrUserPrivs.h | 15 +- 41 files changed, 1128 insertions(+), 689 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/Cli.cpp ---------------------------------------------------------------------- diff --git a/core/sql/cli/Cli.cpp b/core/sql/cli/Cli.cpp index 3d5f033..9318fa5 100644 --- a/core/sql/cli/Cli.cpp +++ b/core/sql/cli/Cli.cpp @@ -6240,8 +6240,9 @@ Int32 SQLCLI_GetAuthState ( Lng32 SQLCLI_GetRoleList( CliGlobals * cliGlobals, - Int32 &numRoles, - Int32 *&roleIDs) + Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs) { Lng32 retcode = 0; @@ -6254,7 +6255,7 @@ Lng32 SQLCLI_GetRoleList( ContextCli &currContext = *(cliGlobals->currContext()); ComDiagsArea &diags = currContext.diags(); - retcode = currContext.getRoleList(numRoles,roleIDs); + retcode = currContext.getRoleList(numEntries,roleIDs,granteeIDs); return CliEpilogue(cliGlobals, NULL, retcode); http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/Cli.h ---------------------------------------------------------------------- diff --git a/core/sql/cli/Cli.h b/core/sql/cli/Cli.h index a8a6b9a..c5aa690 100644 --- a/core/sql/cli/Cli.h +++ b/core/sql/cli/Cli.h @@ -536,9 +536,10 @@ Int32 SQLCLI_GetAuthState ( Lng32 SQLCLI_GetRoleList( CliGlobals *cliGlobals, - Int32 &numRoles, - Int32 *&roleIDs); - + Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs); + Lng32 SQLCLI_ResetRoleList ( /*IN*/ CliGlobals *cliGlobals); http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/CliExtern.cpp ---------------------------------------------------------------------- diff --git a/core/sql/cli/CliExtern.cpp b/core/sql/cli/CliExtern.cpp index 69e4717..7091d14 100644 --- a/core/sql/cli/CliExtern.cpp +++ b/core/sql/cli/CliExtern.cpp @@ -4346,8 +4346,9 @@ Lng32 SQL_EXEC_SetSessionAttr_Internal( Lng32 SQL_EXEC_GetRoleList( - Int32 &numRoles, - Int32 *&roleIDs) + Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs) { @@ -4363,8 +4364,9 @@ Lng32 SQL_EXEC_GetRoleList( threadContext->incrNumOfCliCalls(); retcode = SQLCLI_GetRoleList(GetCliGlobals(), - numRoles, - roleIDs); + numEntries, + roleIDs, + granteeIDs); } catch(...) { http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/Context.cpp ---------------------------------------------------------------------- diff --git a/core/sql/cli/Context.cpp b/core/sql/cli/Context.cpp index 46310d9..fc66151 100644 --- a/core/sql/cli/Context.cpp +++ b/core/sql/cli/Context.cpp @@ -173,6 +173,7 @@ ContextCli::ContextCli(CliGlobals *cliGlobals) arkcmpInitFailed_(&exHeap_), trustedRoutines_(&exHeap_), roleIDs_(NULL), + granteeIDs_(NULL), numRoles_(0), unusedBMOsMemoryQuota_(0) { @@ -3974,7 +3975,9 @@ RETCODE ContextCli::authQuery( char localNameBuf[32]; char isValidFromUsersTable[3]; - if (queryType == USERS_QUERY_BY_USER_ID) + if (queryType == USERS_QUERY_BY_USER_ID || + queryType == ROLE_QUERY_BY_ROLE_ID || + queryType == ROLES_QUERY_BY_AUTH_ID) { sprintf(localNameBuf, "%d", (int) authID); nameForDiags = localNameBuf; @@ -4040,7 +4043,24 @@ RETCODE ContextCli::authQuery( case ROLES_QUERY_BY_AUTH_ID: { authInfoPtr = &authInfo; - authStatus = authInfo.getRoleIDs(authID, roleIDs); + std::vector roleIDs; + std::vector granteeIDs; + authStatus = authInfo.getRoleIDs(authID, roleIDs, granteeIDs); + ex_assert((roleIDs.size() == granteeIDs.size()), "mismatch between roleIDs and granteeIDs"); + numRoles_ = roleIDs.size() + 1; // extra for public role + roleIDs_ = new (&exHeap_) Int32[numRoles_]; + granteeIDs_ = new (&exHeap_) Int32[numRoles_]; + + for (size_t i = 0; i < roleIDs.size(); i++) + { + roleIDs_[i] = roleIDs[i]; + granteeIDs_[i] = granteeIDs[i]; + } + + // Add the public user to the last entry + Int32 lastEntry = numRoles_ - 1; + roleIDs_[lastEntry] = PUBLIC_USER; + granteeIDs_[lastEntry] = databaseUserID_; } break; @@ -4199,19 +4219,35 @@ RETCODE ContextCli::setDatabaseUserByName(const char *userName) // * // * Function: ContextCli::getRoleList // * -// * Return the role IDs granted to the current user +// * Return the role IDs and their grantees for the current user. // * If the list of roles is already stored, just return this list. // * If the list of roles does not exist extract the roles granted to the // * current user from the Metadata and store in roleIDs_. // * // **************************************************************************** RETCODE ContextCli::getRoleList( - Int32 &numRoles, - Int32 *&roleIDs) + Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs) { // If role list has not been created, go read metadata if (roleIDs_ == NULL) { + // If authorization is not enabled, just setup the PUBLIC role + CmpContext *cmpCntxt = CmpCommon::context(); + ex_assert(cmpCntxt, "No compiler context exists"); + if (!cmpCntxt->isAuthorizationEnabled()) + { + numRoles_ = 1; + roleIDs_ = new (&exHeap_) Int32[numRoles_]; + roleIDs_[0] = PUBLIC_USER; + granteeIDs = new (&exHeap_) Int32[numRoles_]; + granteeIDs[0] = databaseUserID_; + numEntries = numRoles_; + roleIDs = roleIDs_; + return SUCCESS; + } + // Get roles for userID char usersNameFromUsersTable[MAX_USERNAME_LEN +1]; Int32 userIDFromUsersTable; @@ -4225,19 +4261,11 @@ RETCODE ContextCli::getRoleList( myRoles); // OUT if (result != SUCCESS) return result; - - // Include the public user - myRoles.push_back(PUBLIC_USER); - - // Add role info to ContextCli - numRoles_ = myRoles.size(); - roleIDs_ = new (&exHeap_) Int32[numRoles_]; - for (size_t i = 0; i < numRoles_; i++) - roleIDs_[i] = myRoles[i]; } - numRoles = numRoles_; + numEntries = numRoles_; roleIDs = roleIDs_; + granteeIDs = granteeIDs_; return SUCCESS; } @@ -4256,6 +4284,11 @@ RETCODE ContextCli::resetRoleList() if (roleIDs_) NADELETEBASIC(roleIDs_, &exHeap_); roleIDs_ = NULL; + + if (granteeIDs_) + NADELETEBASIC(granteeIDs_, &exHeap_); + granteeIDs_ = NULL; + numRoles_ = 0; return SUCCESS; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/Context.h ---------------------------------------------------------------------- diff --git a/core/sql/cli/Context.h b/core/sql/cli/Context.h index c000714..23846d6 100644 --- a/core/sql/cli/Context.h +++ b/core/sql/cli/Context.h @@ -150,8 +150,9 @@ public: // functions to get and set roles for the current user - RETCODE getRoleList(Int32 &numRoles, - Int32 *&roleIDs); + RETCODE getRoleList(Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs); RETCODE resetRoleList(); @@ -258,8 +259,9 @@ private: char *databaseUserName_; // List of active roles for the databaseUser - Int32 *roleIDs_; Int32 numRoles_; + Int32 *roleIDs_; + Int32 *granteeIDs_; NABoolean userNameChanged_; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/cli/SQLCLIdev.h ---------------------------------------------------------------------- diff --git a/core/sql/cli/SQLCLIdev.h b/core/sql/cli/SQLCLIdev.h index 3dddf9e..59646be 100644 --- a/core/sql/cli/SQLCLIdev.h +++ b/core/sql/cli/SQLCLIdev.h @@ -310,8 +310,9 @@ Lng32 SQL_EXEC_SetErrorCodeInRTS( /*IN*/ Lng32 sqlErrorCode); Lng32 SQL_EXEC_GetRoleList( - Int32 &numRoles, - Int32 *&roleIDs); + Int32 &numEntries, + Int32 *& roleIDs, + Int32 *& granteeIDs); Lng32 SQL_EXEC_ResetRoleList_Internal (); http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/comexe/ComTdb.h ---------------------------------------------------------------------- diff --git a/core/sql/comexe/ComTdb.h b/core/sql/comexe/ComTdb.h index e00728f..59db8a7 100644 --- a/core/sql/comexe/ComTdb.h +++ b/core/sql/comexe/ComTdb.h @@ -1111,7 +1111,7 @@ class ComTdbVirtTablePrivInfo : public ComTdbVirtTableBase virtual Int32 size() { return sizeof(ComTdbVirtTablePrivInfo);} - NAList *privmgr_desc_list; + PrivMgrDescList *privmgr_desc_list; }; class ComTdbVirtTableLibraryInfo : public ComTdbVirtTableBase http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComDistribution.cpp ---------------------------------------------------------------------- diff --git a/core/sql/common/ComDistribution.cpp b/core/sql/common/ComDistribution.cpp index 14bb378..a741536 100644 --- a/core/sql/common/ComDistribution.cpp +++ b/core/sql/common/ComDistribution.cpp @@ -301,6 +301,10 @@ const literalAndEnumStruct qiTypeConversionTable [] = {COM_QI_GRANT_ROLE, COM_QI_GRANT_ROLE_LIT}, {COM_QI_USER_GRANT_ROLE, COM_QI_USER_GRANT_ROLE_LIT}, {COM_QI_ROLE_GRANT_ROLE, COM_QI_ROLE_GRANT_ROLE_LIT}, + {COM_QI_COLUMN_SELECT, COM_QI_COLUMN_SELECT_LIT}, + {COM_QI_COLUMN_INSERT, COM_QI_COLUMN_INSERT_LIT}, + {COM_QI_COLUMN_UPDATE, COM_QI_COLUMN_UPDATE_LIT}, + {COM_QI_COLUMN_REFERENCES, COM_QI_COLUMN_REFERENCES_LIT}, {COM_QI_OBJECT_SELECT, COM_QI_OBJECT_SELECT_LIT}, {COM_QI_OBJECT_INSERT, COM_QI_OBJECT_INSERT_LIT}, {COM_QI_OBJECT_DELETE, COM_QI_OBJECT_DELETE_LIT}, http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComSecurityKey.cpp ---------------------------------------------------------------------- diff --git a/core/sql/common/ComSecurityKey.cpp b/core/sql/common/ComSecurityKey.cpp index 567d9ee..a2b4706 100644 --- a/core/sql/common/ComSecurityKey.cpp +++ b/core/sql/common/ComSecurityKey.cpp @@ -46,7 +46,9 @@ NABoolean qiSubjectMatchesRole(uint32_t subjectKey) { NAList roleIDs(NULL); - ComUser::getCurrentUserRoles(roleIDs); + if (ComUser::getCurrentUserRoles(roleIDs) != 0) + return TRUE; // force recompilation if can't get current roles + for (int i = 0; i < roleIDs.entries(); i++) { if (subjectKey = ComSecurityKey::generateHash(roleIDs[i])) @@ -84,6 +86,7 @@ NABoolean qiCheckForInvalidObject (const Int32 numInvalidationKeys, { // Indicates that the DDL of the object has changed. case COM_QI_OBJECT_REDEF: + // Indicates that the histogram statistics of the object has changed. case COM_QI_STATS_UPDATED: { @@ -95,6 +98,10 @@ NABoolean qiCheckForInvalidObject (const Int32 numInvalidationKeys, // Scan the passed-in object keys to find any that match the subject, // object, and key type. That is, the subject has the privilege // (invalidation key type) on the object or a column of the object. + case COM_QI_COLUMN_SELECT: + case COM_QI_COLUMN_INSERT: + case COM_QI_COLUMN_UPDATE: + case COM_QI_COLUMN_REFERENCES: case COM_QI_OBJECT_SELECT: case COM_QI_OBJECT_INSERT: case COM_QI_OBJECT_DELETE: @@ -117,6 +124,7 @@ NABoolean qiCheckForInvalidObject (const Int32 numInvalidationKeys, } } break; + case COM_QI_USER_GRANT_SPECIAL_ROLE: case COM_QI_USER_GRANT_ROLE: { @@ -146,19 +154,36 @@ NABoolean qiCheckForInvalidObject (const Int32 numInvalidationKeys, // Function that builds query invalidation keys for privileges. A separate // invalidation key is added for each granted DML privilege. // +// Parameters: +// roleGrantees - needed to create invalidation keys to represent: +// all authorization ID that have been granted the role +// granteeID - the authID which has been granted one or more privileges +// could be a userID, a role the userID is granted or PUBLIC +// objectUID - the object (object) granted privilege +// privs - the list of DML privileges +// secKeySet - the list of invalidation keys generated +// +// secKeySet is a set so it automatically silently ignores duplicate entries +// // Types of keys available for privs: -// OBJECT_IS_SCHEMA - not supported until we support schema level privs +// OBJECT_IS_SCHEMA - not supported // OBJECT_IS_OBJECT - supported for granting privs to user -// OBJECT_IS_COLUMN - not supported at this time +// grant on to +// OBJECT_IS_COLUMN - partially supported +// grant (col-list) on to // OBJECT_IS_SPECIAL_ROLE - key for PUBLIC authorization ID +// grant [(col-list)] on to PUBLIC // SUBJECT_IS_USER - support for granting roles to user -// SUBJECT_IS_ROLE - not supported until we grant roles to roles +// grant role to +// SUBJECT_IS_ROLE - support for granting roles to role +// grant on to // // returns false is unable to build keys // **************************************************************************** -bool buildSecurityKeys( const int32_t userID, +bool buildSecurityKeys( const NAList &roleGrantees, const int32_t granteeID, const int64_t objectUID, + const bool isColumn, const PrivMgrCoreDesc &privs, ComSecurityKeySet &secKeySet ) { @@ -166,7 +191,7 @@ bool buildSecurityKeys( const int32_t userID, return true; NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE); - std::string msg ("Method: buildSecurityKeys: "); + std::string msg ("Method: buildSecurityKeys "); if (doDebug) { printf("[DBUSER:%d] %s\n", (int) getpid(), msg.c_str()); @@ -191,33 +216,41 @@ bool buildSecurityKeys( const int32_t userID, return false; } - // If the grantee is a role, generate a special security key - // If the role is revoked from the user, this key takes affect + // If the grantee is a role, generate special security keys, one for + // the user and one for each of the user's roles. + // If the role is revoked from the user these key takes affect if (PrivMgr::isRoleID(granteeID)) { - ComSecurityKey key (userID, granteeID, ComSecurityKey::SUBJECT_IS_USER); - if (doDebug) + char buf [200]; + for (CollIndex r = 0; r < roleGrantees.entries(); r++) { - NAString msg = key.print(userID, granteeID); - printf("[DBUSER:%d] (role) %s\n", - (int) getpid(), msg.data()); - fflush(stdout); - } + ComSecurityKey::QIType qiType = ComSecurityKey::SUBJECT_IS_USER; + ComSecurityKey key (roleGrantees[r], granteeID, qiType); + if (doDebug) + { + NAString msg = key.print(roleGrantees[r], granteeID); + printf("[DBUSER:%d] (role) %s\n", + (int) getpid(), msg.data()); + fflush(stdout); + } - if (key.isValid()) - secKeySet.insert(key); - else - return false; + if (key.isValid()) + secKeySet.insert(key); + else + return false; + } } - // Generate object invalidation keys - // Only need to generate keys for DML privileges + // Generate keys one per granted DML privilege for ( size_t i = FIRST_DML_PRIV; i <= LAST_DML_PRIV; i++ ) { if ( privs.getPriv(PrivType(i))) { - ComSecurityKey key (granteeID, objectUID, PrivType(i), - ComSecurityKey::OBJECT_IS_OBJECT); + ComSecurityKey::QIType qiType = (isColumn) ? + ComSecurityKey::OBJECT_IS_COLUMN : + ComSecurityKey::OBJECT_IS_OBJECT; + + ComSecurityKey key (granteeID, objectUID, PrivType(i), qiType); if (doDebug) { NAString msg = key.print(granteeID, objectUID); @@ -270,7 +303,7 @@ void qiInvalidationType (const Int32 numInvalidationKeys, if (doDebug) { sprintf(buf, ": num keys(%d)", numInvalidationKeys); - printf("[DBUSER:%d] Method: qiInvalidationType%s\n", + printf("[DBUSER:%d] Method: qiInvalidationType (what should be invalidated) %s\n", (int) getpid(), buf); fflush(stdout); sprintf(buf, "Not applicable"); @@ -491,14 +524,14 @@ ComQIActionType ComSecurityKey::convertBitmapToQIActionType ( case SELECT_PRIV: if (inputType == OBJECT_IS_OBJECT) result = COM_QI_OBJECT_SELECT; - //else - // result = COM_QI_COLUMN_SELECT; + else + result = COM_QI_COLUMN_SELECT; break; case INSERT_PRIV: if (inputType == OBJECT_IS_OBJECT) result = COM_QI_OBJECT_INSERT; - //else - // result = COM_QI_COLUMN_INSERT; + else + result = COM_QI_COLUMN_INSERT; break; case DELETE_PRIV: if (inputType == OBJECT_IS_OBJECT) @@ -507,8 +540,8 @@ ComQIActionType ComSecurityKey::convertBitmapToQIActionType ( case UPDATE_PRIV: if (inputType == OBJECT_IS_OBJECT) result = COM_QI_OBJECT_UPDATE; - //else - // result = COM_QI_COLUMN_UPDATE; + else + result = COM_QI_COLUMN_UPDATE; break; case USAGE_PRIV: if (inputType == OBJECT_IS_OBJECT) @@ -517,12 +550,12 @@ ComQIActionType ComSecurityKey::convertBitmapToQIActionType ( case REFERENCES_PRIV: if (inputType == OBJECT_IS_OBJECT) result = COM_QI_OBJECT_REFERENCES; + else + result = COM_QI_COLUMN_REFERENCES; break; case EXECUTE_PRIV: if (inputType == OBJECT_IS_OBJECT) result = COM_QI_OBJECT_EXECUTE; - else if (inputType == OBJECT_IS_SCHEMA) - result = COM_QI_SCHEMA_EXECUTE; break; default: result = COM_QI_INVALID_ACTIONTYPE; @@ -560,6 +593,18 @@ void ComSecurityKey::getSecurityKeyTypeAsLit (std::string &actionString) const case COM_QI_ROLE_GRANT_ROLE: actionString = COM_QI_ROLE_GRANT_ROLE_LIT; break; + case COM_QI_COLUMN_SELECT: + actionString = COM_QI_COLUMN_SELECT_LIT; + break; + case COM_QI_COLUMN_INSERT: + actionString = COM_QI_COLUMN_INSERT_LIT; + break; + case COM_QI_COLUMN_UPDATE: + actionString = COM_QI_COLUMN_UPDATE_LIT; + break; + case COM_QI_COLUMN_REFERENCES: + actionString = COM_QI_COLUMN_REFERENCES_LIT; + break; case COM_QI_OBJECT_SELECT: actionString = COM_QI_OBJECT_SELECT_LIT; break; @@ -618,17 +663,17 @@ NAString ComSecurityKey::print(Int32 subjectID, Int64 objectID) case COM_QI_ROLE_GRANT_ROLE: typeString = "ROLE_GRANT_ROLE"; break; - case COM_QI_SCHEMA_SELECT: - typeString = "SCHEMA_SELECT"; + case COM_QI_COLUMN_SELECT: + typeString = "COLUMN_SELECT"; break; - case COM_QI_SCHEMA_INSERT: - typeString = "SCHEMA_INSERT"; + case COM_QI_COLUMN_INSERT: + typeString = "COLUMN_INSERT"; break; - case COM_QI_SCHEMA_DELETE: - typeString = "SCHEMA_DELETE"; + case COM_QI_COLUMN_UPDATE: + typeString = "COLUMN_UPDATE"; break; - case COM_QI_SCHEMA_UPDATE: - typeString = "SCHEMA_UPDATE"; + case COM_QI_COLUMN_REFERENCES: + typeString = "COLUMN_REFERENCES"; break; case COM_QI_OBJECT_SELECT: typeString = "OBJECT_SELECT"; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComSecurityKey.h ---------------------------------------------------------------------- diff --git a/core/sql/common/ComSecurityKey.h b/core/sql/common/ComSecurityKey.h index 8f90d16..3a06779 100644 --- a/core/sql/common/ComSecurityKey.h +++ b/core/sql/common/ComSecurityKey.h @@ -37,9 +37,10 @@ class ComSecurityKey; typedef NASet ComSecurityKeySet; -bool buildSecurityKeys( const int32_t userID, - const int32_t granteeID, +bool buildSecurityKeys( const NAList &roleGrantees, + const int32_t roleID, const int64_t objectUID, + const bool isColumn, const PrivMgrCoreDesc &privs, ComSecurityKeySet &secKeySet); @@ -101,13 +102,22 @@ public: ComSecurityKey( const int32_t subjectUserID, const int64_t objectUserID, - const QIType typeOfSubject = SUBJECT_IS_USER); + const QIType typeOfSubject); // Constructor for a special role grant to an authID. ComSecurityKey( const int32_t subjectUserID, const QIType typeOfObject); + // Constructor for generating revoke role from subject + ComSecurityKey( + const uint32_t subjectHashValue, + const uint32_t objectHashValue) + : subjectHash_(subjectHashValue), + objectHash_ (objectHashValue), + actionType_(COM_QI_USER_GRANT_ROLE) + {}; + ComSecurityKey(); // do not use bool operator == (const ComSecurityKey &other) const; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComSmallDefs.h ---------------------------------------------------------------------- diff --git a/core/sql/common/ComSmallDefs.h b/core/sql/common/ComSmallDefs.h index db99f28..c18662d 100644 --- a/core/sql/common/ComSmallDefs.h +++ b/core/sql/common/ComSmallDefs.h @@ -1309,6 +1309,10 @@ enum ComQIActionType { COM_QI_INVALID_ACTIONTYPE = 0 , COM_QI_OBJECT_REDEF , COM_QI_STATS_UPDATED , COM_QI_GRANT_ROLE + , COM_QI_COLUMN_SELECT + , COM_QI_COLUMN_INSERT + , COM_QI_COLUMN_UPDATE + , COM_QI_COLUMN_REFERENCES } ; #define COM_QI_INVALID_ACTIONTYPE_LIT " " @@ -1332,6 +1336,11 @@ enum ComQIActionType { COM_QI_INVALID_ACTIONTYPE = 0 #define COM_QI_OBJECT_REDEF_LIT "OR" #define COM_QI_STATS_UPDATED_LIT "US" #define COM_QI_GRANT_ROLE_LIT "GG" +#define COM_QI_COLUMN_SELECT_LIT "CS" +#define COM_QI_COLUMN_INSERT_LIT "CI" +#define COM_QI_COLUMN_UPDATE_LIT "CU" +#define COM_QI_COLUMN_REFERENCES_LIT "CF" + http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComUser.cpp ---------------------------------------------------------------------- diff --git a/core/sql/common/ComUser.cpp b/core/sql/common/ComUser.cpp index 2b6831f..516d411 100644 --- a/core/sql/common/ComUser.cpp +++ b/core/sql/common/ComUser.cpp @@ -362,7 +362,8 @@ bool ComUser::currentUserHasRole(Int32 roleID) { Int32 numRoles = 0; Int32 *roleIDs = 0; - if (SQL_EXEC_GetRoleList(numRoles, roleIDs) < 0) + Int32 *granteeIDs = NULL; + if (SQL_EXEC_GetRoleList(numRoles, roleIDs, granteeIDs) < 0) return false; for (Int32 i = 0; i < numRoles; i++) @@ -374,15 +375,64 @@ bool ComUser::currentUserHasRole(Int32 roleID) return false; } -void ComUser::getCurrentUserRoles(NAList &roleList) +// ---------------------------------------------------------------------------- +// method: getCurrentUserRoles +// +// Gets the active roles for the current user as a list of Int32's +// There should be at least one role in this list (PUBLIC) +// +// Returns: +// -1 -- unexpected error getting roles +// 0 -- successful +// ---------------------------------------------------------------------------- +Int16 ComUser::getCurrentUserRoles(NAList &roleIDs) { Int32 numRoles = 0; - Int32 *roleIDs = 0; - Int32 retcode = SQL_EXEC_GetRoleList(numRoles, roleIDs); - assert(retcode == 0); + Int32 *cachedRoleIDs = NULL; + Int32 *cachedGranteeIDs = NULL; + RETCODE retcode = + GetCliGlobals()->currContext()->getRoleList(numRoles, cachedRoleIDs, cachedGranteeIDs); + + if (retcode != SUCCESS) + return -1; + + for (Int32 i = 0; i < numRoles; i++) + { + // in case there are duplicates + if (!roleIDs.contains(cachedRoleIDs[i])) + roleIDs.insert (cachedRoleIDs[i]); + } + return 0; +} + +// ---------------------------------------------------------------------------- +// method: getCurrentUserRoles +// +// Gets the active roles and grantees for the current user as a list of Int32's +// There should be at least one role in this list (PUBLIC) +// +// Returns: +// -1 -- unexpected error getting roles +// 0 -- successful +// ---------------------------------------------------------------------------- +Int16 ComUser::getCurrentUserRoles(NAList &roleIDs, NAList &granteeIDs) +{ + Int32 numRoles = 0; + Int32 *cachedRoleIDs = NULL; + Int32 *cachedGranteeIDs = NULL; + RETCODE retcode = + GetCliGlobals()->currContext()->getRoleList(numRoles, cachedRoleIDs, cachedGranteeIDs); + + if (retcode != SUCCESS) + return -1; for (Int32 i = 0; i < numRoles; i++) - roleList.insert (roleIDs[i]); + { + roleIDs.insert (cachedRoleIDs[i]); + granteeIDs.insert (cachedGranteeIDs[i]); + } + + return 0; } http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/common/ComUser.h ---------------------------------------------------------------------- diff --git a/core/sql/common/ComUser.h b/core/sql/common/ComUser.h index eb5db65..8a24de9 100644 --- a/core/sql/common/ComUser.h +++ b/core/sql/common/ComUser.h @@ -91,7 +91,10 @@ class ComUser Int32 & authID); static bool currentUserHasRole(Int32 roleID); - static void getCurrentUserRoles(NAList &roleList); + static Int16 getCurrentUserRoles(NAList &roleIDs); + static Int16 getCurrentUserRoles(NAList &roleIDs, + NAList &granteeIDs); + static Int32 getRoleList (char *roleList, Int32 &actualLen, http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/executor/ExExeUtilGet.cpp ---------------------------------------------------------------------- diff --git a/core/sql/executor/ExExeUtilGet.cpp b/core/sql/executor/ExExeUtilGet.cpp index 590b068..86e6a7b 100644 --- a/core/sql/executor/ExExeUtilGet.cpp +++ b/core/sql/executor/ExExeUtilGet.cpp @@ -1665,10 +1665,10 @@ NABoolean ExExeUtilGetMetadataInfoTcb::checkUserPrivs( if (ComUser::isRootUserID()) return FALSE; - // any user granted the DB__ROOTROLE sees everything Int32 numRoles; Int32 *roleList; - if (currContext->getRoleList(numRoles, roleList) == SUCCESS) + Int32 *granteeList; + if (currContext->getRoleList(numRoles, roleList, granteeList) == SUCCESS) { char authIDAsChar[sizeof(Int32)+10]; NAString auths; @@ -2001,7 +2001,8 @@ short ExExeUtilGetMetadataInfoTcb::work() // add list of roles stored in context Int32 numRoles; Int32 *roleList; - if (currContext->getRoleList(numRoles, roleList) != SUCCESS) + Int32 *granteeList; + if (currContext->getRoleList(numRoles, roleList, granteeList) != SUCCESS) numRoles = 0; for (Int32 i = 0; i < numRoles; i++) { http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/generator/Generator.cpp ---------------------------------------------------------------------- diff --git a/core/sql/generator/Generator.cpp b/core/sql/generator/Generator.cpp index 4cbb8bf..df98a66 100644 --- a/core/sql/generator/Generator.cpp +++ b/core/sql/generator/Generator.cpp @@ -1723,8 +1723,8 @@ TrafDesc * Generator::createPrivDescs( const ComTdbVirtTablePrivInfo * privInfo, { // When authorization is enabled, each object must have at least one grantee // - the system grant to the object owner - NAList *privGrantees = privInfo[0].privmgr_desc_list; - DCMPASSERT (privGrantees.size() > 0); + PrivMgrDescList *privGrantees = privInfo[0].privmgr_desc_list; + DCMPASSERT (privGrantees->entries() > 0); TrafDesc * priv_desc = TrafAllocateDDLdesc(DESC_PRIV_TYPE, space); TrafDesc * first_grantee_desc = NULL; @@ -1734,17 +1734,18 @@ TrafDesc * Generator::createPrivDescs( const ComTdbVirtTablePrivInfo * privInfo, // attach to the privileges descriptor (priv_desc) for (int i = 0; i < privGrantees->entries(); i++) { - PrivMgrDesc &granteeDesc = (*privGrantees)[i]; + PrivMgrDesc *granteeDesc = (*privGrantees)[i]; TrafDesc * curr_grantee_desc = TrafAllocateDDLdesc(DESC_PRIV_GRANTEE_TYPE, space); if (! first_grantee_desc) first_grantee_desc = curr_grantee_desc; - curr_grantee_desc->privGranteeDesc()->grantee = granteeDesc.getGrantee(); + curr_grantee_desc->privGranteeDesc()->grantee = granteeDesc->getGrantee(); // generate a TrafPrivBitmap for the object level privs and // attach it to the privilege grantee descriptor (curr_grantee_desc) TrafDesc * bitmap_desc = TrafAllocateDDLdesc(DESC_PRIV_BITMAP_TYPE, space); - PrivMgrCoreDesc objDesc = granteeDesc.getTablePrivs(); + PrivMgrCoreDesc objDesc = granteeDesc->getTablePrivs(); + bitmap_desc->privBitmapDesc()->columnOrdinal = -1; bitmap_desc->privBitmapDesc()->privBitmap = objDesc.getPrivBitmap().to_ulong(); bitmap_desc->privBitmapDesc()->privWGOBitmap = objDesc.getWgoBitmap().to_ulong(); @@ -1752,14 +1753,14 @@ TrafDesc * Generator::createPrivDescs( const ComTdbVirtTablePrivInfo * privInfo, // generate a list of TrafPrivBitmapDesc, one for each column and // attach it to the TrafPrivGranteeDesc - size_t numCols = granteeDesc.getColumnPrivs().entries(); + size_t numCols = granteeDesc->getColumnPrivs().entries(); if (numCols > 0) { TrafDesc * first_col_desc = NULL; TrafDesc * prev_col_desc = NULL; for (int j = 0; j < numCols; j++) { - const PrivMgrCoreDesc colBitmap = granteeDesc.getColumnPrivs()[j]; + const PrivMgrCoreDesc colBitmap = granteeDesc->getColumnPrivs()[j]; TrafDesc * curr_col_desc = TrafAllocateDDLdesc(DESC_PRIV_BITMAP_TYPE, space); if (! first_col_desc) first_col_desc = curr_col_desc; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/BindRelExpr.cpp ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index 716a9c6..43afef6 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -7005,6 +7005,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) optStoi = (bindWA->getStoiList())[i]; stoi = optStoi->getStoi(); NATable* tab = optStoi->getTable(); + ComSecurityKeySet secKeySet = tab->getSecKeySet(); // System metadata tables do not, by default, have privileges stored in the // NATable structure. Go ahead and retrieve them now. @@ -7012,6 +7013,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) PrivMgrUserPrivs privInfo; if (!pPrivInfo) { + secKeySet.clear(); CmpSeabaseDDL cmpSBD(STMTHEAP); if (cmpSBD.switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META)) { @@ -7019,7 +7021,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) *CmpCommon::diags() << DgSqlCode( -4400 ); return FALSE; } - retcode = privInterface.getPrivileges( tab, thisUserID, privInfo); + retcode = privInterface.getPrivileges( tab, thisUserID, privInfo, &secKeySet); cmpSBD.switchBackCompiler(); if (retcode != STATUS_GOOD) @@ -7034,7 +7036,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) // Check each primary DML privilege to see if the query requires it. If // so, verify that the user has the privilege - bool insertQIKeys = (QI_enabled && tab->getSecKeySet().entries() > 0); + bool insertQIKeys = (QI_enabled && secKeySet.entries() > 0); for (int_32 i = FIRST_DML_PRIV; i <= LAST_PRIMARY_DML_PRIV; i++) { if (stoi->getPrivAccess((PrivType)i)) @@ -7043,7 +7045,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) RemoveNATableEntryFromCache = TRUE; else if (insertQIKeys) - findKeyAndInsertInOutputList(tab->getSecKeySet(),userHashValue,(PrivType)(i)); + findKeyAndInsertInOutputList(secKeySet,userHashValue,(PrivType)(i), bindWA); } } @@ -7085,7 +7087,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) { // do this only if QI is enabled and object has security keys defined if ( insertQIKeys ) - findKeyAndInsertInOutputList(rtn->getSecKeySet(), userHashValue, EXECUTE_PRIV); + findKeyAndInsertInOutputList(rtn->getSecKeySet(), userHashValue, EXECUTE_PRIV, bindWA); } // plan requires privilege but user has none, report an error @@ -7121,6 +7123,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) NATable* tab = bindWA->getSchemaDB()->getNATableDB()-> get(coProcAggr->getCorrName(), bindWA, NULL); + ComSecurityKeySet secKeySet = tab->getSecKeySet(); Int32 numSecKeys = 0; // Privilege info for the user/table combination is stored in the NATable @@ -7132,6 +7135,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) // NATable structure. Go ahead and retrieve them now. if (!pPrivInfo) { + secKeySet.clear(); CmpSeabaseDDL cmpSBD(STMTHEAP); if (cmpSBD.switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META)) { @@ -7139,7 +7143,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) *CmpCommon::diags() << DgSqlCode( -4400 ); return FALSE; } - retcode = privInterface.getPrivileges( tab, thisUserID, privInfo); + retcode = privInterface.getPrivileges( tab, thisUserID, privInfo, &secKeySet); cmpSBD.switchBackCompiler(); if (retcode != STATUS_GOOD) @@ -7155,13 +7159,13 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) // Verify that the user has select priv // Select priv is needed for EXPLAIN requests, so no special check is done NABoolean insertQIKeys = FALSE; - if (QI_enabled && (tab->getSecKeySet().entries()) > 0) + if (QI_enabled && (secKeySet.entries()) > 0) insertQIKeys = TRUE; if (pPrivInfo->hasPriv(SELECT_PRIV)) { // do this only if QI is enabled and object has security keys defined if ( insertQIKeys ) - findKeyAndInsertInOutputList(tab->getSecKeySet(), userHashValue, SELECT_PRIV ); + findKeyAndInsertInOutputList(secKeySet, userHashValue, SELECT_PRIV, bindWA ); } // plan requires privilege but user has none, report an error @@ -7183,12 +7187,14 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) SequenceValue *seqVal = (bindWA->getSeqValList())[i]; NATable* tab = const_cast(seqVal->getNATable()); CMPASSERT(tab); + ComSecurityKeySet secKeySet = tab->getSecKeySet(); // get privilege information from the NATable structure PrivMgrUserPrivs *pPrivInfo = tab->getPrivInfo(); PrivMgrUserPrivs privInfo; if (!pPrivInfo) { + secKeySet.clear(); CmpSeabaseDDL cmpSBD(STMTHEAP); if (cmpSBD.switchCompiler(CmpContextInfo::CMPCONTEXT_TYPE_META)) { @@ -7196,7 +7202,7 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) *CmpCommon::diags() << DgSqlCode( -4400 ); return FALSE; } - retcode = privInterface.getPrivileges(tab, thisUserID, privInfo); + retcode = privInterface.getPrivileges(tab, thisUserID, privInfo, &secKeySet); cmpSBD.switchBackCompiler(); if (retcode != STATUS_GOOD) { @@ -7210,13 +7216,13 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) // Verify that the user has usage priv NABoolean insertQIKeys = FALSE; - if (QI_enabled && (tab->getSecKeySet().entries()) > 0) + if (QI_enabled && (secKeySet.entries()) > 0) insertQIKeys = TRUE; if (pPrivInfo->hasPriv(USAGE_PRIV)) { // do this only if QI is enabled and object has security keys defined if ( insertQIKeys ) - findKeyAndInsertInOutputList(tab->getSecKeySet(), userHashValue, USAGE_PRIV ); + findKeyAndInsertInOutputList(secKeySet, userHashValue, USAGE_PRIV, bindWA ); } // plan requires privilege but user has none, report an error @@ -7248,44 +7254,68 @@ NABoolean RelRoot::checkPrivileges(BindWA* bindWA) // COM_QI_USER_GRANT_SPECIAL_ROLE: privileges granted to PUBLIC // // Keys are added as follows: -// if a privilege has been granted via a role, add a RoleUserKey -// if this role is revoked from the user, then invalidation is forced -// if a privilege has been granted to public, add a UserObjectPublicKey -// if a privilege is revoked from public, then invalidation is forced -// if a privilege has been granted directly to an object, add UserObjectKey -// if the privilege is revoked from the user, then invalidation is forced -// If a privilege has not been granted to an object, but is has been granted -// to a role, add a RoleObjectKey +// if a privilege has been granted to public, +// add UserObjectPublicKey +// invalidation is enforced when priv is revoked from public +// if a privilege has been granted on a column of an object to a user: +// add UserColumnKey +// invalidation is enforced when and column priv is revoked from the user +// if a privilege has been granted on a column of an object to a role: +// add to ColumnRoleKeys +// invalidation is enforced when any priv is revoked from one of these roles +// or when one of these roles is revoked from the user. +// if a privilege has been granted directly on an object to a user: +// add UserObjectKey +// invalidation is enforced when priv is revoked from the user +// if a privilege has been granted directly on an object to a role: +// add an entry to ObjectRoleKeys +// invalidation is enforced when priv is revoked from one of these roles, +// or when one of these roles is revoked from user // -// So if the same privilege has been granted directly to the user and via -// a role granted to the user, we only add a UserObjectKey // **************************************************************************** void RelRoot::findKeyAndInsertInOutputList( ComSecurityKeySet KeysForTab , const uint32_t userHashValue , const PrivType which + , BindWA* bindWA ) { // If no keys associated with object, just return if (KeysForTab.entries() == 0) return; + ComSecurityKey * UserColumnKey = NULL; + ComSecurityKey * RoleColumnKey = NULL; ComSecurityKey * UserObjectKey = NULL; ComSecurityKey * RoleObjectKey = NULL; ComSecurityKey * UserObjectPublicKey = NULL; - ComSecurityKey * RoleUserKey = NULL; // These may be implemented at a later time ComSecurityKey * UserSchemaKey = NULL; //privs granted at schema level to user - ComSecurityKey * RoleSchemaKey = NULL; //privs granted at schema level to role // Get action type for UserObjectKey based on the privilege (which) // so if (which) is SELECT, then the objectActionType is COM_QI_OBJECT_SELECT ComSecurityKey dummyKey; + ComQIActionType columnActionType = + dummyKey.convertBitmapToQIActionType ( which, ComSecurityKey::OBJECT_IS_COLUMN ); ComQIActionType objectActionType = dummyKey.convertBitmapToQIActionType ( which, ComSecurityKey::OBJECT_IS_OBJECT ); ComSecurityKey * thisKey = NULL; + // With column level privileges, the user may get privileges from various + // roles. Today, we add all roles that may hold the requested privilege. + // If we ever fully support invalidation keys at the column level, then only + // roles that are required to run the query should be added. + // For example, + // user gets select on table1: col1, col2 from role1 + // user gets select on table1: col3, col4 from role2 + // If the query performs a select for col1, then only changes to role1 are relevant + // Today, we include both role1 and role2 + // Therefore, if role2 is revoked from the user, invalidation is unnecessarily enforced + ComSecurityKeySet ColumnRoleKeys(bindWA->wHeap()); + ComSecurityKeySet ObjectRoleKeys(bindWA->wHeap()); + ComSecurityKeySet SchemaRoleKeys(bindWA->wHeap()); + // NOTE: hashValueOfPublic will be the same for all keys, so we generate it only once. uint32_t hashValueOfPublic = ComSecurityKey::SPECIAL_OBJECT_HASH; @@ -7294,33 +7324,38 @@ void RelRoot::findKeyAndInsertInOutputList( ComSecurityKeySet KeysForTab { thisKey = &(KeysForTab[ii]); - // See if the key is object related - if ( thisKey->getSecurityKeyType() == objectActionType ) + // See if the key is column related + if ( thisKey->getSecurityKeyType() == columnActionType ) { if ( thisKey->getSubjectHashValue() == userHashValue ) { // Found a security key for the objectActionType - if ( ! UserObjectKey ) - UserObjectKey = thisKey; + if ( ! UserColumnKey ) + UserColumnKey = thisKey; } // Found a security key for a role associated with the user - else + else if (qiSubjectMatchesRole(thisKey->getSubjectHashValue())) { - if ( ! RoleObjectKey ) - RoleObjectKey = thisKey; + ColumnRoleKeys.insert(*thisKey); } } - - // See if the security key is role related - else if (thisKey->getSecurityKeyType() == COM_QI_USER_GRANT_ROLE) + + // See if the key is object related + else if ( thisKey->getSecurityKeyType() == objectActionType ) { if ( thisKey->getSubjectHashValue() == userHashValue ) { - if (! RoleUserKey ) - RoleUserKey = thisKey; + // Found a security key for the objectActionType + if ( ! UserObjectKey ) + UserObjectKey = thisKey; + } + // Found a security key for a role associated with the user + else if (qiSubjectMatchesRole(thisKey->getSubjectHashValue())) + { + ObjectRoleKeys.insert(*thisKey); } } - + else if (thisKey->getSecurityKeyType() == COM_QI_USER_GRANT_SPECIAL_ROLE) { if (thisKey->getObjectHashValue() == hashValueOfPublic ) @@ -7333,16 +7368,39 @@ void RelRoot::findKeyAndInsertInOutputList( ComSecurityKeySet KeysForTab else {;} // Not right action type, just continue traversing. } - // Determine best key, UserObjectKeys are better than RoleObjectKeys - ComSecurityKey * BestKey = (UserObjectKey) ? UserObjectKey : RoleObjectKey; + // Determine best key (fewest invalidations required) - if ( BestKey != NULL) - securityKeySet_.insert(*BestKey); + // For now, always add column invalidation keys. Once full integration of + // column privileges is implemented, then this code changes + if (UserColumnKey) + securityKeySet_.insert(*UserColumnKey); + else if (ColumnRoleKeys.entries() > 0) + { + for (int j = 0; j < ColumnRoleKeys.entries(); j++) + { + securityKeySet_.insert(ColumnRoleKeys[j]); + + // add a key in case the role is revoked from the user + ComSecurityKey roleKey(userHashValue, ColumnRoleKeys[j].getSubjectHashValue()); + securityKeySet_.insert(roleKey); + } + } - // Add RoleUserKey if priv comes from role - handles revoke role from user - if (BestKey == RoleObjectKey) - if ( RoleUserKey ) - securityKeySet_.insert(*RoleUserKey ); + // UserObjectKeys are better than ObjectRoleKeys + if (UserObjectKey) + securityKeySet_.insert(*UserObjectKey); + + else if (ObjectRoleKeys.entries() > 0) + { + for (int j = 0; j < ObjectRoleKeys.entries(); j++) + { + securityKeySet_.insert(ObjectRoleKeys[j]); + + // add a key in case the role is revoked from the user + ComSecurityKey roleKey(userHashValue, ObjectRoleKeys[j].getSubjectHashValue()); + securityKeySet_.insert(roleKey); + } + } // Add public if it exists - handles revoke public from user if ( UserObjectPublicKey != NULL ) http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/NARoutine.cpp ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/NARoutine.cpp b/core/sql/optimizer/NARoutine.cpp index 905e374..49df34f 100644 --- a/core/sql/optimizer/NARoutine.cpp +++ b/core/sql/optimizer/NARoutine.cpp @@ -96,7 +96,7 @@ NARoutine::NARoutine (CollHeap *heap) , hasOutParams_ (FALSE) , redefTime_ (0) , lastUsedTime_ (0) - , routineSecKeySet_ (heap) + , secKeySet_ (heap) , passThruDataNumEntries_ (0) , passThruData_ (NULL) , passThruDataSize_ (NULL) @@ -117,6 +117,7 @@ NARoutine::NARoutine (CollHeap *heap) , objectOwner_ (0) , schemaOwner_ (0) , privInfo_ (NULL) + , privDescs_ (NULL) , heap_ (heap) { } @@ -154,7 +155,7 @@ NARoutine::NARoutine ( const QualifiedName &name , hasOutParams_ (FALSE) , redefTime_ (0) , lastUsedTime_ (0) - , routineSecKeySet_ (heap) + , secKeySet_ (heap) , passThruDataNumEntries_ (0) , passThruData_ (NULL) , passThruDataSize_ (NULL) @@ -175,6 +176,7 @@ NARoutine::NARoutine ( const QualifiedName &name , objectOwner_ (0) , schemaOwner_ (0) , privInfo_ (NULL) + , privDescs_ (NULL) , heap_(heap) { CollIndex colCount = 0; @@ -285,7 +287,7 @@ NARoutine::NARoutine (const NARoutine &old, CollHeap *h) , hasOutParams_ (old.hasOutParams_) , redefTime_ (old.redefTime_) , lastUsedTime_ (old.lastUsedTime_) - , routineSecKeySet_ (h) + , secKeySet_ (h) , isUniversal_ (old.isUniversal_) , executionMode_ (old.getExecutionMode()) , objectUID_ (old.objectUID_) @@ -307,6 +309,7 @@ NARoutine::NARoutine (const NARoutine &old, CollHeap *h) , objectOwner_ (0) , schemaOwner_ (0) , privInfo_ (NULL) + , privDescs_ (NULL) , heap_ (h) { extRoutineName_ = new (h) ExtendedQualName(*old.extRoutineName_, h); @@ -335,7 +338,7 @@ NARoutine::NARoutine (const NARoutine &old, CollHeap *h) } } - routineSecKeySet_ = old.routineSecKeySet_; + secKeySet_ = old.secKeySet_; heapSize_ = (h ? h->getTotalSize() : 0); } @@ -368,7 +371,7 @@ NARoutine::NARoutine(const QualifiedName &name, , hasOutParams_ (FALSE) , redefTime_ (0) //TODO , lastUsedTime_ (0) - , routineSecKeySet_ (heap) + , secKeySet_ (heap) , passThruDataNumEntries_ (0) , passThruData_ (NULL) , passThruDataSize_ (0) @@ -388,6 +391,7 @@ NARoutine::NARoutine(const QualifiedName &name, , objectOwner_ (routine_desc->routineDesc()->owner) , schemaOwner_ (routine_desc->routineDesc()->schemaOwner) , privInfo_ (NULL) + , privDescs_ (NULL) , heap_(heap) { char parallelism[5]; @@ -602,7 +606,7 @@ NARoutine::NARoutine(const QualifiedName &name, } - getPrivileges(routine_desc->routineDesc()->priv_desc); + getPrivileges(routine_desc->routineDesc()->priv_desc, bindWA); heapSize_ = (heap ? heap->getTotalSize() : 0); } @@ -645,7 +649,7 @@ void NARoutine::setSasFormatWidth(NAString &width) // If authorization is enabled, set privs based on the passed in priv_desc // and set up query invalidation (security) keys for the routine. // ---------------------------------------------------------------------------- -void NARoutine::getPrivileges(TrafDesc *priv_desc) +void NARoutine::getPrivileges(TrafDesc *priv_desc, BindWA *bindWA) { if ( !CmpCommon::context()->isAuthorizationEnabled() || ComUser::isRootUserID()) { @@ -677,52 +681,58 @@ void NARoutine::getPrivileges(TrafDesc *priv_desc) COM_STORED_PROCEDURE_OBJECT : COM_USER_DEFINED_ROUTINE_OBJECT); - std::vector * secKeyVec = new(heap_) std::vector; - if (privInterface.getPrivileges(objectUID_, objectType, - ComUser::getCurrentUser(), - *privInfo_, secKeyVec) != STATUS_GOOD) - { - NADELETE(privInfo_, PrivMgrUserPrivs, heap_); - privInfo_ = NULL; - } - + // get all privileges granted to routine object + privDescs_ = new (heap_) PrivMgrDescList(heap_); //initialize empty list + PrivStatus privStatus = privInterface.getPrivileges(objectUID_, objectType, *privDescs_); cmpSBD.switchBackCompiler(); - if (privInfo_) - { - for (std::vector::iterator iter = secKeyVec->begin(); - iter != secKeyVec->end(); - iter++) - { - // Insertion of the dereferenced pointer results in NASet making - // a copy of the object, and then we delete the original. - routineSecKeySet_.insert(**iter); - delete *iter; - } - } + if (privStatus == STATUS_ERROR) + return; } else { - // get roles granted to current user - // SQL_EXEC_GetRoleList returns the list of roles from the CliContext - std::vector myRoles; - Int32 numRoles = 0; - Int32 *roleIDs = NULL; - if (SQL_EXEC_GetRoleList(numRoles, roleIDs) < 0) + // convert priv_desc (TrafPrivDesc) in privDescs_ member + privDescs_ = new (heap_) PrivMgrDescList(heap_); //initialize empty list + TrafDesc *priv_grantees_desc = priv_desc->privDesc()->privGrantees; + while (priv_grantees_desc) { - *CmpCommon::diags() << DgSqlCode(-1034); - return; - } + PrivMgrDesc *privs = new (heap_) PrivMgrDesc(priv_grantees_desc->privGranteeDesc()->grantee); + TrafDesc *objectPrivs = priv_grantees_desc->privGranteeDesc()->objectBitmap; + + PrivMgrCoreDesc objectDesc(objectPrivs->privBitmapDesc()->privBitmap, + objectPrivs->privBitmapDesc()->privWGOBitmap); - // At this time we should have at least one entry in roleIDs (PUBLIC_USER) - CMPASSERT (roleIDs && numRoles > 0); + TrafDesc *priv_grantee_desc = priv_grantees_desc->privGranteeDesc(); + TrafDesc *columnPrivs = priv_grantee_desc->privGranteeDesc()->columnBitmaps; + NAList columnDescs(NULL); + while (columnPrivs) + { + PrivMgrCoreDesc columnDesc(columnPrivs->privBitmapDesc()->privBitmap, + columnPrivs->privBitmapDesc()->privWGOBitmap, + columnPrivs->privBitmapDesc()->columnOrdinal); + columnDescs.insert(columnDesc); + columnPrivs = columnPrivs->next; + } - for (Int32 i = 0; i < numRoles; i++) - myRoles.push_back(roleIDs[i]); + privs->setTablePrivs(objectDesc); + privs->setColumnPrivs(columnDescs); + privs->setHasPublicPriv(ComUser::isPublicUserID(privs->getGrantee())); - privInfo_ = new (heap_) PrivMgrUserPrivs; - privInfo_->initUserPrivs(myRoles, priv_desc, ComUser::getCurrentUser(),objectUID_, routineSecKeySet_); + privDescs_->insert(privs); + priv_grantees_desc = priv_grantees_desc->next; + } } + + // get roles granted to current user + NAList roleIDs(heap_); + NAList grantees(heap_); + if (ComUser::getCurrentUserRoles(roleIDs, grantees) != 0) + return; + + // set up privileges for current user + privInfo_ = new (heap_) PrivMgrUserPrivs; + privInfo_->initUserPrivs(roleIDs, privDescs_, ComUser::getCurrentUser(), + objectUID_, &secKeySet_); } ULng32 NARoutineDBKey::hash() const http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/NARoutine.h ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/NARoutine.h b/core/sql/optimizer/NARoutine.h index 65aa473..0ffc83b 100644 --- a/core/sql/optimizer/NARoutine.h +++ b/core/sql/optimizer/NARoutine.h @@ -145,7 +145,7 @@ public: inline const ComString &getSignature() const { return signature_; } inline const ComObjectName &getLibrarySqlName() const { return librarySqlName_; } inline const QualifiedName &getSqlName() const { return name_; } - inline ComSecurityKeySet getSecKeySet() { return routineSecKeySet_ ; } + inline ComSecurityKeySet getSecKeySet() { return secKeySet_ ; } inline const Int64 getRoutineID() const { return objectUID_; } inline const Int32 getStateAreaSize() const { return stateAreaSize_; } inline const NAString &getDllName() const { return dllName_; } @@ -174,6 +174,7 @@ public: inline Int32 getActionPosition() const { return actionPosition_; } inline PrivMgrUserPrivs * getPrivInfo() const { return privInfo_; } + inline PrivMgrDescList * getPrivDescs() const { return privDescs_; } inline Int32 getObjectOwner() const { return objectOwner_; } inline Int32 getSchemaOwner() const { return schemaOwner_; } @@ -205,7 +206,9 @@ public: inline NABoolean hasResultSets() const { return (maxResults_ > 0); } - void getPrivileges(TrafDesc * priv_desc); + void setPrivInfo(PrivMgrUserPrivs *privInfo) { privInfo_ = privInfo; } + void setPrivDescs(PrivMgrDescList *privDescs) { privDescs_ = privDescs; } + void getPrivileges(TrafDesc * priv_desc, BindWA * bindWA); // ------------------------------------------------------------------- // Standard operators @@ -258,7 +261,6 @@ private: NABoolean isExtraCall_; NABoolean hasOutParams_; - ComSecurityKeySet routineSecKeySet_ ; Int64 objectUID_; NABoolean isUniversal_; @@ -283,7 +285,10 @@ private: COM_VERSION schemaVersionOfRoutine_; Int32 objectOwner_; Int32 schemaOwner_; + + PrivMgrDescList *privDescs_; PrivMgrUserPrivs *privInfo_; + ComSecurityKeySet secKeySet_ ; }; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/NATable.cpp ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/NATable.cpp b/core/sql/optimizer/NATable.cpp index 2d13bc2..0f282f6 100644 --- a/core/sql/optimizer/NATable.cpp +++ b/core/sql/optimizer/NATable.cpp @@ -4981,6 +4981,7 @@ NABoolean NATable::fetchObjectUIDForNativeTable(const CorrName& corrName, hiveTableId_(-1), tableDesc_(inTableDesc), privInfo_(NULL), + privDescs_(NULL), secKeySet_(heap), newColumns_(heap), snapshotName_(NULL), @@ -5713,6 +5714,7 @@ NATable::NATable(BindWA *bindWA, tableDesc_(NULL), secKeySet_(heap), privInfo_(NULL), + privDescs_(NULL), newColumns_(heap), snapshotName_(NULL), allColFams_(heap) @@ -6792,10 +6794,12 @@ void NATable::getPrivileges(TrafDesc * priv_desc) return; } + Int32 currentUser (ComUser::getCurrentUser()); + // Generally, if the current user is the object owner, then the automatically // have all privs. However, if this is a shared schema then views can be // owned by the current user but not have all privs - if (ComUser::getCurrentUser() == owner_ && objectType_ != COM_VIEW_OBJECT) + if (currentUser == owner_ && objectType_ != COM_VIEW_OBJECT) { privInfo_ = new(heap_) PrivMgrUserPrivs; privInfo_->setOwnerDefaultPrivs(); @@ -6805,46 +6809,94 @@ void NATable::getPrivileges(TrafDesc * priv_desc) ComSecurityKeySet secKeyVec(heap_); if (priv_desc == NULL) { - if (isHiveTable() || isHbaseCellTable() || - isHbaseRowTable() || isHbaseMapTable()) + if (!isSeabaseTable()) readPrivileges(); else + { privInfo_ = NULL; - return; + return; + } } else { // get roles granted to current user - // SQL_EXEC_GetRoleList returns the list of roles from the CliContext - std::vector myRoles; - Int32 numRoles = 0; - Int32 *roleIDs = NULL; - if (SQL_EXEC_GetRoleList(numRoles, roleIDs) < 0) - { - *CmpCommon::diags() << DgSqlCode(-1034); + NAList roleIDs(heap_); + if (ComUser::getCurrentUserRoles(roleIDs) != 0) return; - } + + Int32 numRoles = roleIDs.entries(); // At this time we should have at least one entry in roleIDs (PUBLIC_USER) - CMPASSERT (roleIDs && numRoles > 0); + CMPASSERT (numRoles > 0); + + // (PrivMgrUserPrivs) privInfo_ are privs for the current user + // (PrivMgrDescList) privDescs_ are all privs for the object + // (TrafPrivDesc) priv_desc are all object privs in TrafDesc form + // created by CmpSeabaseDDL::getSeabasePrivInfo + // before the NATable entry is constructed + // (ComSecurityKeySet) secKeySet_ are the qi keys for the current user + + // Convert priv_desc into a list of PrivMgrDesc (privDescs_) + privDescs_ = new (heap_) PrivMgrDescList(heap_); //initialize empty list + TrafDesc *priv_grantees_desc = priv_desc->privDesc()->privGrantees; + while (priv_grantees_desc) + { + PrivMgrDesc *privs = new (heap_) PrivMgrDesc(priv_grantees_desc->privGranteeDesc()->grantee); + TrafDesc *objectPrivs = priv_grantees_desc->privGranteeDesc()->objectBitmap; + PrivMgrCoreDesc objectDesc(objectPrivs->privBitmapDesc()->privBitmap, + objectPrivs->privBitmapDesc()->privWGOBitmap); + + TrafDesc *priv_grantee_desc = priv_grantees_desc->privGranteeDesc(); + TrafDesc *columnPrivs = priv_grantee_desc->privGranteeDesc()->columnBitmaps; + NAList columnDescs(heap_); + while (columnPrivs) + { + PrivMgrCoreDesc columnDesc(columnPrivs->privBitmapDesc()->privBitmap, + columnPrivs->privBitmapDesc()->privWGOBitmap, + columnPrivs->privBitmapDesc()->columnOrdinal); + columnDescs.insert(columnDesc); + columnPrivs = columnPrivs->next; + } - for (Int32 i = 0; i < numRoles; i++) - myRoles.push_back(roleIDs[i]); + privs->setTablePrivs(objectDesc); + privs->setColumnPrivs(columnDescs); - // Build privInfo_ based on the priv_desc - privInfo_ = new(heap_) PrivMgrUserPrivs; - privInfo_->initUserPrivs(myRoles, priv_desc, - ComUser::getCurrentUser(), - objectUID_.get_value(), secKeySet_); - } + privs->setHasPublicPriv(ComUser::isPublicUserID(privs->getGrantee())); + + privDescs_->insert(privs); + priv_grantees_desc = priv_grantees_desc->next; + } + // Generate privInfo_ and secKeySet_ for current user from privDescs_ + privInfo_ = new(heap_) PrivMgrUserPrivs; + privInfo_->initUserPrivs(roleIDs, + privDescs_, + currentUser, + objectUID_.get_value(), + &secKeySet_); - if (privInfo_ == NULL) + if (privInfo_ == NULL) { - *CmpCommon::diags() << DgSqlCode(-1034); + if (!CmpCommon::diags()->containsError(-1034)) + *CmpCommon::diags() << DgSqlCode(-1034); return; } + } + // log privileges enabled for table + Int32 len = 500; + char msg[len]; + std::string privDetails = privInfo_->print(); + snprintf(msg, len, "NATable::getPrivileges (list of all privileges on object), user: %s obj %s, %s", + ComUser::getCurrentUsername(), + qualifiedName_.getExtendedQualifiedNameAsString().data(), + privDetails.c_str()); + QRLogger::log(CAT_SQL_EXE, LL_DEBUG, "%s", msg); + if (getenv("DBUSER_DEBUG")) + { + printf("[DBUSER:%d] %s\n", (int) getpid(), msg); + fflush(stdout); + } } // Call privilege manager to get privileges and security keys @@ -6879,8 +6931,10 @@ void NATable::readPrivileges () std::vector secKeyVec; if (testError || (STATUS_GOOD != - privInterface.getPrivileges((NATable *)this, - ComUser::getCurrentUser(), *privInfo_, &secKeyVec))) + privInterface.getPrivileges((NATable *)this, + ComUser::getCurrentUser(), + *privInfo_, &secKeySet_))) + { if (testError) #ifndef NDEBUG http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/NATable.h ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/NATable.h b/core/sql/optimizer/NATable.h index 746142f..f28230c 100644 --- a/core/sql/optimizer/NATable.h +++ b/core/sql/optimizer/NATable.h @@ -679,8 +679,6 @@ public: NABoolean isToBeRemovedFromCacheBNC() const /* BNC = Before Next Compilation attempt */ { return( (flags_ & REMOVE_FROM_CACHE_BNC) != 0 ); } - ComSecurityKeySet getSecKeySet() { return secKeySet_ ; } - void setDroppableTable( NABoolean value ) { value ? flags_ |= DROPPABLE : flags_ &= ~DROPPABLE; } @@ -917,7 +915,12 @@ public: NAMemory* getHeap() const { return heap_; } NATableHeapType getHeapType() { return heapType_; } - PrivMgrUserPrivs* getPrivInfo() const { return privInfo_; } + // Privilege related operations + PrivMgrDescList *getPrivDescs() { return privDescs_; } + PrivMgrUserPrivs *getPrivInfo() const { return privInfo_; } + void setPrivInfo(PrivMgrUserPrivs *privInfo){ privInfo_ = privInfo; } + ComSecurityKeySet getSecKeySet() { return secKeySet_ ; } + void setSecKeySet(ComSecurityKeySet secKeySet) { secKeySet_ = secKeySet; } // Get the part of the row size that is computable with info we have available // without accessing HBase. The result is passed to estimateHBaseRowCount(), @@ -1208,8 +1211,6 @@ private: char *snapshotName_; - ComSecurityKeySet secKeySet_ ; - TrafDesc *partnsDesc_; TrafDesc *tableDesc_; @@ -1242,8 +1243,14 @@ private: Int32 hiveDefaultStringLen_; // in bytes Int32 hiveTableId_; - // Object containing info on all privileges the current user has for this table. - PrivMgrUserPrivs* privInfo_; + // Privilege information for the object + // privDescs_ is the list of all grants on the object + // privInfo_ are the privs for the current user + // secKeySet_ are the security keys for the current user + PrivMgrDescList *privDescs_; + PrivMgrUserPrivs *privInfo_; + ComSecurityKeySet secKeySet_ ; + // While creating the index keys, the NAColumn from colArray_ // is not used in all cases. Sometimes, a new NAColumn is // constructured from the NAColumn. The variable below http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/optimizer/RelMisc.h ---------------------------------------------------------------------- diff --git a/core/sql/optimizer/RelMisc.h b/core/sql/optimizer/RelMisc.h index 9275cac..6b03b21 100644 --- a/core/sql/optimizer/RelMisc.h +++ b/core/sql/optimizer/RelMisc.h @@ -364,7 +364,8 @@ public: NABoolean checkPrivileges(BindWA* bindWA); void findKeyAndInsertInOutputList( ComSecurityKeySet KeysForTab , const uint32_t userHashValue - , const PrivType which ); + , const PrivType which + , BindWA* bindWA ); //++ MVs NABoolean hasMvBindContext() const; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/regress/privs1/EXPECTED120 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs1/EXPECTED120 b/core/sql/regress/privs1/EXPECTED120 index 13d19fe..45713b9 100644 --- a/core/sql/regress/privs1/EXPECTED120 +++ b/core/sql/regress/privs1/EXPECTED120 @@ -583,11 +583,13 @@ End of MXCI Session >>-- AR - role involved, check query plans that rely on roles during revoke >>log; Query_Invalidation_Keys explain output for select_games, select_teams, insert_teams, update_teams, select_players, select_standings: -Query_Invalidation_Keys{,,OS}{,,UR} +Query_Invalidation_Keys{,,CS}{,, +UR}{,,CS}{, +,UR} Query_Invalidation_Keys{,,OS} Query_Invalidation_Keys{,,OI}{,,UR} Query_Invalidation_Keys{,,OS}{,, -OU}{,,UR} +CU}{,,UR} Query_Invalidation_Keys{,,OS} Query_Invalidation_Keys{,,OS}{,, OG}{,,UR} @@ -799,9 +801,13 @@ SQL_USER3 End of MXCI Session ->>-- still have privilege +>>-- still have privilege but recompile because of revoke on t120_role2 >>execute select_teams; +*** WARNING[8597] Statement was automatically retried 1 time(s). Delay before each retry was 0 seconds. See next entry for the error that caused this retry. + +*** WARNING[8734] Statement must be recompiled to allow privileges to be re-evaluated. + TEAM_NUMBER TEAM_NAME ----------- -------------------- @@ -1274,7 +1280,8 @@ End of MXCI Session --- SQL command prepared. >>log; Query_Invalidation_Keys explain output for select_stats: -Query_Invalidation_Keys{,,OS}{,,UZ} +Query_Invalidation_Keys{,,CS}{,, +UR}{,,UZ} >>shecho"Query_Invalidation_Keysexplainoutputforselect_stats:">>LOG; >> >>execute select_stats; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/regress/privs1/TEST120 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs1/TEST120 b/core/sql/regress/privs1/TEST120 index 384dee0..632202c 100755 --- a/core/sql/regress/privs1/TEST120 +++ b/core/sql/regress/privs1/TEST120 @@ -251,7 +251,7 @@ execute select_teams; -- revoke insert, delete privilege from t120role2 sh sqlci -i "TEST120(revoke_t120role2p)" -u sql_user3; --- still have privilege +-- still have privilege but recompile because of revoke on t120_role2 execute select_teams; -- no longer has privilege (4481) and query attempted recompilation execute insert_teams; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/regress/privs2/EXPECTED129 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs2/EXPECTED129 b/core/sql/regress/privs2/EXPECTED129 index c844a4a..d6ef9e6 100644 --- a/core/sql/regress/privs2/EXPECTED129 +++ b/core/sql/regress/privs2/EXPECTED129 @@ -222,6 +222,25 @@ CREATE TABLE TRAFODION.US4.T4 End of MXCI Session >>-- As user1, should fail +>>get privileges for user sql_user1; + +Privileges for User SQL_USER1 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +---U--- TRAFODION.US4.T1 +S------ TRAFODION.US4.T1 COL3 +S------ TRAFODION.US4.T129_A +S------ TRAFODION.US4.T129_STARTER +SI----- TRAFODION.US4.T2 +S------ TRAFODION.US4.V1 +-I-U--- TRAFODION.US4.V1 VC1 + +======================= + 9 row(s) returned + +--- SQL operation complete. >>select * from us4.t1 ; *** ERROR[4481] The user does not have SELECT privilege on table or view TRAFODION.US4.T1(columns: COL1, COL2). @@ -284,36 +303,43 @@ VC1 VC2 VC3 --- 1 row(s) inserted. >> ->>delete all from table(querycache()) ; - -*** ERROR[15001] A syntax error occurred at or before: -delete all from table(querycache()) ; - ^ (34 characters from start of SQL statement) - -*** ERROR[8822] The statement was not prepared. - ->>delete all from table(natablecache()); +>>delete all from table(querycache('user', 'local')) ; --- 0 row(s) deleted. ->>select * from table(querycacheentries()); - -*** ERROR[15001] A syntax error occurred at or before: -select * from table(querycacheentries()); - ^ (39 characters from start of SQL statement) - -*** ERROR[8822] The statement was not prepared. +>>select count(*) from table(querycacheentries('user', 'local')); ->>select * from table(natablecache()) ; +(EXPR) +-------------------- -*** ERROR[15001] A syntax error occurred at or before: -select * from table(natablecache()) ; - ^ (34 characters from start of SQL statement) + 0 -*** ERROR[8822] The statement was not prepared. +--- 1 row(s) selected. +>>delete all from table (natablecache()); +--- 0 row(s) deleted. +>>--select context, num_entries from table(natablecache('all','local')) ; >> >>log; >>-- As user1, should fail +>>get privileges for user sql_user1; + +Privileges for User SQL_USER1 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +---U--- TRAFODION.US4.T1 +S------ TRAFODION.US4.T1 COL3 +S------ TRAFODION.US4.T129_A +S------ TRAFODION.US4.T129_STARTER +SI----- TRAFODION.US4.T2 +S------ TRAFODION.US4.V1 +-I-U--- TRAFODION.US4.V1 VC1 + +======================= + 9 row(s) returned + +--- SQL operation complete. >>select * from us4.t1 ; *** ERROR[4481] The user does not have SELECT privilege on table or view TRAFODION.US4.T1(columns: COL1, COL2). @@ -381,36 +407,41 @@ VC1 VC2 VC3 --- 0 row(s) inserted. >> ->>delete all from table(querycache()) ; - -*** ERROR[15001] A syntax error occurred at or before: -delete all from table(querycache()) ; - ^ (34 characters from start of SQL statement) - -*** ERROR[8822] The statement was not prepared. - ->>delete all from table(natablecache()); +>>delete all from table(querycache('user', 'local')) ; --- 0 row(s) deleted. ->>select * from table(querycacheentries()); +>>select count(*) from table(querycacheentries('user', 'local')); -*** ERROR[15001] A syntax error occurred at or before: -select * from table(querycacheentries()); - ^ (39 characters from start of SQL statement) - -*** ERROR[8822] The statement was not prepared. - ->>select * from table(natablecache()) ; +(EXPR) +-------------------- -*** ERROR[15001] A syntax error occurred at or before: -select * from table(natablecache()) ; - ^ (34 characters from start of SQL statement) + 0 -*** ERROR[8822] The statement was not prepared. +--- 1 row(s) selected. +>>delete all from table (natablecache()); +--- 0 row(s) deleted. +>>--select context, num_entries from table(natablecache('all','local')) ; >> >>log; >>-- As user2, should fail +>>get privileges for user sql_user2; + +Privileges for User SQL_USER2 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +S------ TRAFODION.US4.T1 +---U--- TRAFODION.US4.T1 COL2 +---U--- TRAFODION.US4.T1 COL3 +SI----- TRAFODION.US4.T2 A +SI----- TRAFODION.US4.T2 B + +======================= + 7 row(s) returned + +--- SQL operation complete. >>delete from us4.t1 ; *** ERROR[4481] The user does not have DELETE privilege on table or view TRAFODION.US4.T1. @@ -460,6 +491,24 @@ COL1 COL2 COL3 --- 1 row(s) inserted. >>log; >>-- as user3 +>>get privileges for user sql_user3; + +Privileges for User SQL_USER3 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +S--U--- TRAFODION.US4.T1 COL1 +SI----- TRAFODION.US4.T2 A +S------ TRAFODION.US4.T3 B +S------ TRAFODION.US4.T3 D +S------ TRAFODION.US4.T4 F +S------ TRAFODION.US4.T4 G + +======================= + 8 row(s) returned + +--- SQL operation complete. >>insert into us4.t2(a,b) values (2,2) ; *** ERROR[4481] The user does not have SELECT privilege on table or view TRAFODION.US4.T2(columns: B). @@ -600,6 +649,24 @@ X >>-- Testing create view based on column-level SELECT >>-- as user3 >> +>>get privileges for user sql_user3; + +Privileges for User SQL_USER3 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +S--U--- TRAFODION.US4.T1 COL1 +SI----- TRAFODION.US4.T2 A +S------ TRAFODION.US4.T3 B +S------ TRAFODION.US4.T3 D +S------ TRAFODION.US4.T4 F +S------ TRAFODION.US4.T4 G + +======================= + 8 row(s) returned + +--- SQL operation complete. >>set schema cat.us4; --- SQL operation complete. @@ -782,6 +849,28 @@ X >>set schema us4; --- SQL operation complete. +>>get privileges for user sql_user4; + +Privileges for User SQL_USER4 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +SIDU-R- TRAFODION.US4.SB_HISTOGRAMS +SIDU-R- TRAFODION.US4.SB_HISTOGRAM_INTERVALS +SIDU-R- TRAFODION.US4.SB_PERSISTENT_SAMPLES +SIDU-R- TRAFODION.US4.T1 +SIDU-R- TRAFODION.US4.T129_A +SIDU-R- TRAFODION.US4.T129_STARTER +SIDU-R- TRAFODION.US4.T2 +SIDU-R- TRAFODION.US4.T3 +SIDU-R- TRAFODION.US4.T4 +SIDU-R- TRAFODION.US4.V1 + +======================= + 12 row(s) returned + +--- SQL operation complete. >> >>grant select (b,d) on t3 to sql_user3 with grant option; @@ -868,6 +957,25 @@ CREATE TABLE TRAFODION.US4.T3 End of MXCI Session >>-- as user1 +>>get privileges for user sql_user1; + +Privileges for User SQL_USER1 +============================= + +------E TRAFODION."_LIBMGR_".EVENT_LOG_READER +------E TRAFODION."_LIBMGR_".JDBC +---U--- TRAFODION.US4.T1 +S------ TRAFODION.US4.T1 COL3 +S------ TRAFODION.US4.T129_A +S------ TRAFODION.US4.T129_STARTER +SI----- TRAFODION.US4.T2 +S------ TRAFODION.US4.V1 +-I-U--- TRAFODION.US4.V1 VC1 + +======================= + 9 row(s) returned + +--- SQL operation complete. >> >>cqd query_cache '0' ; @@ -910,15 +1018,16 @@ End of MXCI Session --- SQL operation complete. >> ->>select case when current_cache_size > 0 then 1 else 0 end from table(natablecache()); +>>select case when current_cache_size > 0 then 1 else 0 end from table(natablecache('all', 'local')); -*** ERROR[15001] A syntax error occurred at or before: -select case when current_cache_size > 0 then 1 else 0 end from table(natablecac -he()); - ^ (83 characters from start of SQL statement) +(EXPR) +------ -*** ERROR[8822] The statement was not prepared. + 0 + 1 + 1 +--- 3 row(s) selected. >> >>--should error but place t129_a in natable cache >>prepare s1 from select * from us4.t129_a where c1 > 10; @@ -928,15 +1037,16 @@ he()); *** ERROR[8822] The statement was not prepared. >> ->>select case when current_cache_size > 0 then 1 else 0 end from table(natablecache()); +>>select case when current_cache_size > 0 then 1 else 0 end from table(natablecache('all', 'local')); -*** ERROR[15001] A syntax error occurred at or before: -select case when current_cache_size > 0 then 1 else 0 end from table(natablecac -he()); - ^ (83 characters from start of SQL statement) +(EXPR) +------ -*** ERROR[8822] The statement was not prepared. + 1 + 1 + 1 +--- 3 row(s) selected. >> >>sh sh runmxci.ksh -i "TEST129(grant1)" -u sql_user4; >>grant select on us4.t129_a to sql_user1 ; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/regress/privs2/TEST129 ---------------------------------------------------------------------- diff --git a/core/sql/regress/privs2/TEST129 b/core/sql/regress/privs2/TEST129 index 1cea5c2..9cbe511 100755 --- a/core/sql/regress/privs2/TEST129 +++ b/core/sql/regress/privs2/TEST129 @@ -32,7 +32,6 @@ sh sqlci -i "TEST129(step3)" -u sql_user3; sh sqlci -i "TEST129(step4)" -u sql_user3; sh sqlci -i "TEST129(step5)" -u sql_user4; sh sqlci -i "TEST129(step6)" -u sql_user4; -sh sqlci -i "TEST129(step7)" -u sql_user4; sh sqlci -i "TEST129(invalidate)" -u sql_user1; obey TEST129(clean_up); @@ -44,7 +43,6 @@ drop schema us4 cascade; ?section setup cqd SHOWDDL_DISPLAY_PRIVILEGE_GRANTS 'ON'; -cqd CAT_TEST_BOOL 'ON'; log LOG129 clear; log LOG129; create schema us4; @@ -123,9 +121,9 @@ insert into t3 values (1,2,3,4), (5,6,7,8); insert into t4 values (11,22,33,44), (55,66,77,88); ?section step1 -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- As user1, should fail +get privileges for user sql_user1; select * from us4.t1 ; delete from us4.t1; insert into us4.t1 values (1,1,1); @@ -140,17 +138,17 @@ insert into us4.t2 values (5,5,5); update us4.v1 set vc1 = vc1 ; insert into us4.v1(vc1) values (10) ; -delete all from table(querycache()) ; -delete all from table(natablecache()); -select * from table(querycacheentries()); -select * from table(natablecache()) ; +delete all from table(querycache('user', 'local')) ; +select count(*) from table(querycacheentries('user', 'local')); +delete all from table (natablecache()); +--select context, num_entries from table(natablecache('all','local')) ; log; ?section step2 -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- As user2, should fail +get privileges for user sql_user2; delete from us4.t1 ; insert into us4.t1 values (1,1,1); select * from us4.v1 ; @@ -164,9 +162,9 @@ insert into us4.t2(a,b) values (1,1); log; ?section step3 -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- as user3 +get privileges for user sql_user3; insert into us4.t2(a,b) values (2,2) ; update us4.t1 set col2 = col1; @@ -202,11 +200,11 @@ select * from us4.t1 ; log; ?section step4 -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- Testing create view based on column-level SELECT -- as user3 +get privileges for user sql_user3; set schema cat.us4; -- View on single table (positive): @@ -253,12 +251,12 @@ create view v34bh as select b,h from t3,t4; log; ?section step5 -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- Testing revoke for column-level SELECT -- as user4 set schema us4; +get privileges for user sql_user4; grant select (b,d) on t3 to sql_user3 with grant option; grant select (f,g) on t4 to sql_user3; @@ -278,8 +276,8 @@ revoke grant option for select (b) on t3 from sql_user3 cascade; showddl t3; ?section step6 -cqd CAT_TEST_BOOL 'ON'; set schema us4; +get privileges for user sql_user4; -- Testing other variations of column level @@ -306,9 +304,9 @@ revoke select (a) on t1 from sql_user5 cascade; showddl t1; ?section invalidate -cqd CAT_TEST_BOOL 'ON'; log LOG129; -- as user1 +get privileges for user sql_user1; cqd query_cache '0' ; cqd metadata_cache_size '0' ; @@ -325,12 +323,12 @@ prepare s1 from select * from us4.t129_a ; cqd metadata_cache_size reset ; -select case when current_cache_size > 0 then 1 else 0 end from table(natablecache()); +select case when current_cache_size > 0 then 1 else 0 end from table(natablecache('all', 'local')); --should error but place t129_a in natable cache prepare s1 from select * from us4.t129_a where c1 > 10; -select case when current_cache_size > 0 then 1 else 0 end from table(natablecache()); +select case when current_cache_size > 0 then 1 else 0 end from table(natablecache('all', 'local')); sh sh runmxci.ksh -i "TEST129(grant1)" -u sql_user4; @@ -421,22 +419,18 @@ log ; exit ; ?section revoke1 -cqd CAT_TEST_BOOL 'ON'; log LOG129; revoke select on us4.t129_a from sql_user1 ; ?section grant1 -cqd CAT_TEST_BOOL 'ON'; log LOG129; grant select on us4.t129_a to sql_user1 ; ?section grant2 -cqd CAT_TEST_BOOL 'ON'; log LOG129; grant select on us4.t129_a to sql_user2 ; ?section grant3 -cqd CAT_TEST_BOOL 'ON'; log LOG129; grant select on us4.t129_a to sql_user3 ; http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/sqlcomp/CmpSeabaseDDLauth.cpp ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/CmpSeabaseDDLauth.cpp b/core/sql/sqlcomp/CmpSeabaseDDLauth.cpp index 3c9939d..d4a2038 100644 --- a/core/sql/sqlcomp/CmpSeabaseDDLauth.cpp +++ b/core/sql/sqlcomp/CmpSeabaseDDLauth.cpp @@ -246,9 +246,24 @@ CmpSeabaseDDLauth::AuthStatus CmpSeabaseDDLauth::getAuthDetails(Int32 authID) } } +// ---------------------------------------------------------------------------- +// public method: getRoleIDs +// +// Return the list of roles that granted to the passed in authID +// +// Input: +// authID - the database authorization ID to search for +// +// Output: +// A returned parameter: +// STATUS_GOOD: list of roles returned +// STATUS_NOTFOUND: no roles were granted +// STATUS_ERROR: error was returned, diags area populated +// ---------------------------------------------------------------------------- CmpSeabaseDDLauth::AuthStatus CmpSeabaseDDLauth::getRoleIDs( const Int32 authID, - std::vector &roleIDs) + std::vector &roleIDs, + std::vector &grantees) { NAString privMgrMDLoc; CONCAT_CATSCH(privMgrMDLoc,systemCatalog_.data(),SEABASE_PRIVMGR_SCHEMA); @@ -257,11 +272,13 @@ CmpSeabaseDDLauth::AuthStatus CmpSeabaseDDLauth::getRoleIDs( std::string(privMgrMDLoc.data()), CmpCommon::diags()); std::vector roleNames; - std::vector roleDepths; + std::vector grantDepths; - if (role.fetchRolesForUser(authID,roleNames,roleIDs,roleDepths) == PrivStatus::STATUS_ERROR) + if (role.fetchRolesForAuth(authID,roleNames,roleIDs,grantDepths,grantees) == PrivStatus::STATUS_ERROR) return STATUS_ERROR; - return STATUS_GOOD; + + assert (roleIDs.size() == grantees.size()); + return STATUS_GOOD; } // ---------------------------------------------------------------------------- @@ -1820,16 +1837,15 @@ bool CmpSeabaseDDLrole::describe( std::vector granteeNames; std::vector grantDepths; std::vector grantorIDs; - - PrivStatus privStatus = PrivStatus::STATUS_GOOD; - - privStatus = roles.fetchUsersForRole(getAuthID(),granteeNames, - grantorIDs,grantDepths); - - // If no users were granted this role, nothing to do. + + + PrivStatus privStatus = roles.fetchGranteesForRole(getAuthID() ,granteeNames, + grantorIDs,grantDepths); + + // If nobody was granted this role, nothing to do. if (privStatus == PrivStatus::STATUS_NOTFOUND || granteeNames.size() == 0) return true; - + if (privStatus == PrivStatus::STATUS_ERROR) SEABASEDDL_INTERNAL_ERROR("Could not fetch users granted role."); http://git-wip-us.apache.org/repos/asf/trafodion/blob/adf2b8f2/core/sql/sqlcomp/CmpSeabaseDDLauth.h ---------------------------------------------------------------------- diff --git a/core/sql/sqlcomp/CmpSeabaseDDLauth.h b/core/sql/sqlcomp/CmpSeabaseDDLauth.h index fbfe354..d451fb7 100644 --- a/core/sql/sqlcomp/CmpSeabaseDDLauth.h +++ b/core/sql/sqlcomp/CmpSeabaseDDLauth.h @@ -78,7 +78,8 @@ class CmpSeabaseDDLauth virtual bool describe (const NAString &authName, NAString &authText); AuthStatus getRoleIDs (const Int32 authID, - std::vector &roleIDs); + std::vector &roleIDs, + std::vector &granteeIDs); NAString getObjectName (const std::vector objectUIDs); // accessors