Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
Kristen
Test
22859 Posts |
Posted - 2012-01-05 : 06:21:42
|
We have Sprocs in our application that are the same for all Clients. They basically do some sort of SELECT, and then the application does a REPLACE on TAGs in a CMS template to produce the HTML output.So a CMS template might look like:Your account: {A_Col1}Your name: {A_Col2}Your billing address: {B1_B_Col1}Your delivery address: {B2_B_Col1} What that means , in practice, is that each Sproc provides all columns, in the SELECT, that any client MIGHT want. If we then we get a request for an additional column (usually from a table that is already in the query), we add that to the SProc SELECT and then ALL clients will include that in their query (whether it is used in their CMS or not).I'm thinking I should make these queries "configurable" to improve efficiency (reduce the number of columns, and thus the amount of data / bandwidth between SQL and Web servers). That would also allow adding of additional columns (from within tables already in the Query) without any further programming I'm looking for learned-opinion / advice on best way to handle this please.Lets say I haveSELECT A_Col1, A_Col2, B1.B_Col1 AS [B1_B_Col1], B2.B_Col1 AS [B2_B_Col1]FROM TableA AS A JOIN TableB AS B1 ON B1.ID = A.ID_B1 JOIN TableB AS B2 ON B2.ID = A.ID_B2WHERE A.ColN = @ParamNORDER BY A_Col1, B1.B_Col2, B2.B_Col3 and lets assume that I have the SELECT LIST "A_Col1, A_Col2, B1.B_Col1 AS [B1_B_Col1], B2.B_Col1 AS [B2_B_Col1]" in some configuration object.I could lookup the SELECT LIST within the Sproc. That's an additional lookup every time the Sproc runs, so (in such circumstances) I am more inclined to have the Web Server send that along with the other parameters when it executes the Sproc (the Web Server can cache it in memory, and has more spare CPU than our SQL boxes).So I now want to convert the SQL to be dynamic? Best way to do that? Use sp_ExecuteSQL?SELECT @strSQL = 'SELECT ' + @SelectList + 'FROM TableA AS A JOIN TableB AS B1 ON B1.ID = A.ID_B1 JOIN TableB AS B2 ON B2.ID = A.ID_B2WHERE A.ColN = @ParamNORDER BY A_Col1, B1.B_Col2, B2.B_Col3'EXEC sp_ExecuteSQL @strSQL, N'@ParamN int', @ParamN but I need to do something with permissions as the User will not have SELECT permission on the tables, only EXECUTE on this Sproc, so I need to execute AS the same user that created / owns the SProc (or some other pseudo-user set up specifically for this purpose)I don't suppose creating the Sproc asCREATE PROCEDURE dbo.MySprocWITH EXECUTE AS OWNERAS... will solve this? BoL says "[as OWNER] specifies the statements inside the module executes in the context of the current owner of the module. If the module does not have a specified owner, the owner of the schema of the module is used. OWNER cannot be specified for DDL or logon triggers."; Dunno if my assumption is correct, but BoL does NOT explicitly say this is the default, so I assume this is something extra to an Sproc having runtime table permissions equivalent to the logon that created it?The EXECUTE AS syntax is BoL does not seem to include Sprocs calls  EXEC | EXECUTE } ( { @string_variable | [ N ]'tsql_string' } [ + ...n ] ) [ AS { LOGIN | USER } = ' name ' ] so I'm not sure I could use EXECUTE AS to execute the sp_ExecuteSQL ??One thought that occurs to me is that using sp_ExecuteSQL I will have to be careful to keep the @ParamN definition in step with the definition in the CREATE SPROC parameter list - thus a window-of-opportunity for a cock-up there (unless I start including all that in the dynamic parameters too ??)Any other bright ideas / suggests / experiences would be appreciated before I start Klutzing around and wasting a whole lot of time down blind alleys! |
|
Bustaz Kool
Master Smack Fu Yak Hacker
1834 Posts |
Posted - 2012-01-05 : 12:22:45
|
I worked one place where we did simple string substitutions in the sproc script when deploying to production. If every client is in a separate database, you could apply your logic at deployment time to substitute the proper column list into your SELECT statement. You would end up with "different" stored procedures but they would all be based on the same script.Just a thought...=================================================Men shout to avoid listening to one another. -Miguel de Unamuno |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-05 : 12:59:32
|
Its a good thought, thanks. Means "rebuilding" an Sproc each time the SELECT list is modified (during BUILD of the Client's site) ...I could have some markers in the SProc to indicate where substitution should take place (rather than a {SELECT_LIST_HERE} type tag, so this perhaps:SELECT--{SELECT_LIST_START} A_Col1, A_Col2, B1.B_Col1 AS [B1_B_Col1], B2.B_Col1 AS [B2_B_Col1]--{SELECT_LIST_END}FROM TableA AS A JOIN TableB AS B1 ON B1.ID = A.ID_B1 JOIN TableB AS B2 ON B2.ID = A.ID_B2WHERE A.ColN = @ParamNORDER BY A_Col1, B1.B_Col2, B2.B_Col3 so it would work out-of-the-box (and during BUILD Phase perhaps), and then "optimised" when BUILD was done by substituting between the markers |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-05 : 13:01:12
|
I've been trying an sp_ExecuteSQL solution today ... first issue is that Syntax Errors in the SQL are harder to debug. Error is "Error at line 999" which is relative to the sp_ExecuteSQL SQL, rather than the Sproc, and if you have more than one sp_ExecuteSQL in an Sproc then its harder to know which is causing the problem ... |
 |
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2012-01-05 : 13:25:01
|
We used a configuration table. you could use an xml as parm as well. with a configuration table you do not change the sproc every time use requests a change. more scalabale?If you don't have the passion to help people, you have no passion |
 |
|
X002548
Not Just a Number
15586 Posts |
Posted - 2012-01-05 : 13:32:36
|
My first thought is...are you new here ;-)my second is, what's the point of security if the users don't have permission?I'm not sure I follow, but if the "app" is set up using a connecting pooling id, why are you were about the users...or are they connecting as individuals, and if they are, how are they getting in? Public? You manage all the users manually?Can the users "store" their "templates" of requests in a table?Can you build a View on the fly and then just execute that with a view name of something unique to the user (as stored in the config table)?I need to take a shower nowBrett8-)Hint: Want your questions answered fast? Follow the direction in this linkhttp://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspxWant to help yourself?http://msdn.microsoft.com/en-us/library/ms130214.aspxhttp://weblogs.sqlteam.com/brettk/http://brettkaiser.blogspot.com/ |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-05 : 13:57:16
|
APP connects as a specific user (probably not a user, whatever the thing is called ... but all Users connect via the APP using a single login, permission-wise. That login is only granted SPROC Execute."Can the users "store" their "templates" of requests in a table?"Currently it is Client-specific, rather than per-user. A Client has their own database, so its only really a question of code-management and deployment. We do not want to have clients on bespoke code variants (we aren't geared up to supporting that), but equally I don't want to have SELECT statements pulling Columns that are not used (which is what we have at present, as all Clients have identical SELECT statements, regardless of whether their implementation actually uses the column)"Can you build a View on the fly and then just execute that with a view name of something unique to the user (as stored in the config table)?"That's a Dandy idea thanks. My guess is that there will be some complex queries where the interaction of Parameters and Query will make use of a VIEW less than ideal, but on 99% of cases that is likely to be workable |
 |
|
X002548
Not Just a Number
15586 Posts |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-05 : 17:28:29
|
quote: Originally posted by X002548 In any Case, that connection ID (SQL Server security right) is going to HAVE to have read access to the tables
I haven'/t tried it yet, but I'm figuring that I can run any Dynamic SQL using either an explicit EXECUTE AS or using a CERTIFICATE:CREATE CERTIFICATECREATE USER based on the CERTIFICATE (i.e. a user with no actual Logon)GRANT SELECT ON tables TO my CertificateUserADD SIGNATURE TO MySprocFingers crossed eh?!! |
 |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-06 : 10:59:59
|
I seem to be OK with the follow approach to giving "controlled permission" to Dynamic SQL within an SProc:CREATE PROCEDURE MySproc @ParamN intWITH EXECUTE AS 'MyUser'AS SELECT @strSQL = 'SELECT ' + @SelectList + ' FROM TableA AS A JOIN TableB AS B1 ON B1.ID = A.ID_B1 JOIN TableB AS B2 ON B2.ID = A.ID_B2 WHERE A.ColN = @ParamN ORDER BY A_Col1, B1.B_Col2, B2.B_Col3' EXEC sp_ExecuteSQL @strSQL, N'@ParamN int', @ParamN where I have created MyUser as follows:CREATE LOGIN MyUser WITH PASSWORD = 'MyPassword'GOUSE MyDatabaseGOCREATE USER MyUser FOR LOGIN MyUserGO EXEC sp_addrolemember 'MyRole', 'MyUser'EXEC sp_addrolemember 'db_datareader', 'MyUser'EXEC sp_addrolemember 'db_datawriter', 'MyUser' The role "MyRole" is used, only, to grant EXECUTE permission on all appropriate Sprocs and FunctionsI could (I think) also, and probably more securely, skip creating the LOGIN and just create the user within the database usingCREATE USER MyUser WITHOUT LOGIN however that does not allow me to login, using the MyUser LOGIN/PASSWORD, from QA/SSMS which (I think) makes testing SQL Code snippets more difficult as I find it handy to execute them with the same user permissions that the Application will get.Perhaps I should trying have "MyUserEXEC" *WITHOUT LOGIN) and "MyUserTest" (WIth normal LOGIN) and see if using "MyUserTest", both set to use the same "MyRole", when I do actually need to run SQL code snippets under the target permissions. I could then avoid having that user on the production system.One side-effect. In the past we have not needed to explicitly GRANT EXECUTE ON MyFunction TO MyRole - presumably because the context that the Sproc was running in had permission to all functions. However, when the function is now in Dynamic SQL it does need explicitly EXECUTE permission. That's not a great hardship,a nd is probably "tider" than what we had beforeQuestion: Do you think there is any disadvantage havingWITH EXECUTE AS 'MyUser' on ALL my Sprocs (even if they do not, yet, have any dynamic SQL)? If I start putting it into the core-templates we use it will start to be included regardless of whether the Sproc has Dynamic SQL or not, and I don't want to do that if there might be a perfromance disadvantage or somesuch |
 |
|
X002548
Not Just a Number
15586 Posts |
|
Kristen
Test
22859 Posts |
Posted - 2012-01-06 : 12:23:56
|
So I can have dynamic SQL in Sproc but only GRANT EXECUTE to the user that that Application connects as.Apart from [the one-time activity of] creating the Pseudo User, I only need to modify Sprocs in two ways:1. Add WITH EXECUTE AS 'MyUser'2. Add GRANT EXECUTE ON MySproc TO MyRole (which we already have in the scripts for all Sprocs so, for me, that is not an additional action) |
 |
|
|
|
|
|
|