Add explicit CREATE TABLE permission check for table designer (#2128)

This commit is contained in:
Hai Cao
2023-07-06 16:19:50 -07:00
committed by GitHub
parent 11f632aaa9
commit b9277c3830
5 changed files with 101 additions and 1 deletions

View File

@@ -12916,6 +12916,16 @@ namespace Microsoft.SqlTools.ServiceLayer
return Keys.GetString(Keys.NonClusteredColumnStoreIndexMustHaveColumnsRuleDescription, indexName); return Keys.GetString(Keys.NonClusteredColumnStoreIndexMustHaveColumnsRuleDescription, indexName);
} }
public static string TableDesignerCreateTablePermissionDenied(string db)
{
return Keys.GetString(Keys.TableDesignerCreateTablePermissionDenied, db);
}
public static string TableDesignerAlterTablePermissionDenied(string table)
{
return Keys.GetString(Keys.TableDesignerAlterTablePermissionDenied, table);
}
public static string SqlProjectModelNotFound(string projectUri) public static string SqlProjectModelNotFound(string projectUri)
{ {
return Keys.GetString(Keys.SqlProjectModelNotFound, projectUri); return Keys.GetString(Keys.SqlProjectModelNotFound, projectUri);
@@ -16871,6 +16881,12 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string TableDesignerConfirmationText = "TableDesignerConfirmationText"; public const string TableDesignerConfirmationText = "TableDesignerConfirmationText";
public const string TableDesignerCreateTablePermissionDenied = "TableDesignerCreateTablePermissionDenied";
public const string TableDesignerAlterTablePermissionDenied = "TableDesignerAlterTablePermissionDenied";
public const string SqlProjectModelNotFound = "SqlProjectModelNotFound"; public const string SqlProjectModelNotFound = "SqlProjectModelNotFound";

View File

@@ -5440,6 +5440,16 @@ The Query Processor estimates that implementing the following index could improv
<value>I have read the summary and understand the potential risks.</value> <value>I have read the summary and understand the potential risks.</value>
<comment></comment> <comment></comment>
</data> </data>
<data name="TableDesignerCreateTablePermissionDenied" xml:space="preserve">
<value>CREATE TABLE permission denied in database &apos;{0}&apos;.</value>
<comment>.
Parameters: 0 - db (string) </comment>
</data>
<data name="TableDesignerAlterTablePermissionDenied" xml:space="preserve">
<value>ALTER TABLE permission denied for table &apos;{0}&apos;.</value>
<comment>.
Parameters: 0 - table (string) </comment>
</data>
<data name="SqlProjectModelNotFound" xml:space="preserve"> <data name="SqlProjectModelNotFound" xml:space="preserve">
<value>Could not find SQL model from project: {0}.</value> <value>Could not find SQL model from project: {0}.</value>
<comment>. <comment>.

View File

@@ -2451,6 +2451,8 @@ HashIndexMustHaveBucketCountRuleDescription(string indexName) = Hash index '{0}'
ColumnCanOnlyAppearOnceInNonClusteredColumnStoreIndexRuleDescription(string columnName, string indexName, int rowNumber) = Column with name '{0}' has already been added to the non-clustered columnstore index '{1}'. Row number: {2}. ColumnCanOnlyAppearOnceInNonClusteredColumnStoreIndexRuleDescription(string columnName, string indexName, int rowNumber) = Column with name '{0}' has already been added to the non-clustered columnstore index '{1}'. Row number: {2}.
NonClusteredColumnStoreIndexMustHaveColumnsRuleDescription(string indexName) = Non-clustered columnstore index '{0}' does not have any columns associated with it. NonClusteredColumnStoreIndexMustHaveColumnsRuleDescription(string indexName) = Non-clustered columnstore index '{0}' does not have any columns associated with it.
TableDesignerConfirmationText = I have read the summary and understand the potential risks. TableDesignerConfirmationText = I have read the summary and understand the potential risks.
TableDesignerCreateTablePermissionDenied(string db) = CREATE TABLE permission denied in database '{0}'.
TableDesignerAlterTablePermissionDenied(string table) = ALTER TABLE permission denied for table '{0}'.
############################################################################ ############################################################################
# TSql Model # TSql Model

View File

@@ -8321,6 +8321,17 @@ The Query Processor estimates that implementing the following index could improv
<target state="new">None</target> <target state="new">None</target>
<note></note> <note></note>
</trans-unit> </trans-unit>
<trans-unit id="TableDesignerCreateTablePermissionDenied">
<source>CREATE TABLE permission denied in database '{0}'.</source>
<target state="new">CREATE TABLE permission denied in database '{0}'.</target>
<note></note>
</trans-unit>
<trans-unit id="TableDesignerAlterTablePermissionDenied">
<source>ALTER TABLE permission denied for table '{0}'.</source>
<target state="new">ALTER TABLE permission denied for table '{0}'.</target>
<note>.
Parameters: 0 - table (string) </note>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@@ -18,6 +18,7 @@ using Dac = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner;
using STSHost = Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost; using STSHost = Microsoft.SqlTools.ServiceLayer.Hosting.ServiceHost;
using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
namespace Microsoft.SqlTools.ServiceLayer.TableDesigner namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
{ {
@@ -31,6 +32,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
private Dictionary<string, Dac.TableDesigner> idTableMap = new Dictionary<string, Dac.TableDesigner>(); private Dictionary<string, Dac.TableDesigner> idTableMap = new Dictionary<string, Dac.TableDesigner>();
private bool disposed = false; private bool disposed = false;
private static readonly Lazy<TableDesignerService> instance = new Lazy<TableDesignerService>(() => new TableDesignerService()); private static readonly Lazy<TableDesignerService> instance = new Lazy<TableDesignerService>(() => new TableDesignerService());
private const string CheckCreateTablePermissionInDbQuery = "SELECT HAS_PERMS_BY_NAME(QUOTENAME(@dbname), 'DATABASE', 'CREATE TABLE')";
private const string CheckAlterTablePermissionQuery = "SELECT HAS_PERMS_BY_NAME(QUOTENAME(@schema) + '.' + QUOTENAME(@table), 'OBJECT', 'ALTER')";
public TableDesignerService() public TableDesignerService()
{ {
@@ -1807,7 +1810,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
// Set Access Token only when authentication mode is not specified. // Set Access Token only when authentication mode is not specified.
var accessToken = connectionStringBuilder.Authentication == SqlAuthenticationMethod.NotSpecified var accessToken = connectionStringBuilder.Authentication == SqlAuthenticationMethod.NotSpecified
? tableInfo.AccessToken : null; ? tableInfo.AccessToken : null;
tableDesigner = new Dac.TableDesigner(connectionString, accessToken, tableInfo.Schema, tableInfo.Name, tableInfo.IsNewTable, tableDesignerOptions);
try
{
tableDesigner = new Dac.TableDesigner(connectionString, accessToken, tableInfo.Schema, tableInfo.Name, tableInfo.IsNewTable, tableDesignerOptions);
}
catch (Exception ex)
{
CheckPermissions(tableInfo, connectionString);
throw ex;
}
} }
else else
{ {
@@ -1855,6 +1867,55 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner
return metadata; return metadata;
} }
private void CheckPermissions(TableInfo tableInfo, string connectionString)
{
CheckCreateAlterTablePermission(tableInfo, connectionString);
}
private void CheckCreateAlterTablePermission(TableInfo tableInfo, string connectionString)
{
if (tableInfo.IsNewTable)
{
ReliableConnectionHelper.ExecuteReader(connectionString, CheckCreateTablePermissionInDbQuery, (reader) =>
{
reader.Read();
if (reader.IsDBNull(0) || (int)reader[0] != 1)
{
throw new Exception(SR.TableDesignerCreateTablePermissionDenied(tableInfo.Database));
}
}, (cmd) =>
{
var dbNameParameter = cmd.CreateParameter();
dbNameParameter.ParameterName = "@dbname";
dbNameParameter.Value = tableInfo.Database;
cmd.Parameters.Add(dbNameParameter);
});
}
else
{
ReliableConnectionHelper.ExecuteReader(connectionString, CheckAlterTablePermissionQuery, (reader) =>
{
reader.Read();
if (reader.IsDBNull(0) || (int)reader[0] != 1)
{
throw new Exception(SR.TableDesignerAlterTablePermissionDenied(tableInfo.Name));
}
}, (cmd) =>
{
var schemaParameter = cmd.CreateParameter();
schemaParameter.ParameterName = "@schema";
schemaParameter.Value = tableInfo.Schema;
cmd.Parameters.Add(schemaParameter);
var tableParameter = cmd.CreateParameter();
tableParameter.ParameterName = "@table";
tableParameter.Value = tableInfo.Name;
cmd.Parameters.Add(tableParameter);
});
}
}
/// <summary> /// <summary>
/// Disposes the table designer Service /// Disposes the table designer Service
/// </summary> /// </summary>