How to implement role-based security in T-SQL? - security

I am developing a stored proc for an SSRS 2008 report, but I want to limit the data output according to the role of the user running the report. How do I do this? What I wanted to do was to retrieve the Windows user name and filter the records based on this, but users are using the "sa" account to login to the server. So now I'm thinking I should use the AD login instead.
I've also seen how security can be setup in SSRS instead of the T-SQL sproc so that users have access to appropriate folders. But this second approach sounds much more cumbersome since we have many different reports and because I want users to have access to all reports, but just access to different parts of the data.
Is it better to implement security via SSRS groups and folders on the report server or else inside the T-SQL sproc?
I looked at that link for the "(=User.UserID)" solution, but am having trouble implementing this. What I did: I created a dataset in SSRS by selecting the text query:
select people_id from people_rv where last_name like 'd%'
This returns a list of people_id's
Then, I created a new parameter and set it equal to the above dataset for available values. And I made it Text datatype and allow Null and Blank values. No default values. Finally, I set visibility for the tablix:
=iif(Parameters!staff_id.Value in (select people_id from users),1,0)
But this generates an error. How can I reformulate this tablix expression?

Regardless of the method used to access the data source you can still retrieve the user ID (=User.UserID) that is accessing the report. Set this to an internal parameter in SSRS, and you can then incorporate security into your queries very easily.
Check out the answer to this question submitted a few minutes after yours.
More specific details of implementation using BIDS and SSRS 2008R2 (2008 should be identical)
Create a parameter, let's call it "UserID". Type should be Text, and parameter visibility should be "Internal"
The Default value for this parameter should be set to Specify Values, and add a value: =User.UserID
As a temporary debugging aid, drag the parameter to your design surface to create a textbox with the value of the UserID. (Preview the report and see that this is getting set to your user ID if you'd like to confirm.)
Create a dataset for your next parameter: Create a dataset that will only list available values for this user. The query might be something like:
SELECT
CategoryName,
CategoryID
FROM
Categories c
INNER JOIN
CategoryPermissions cp
ON c.ID = cp.CategoryID
INNER JOIN
Users u
ON cp.UserID = u.People_ID
WHERE u.WindowsAccount = #UserID
Set up a parameter that you will display to the user. It should get its available values from the query in the previous step.
Set up your main dataset. It should both use the value of the parameter from step 5 as well as the permissions query from step 4. Something like:
SELECT
*
FROM
Products p
INNER JOIN
Categories c
ON p.CategoryID = c.ID
INNER JOIN
CategoryPermissions cp
ON c.ID = cp.CategoryID
INNER JOIN
Users u
ON cp.UserID = u.People_ID
WHERE u.WindowsAccount = #UserID
AND c.CategoryName in ( #Categories )
(This double checks that the user has the permission to see this category.)

Related

How to get the view definition in SQL server using NodeJS through code

I am having a requirement where I need to change the definition of view based on the user requirement.
Suppose if the definition of the view is like this:
create view view_name as select tableA.col_3 as colTabA3 from tableA ,tableB where 1=1;
now if the user has a requirement such that colTabA3 column should have the data from tableB.col_3 then I need to change the view definition to
create view view_name as select tableB.col_3 as colTabA3 from tableA ,tableB where 1=1;
I am going to show some UI to the user to give the expression for colTabA3 and when he gives the expression then I will have to get the definition of the table, modify that definition and add the new expression.
SELECT OBJECT_DEFINITION (OBJECT_ID('${view_name}')) AS ObjectDefinition;
this query is giving the view definition, I can connect to the database through code and run this query to get the view definition.

how do i correctly set up a parameterized information link in spotfire?

Also posted on super users:
I'm a spotfire novice trying to create a parameterized info link. Ultimate goal is to create a default template that may be customized to return specific rows in a very large table. I've not been able to cobble together enough information from online searches to get me from point A to Z.
Spotfire version is 7.11 on an Oracle 11.2 SE DB.
Currently I've got a date/time prompt in the info link that will be global to all users. What I need is to be able to further filter to 1 of 2 columns (one is real, the other a string) in order to minimize loading times. There are 17 other on-demand tables that are related to the main one. Limiting the initial query will greatly speed up performance.
In information designer for the information link, if I edit the SQL in the WHERE and explicitly define the value or string for the column, I get the rows I want. When I try to define it using an input parameter (?ParamName), I either get nothing when I reload or get asked to input a parameter "for testing".
Q1: In the document properties for the analysis, I've been adding in properties that I assume is supposed to get picked up by the query.
- What part do scripts play in passing this variable to the SQL?
- Do I just need to define a value for a property name or include a IronPython script? - If script is required, can I just define the parameter to pass?
Q2: In the info link SQL, what is the correct syntax for defining the parameter variable depending on the type (real v string)? If I use a string, I need to include LIKE in order to pick up the desired rows. If I use a real, is it possible to define it as a list of values?
Thanks in advance.
Though not exactly clear from your description, I think you should be able to accomplish your goals using the "Load on demand" dialog that is accessed either when you add your data table to your analysis, or subsequently using the Data Table Properties>Type of Data>Settings dialog.
Spotfire uses this dialog to dynamically modify your SQL. Thus, you do not need to explicitly include the LIKE statement in your SQL. Spotfire will add it in based on what you define in the On-Demand settings. For example, you could have an Input Field where you type a constraint that will be stored as a Document Property and then refer to that Document Property in your On-Demand settings to control the table loading.

Order By not working in Azure Web Document Explorer

I am trying to query documentdb inside the Azure Web Document Explorer. The problem is Order By doesn't seem to work anymore.
For instance the following query:
SELECT * FROM c
WHERE c.type="myType" ORDER BY c.createdDate
When queried I get a red alert stating:
Failed to get documents. Please try again.
If I remove Order By it works fine.
Any idea why it doesn't work anymore to query with Order By?
Any idea why it doesn't work anymore to query with Order By?
Order By can be specified only against a property, either numeric or String when it is range indexed with the Maximum Precision (-1). More detail please refer to document
You also cannot perform the following:
Order By with internal string properties like id, _rid, and _self (coming soon).
Order By with properties derived from the result of an intra-document join (coming soon).
Order By multiple properties (coming soon).
Order By with queries on databases, collections, users, permissions or attachments (coming soon).
Order By with computed properties e.g. the result of an expression or a UDF/built-in function

Maximo: show last status memo for current work order

In Maximo, I want to retrieve the most recent status memo and add the WOSTATUS.MEMO field to Work Order Tracking Module via Application Designer. In the Work Order Tracking application, to see the same information, you'd go to an individual Work Order > Select Action > View > Work Order History.
You may have noticed the WOSTATUS relationship on the WORKORDER object and found that you can't control which of the many WOSTATUS records for this work order gets chosen for showing the memo. You'll need to make a copy of this relationship which specifically finds the latest record. To find that latest record, you could go for the WOSTATUS record with the CHANGEDATE matching the STATUSDATE on the work order or with the highest WOSTATUSID. Assuming you go for the former, because it doesn't require a subquery, you'll create a new relationship from WORKORDER to WOSTATUS called LASTSTATUS with a where clause like this:
wonum = :wonum and siteid = :siteid
and status = :status and changedate = :statusdate
You can then use the standard Relationship.Attribute syntax for the Attribute property of a Textbox in App Designer: LASTSTATUS.MEMO.
In case you were interested, here's the where clause you would use if you wanted to go for the WOSTATUSID instead:
wonum = :wonum and siteid = :siteid
and wostatusid = (
select max(wostatusid)
from wostatus
where wonum = :wonum and siteid = :siteid
)
(Some may argue the toss about whether the first line in the above query is needed. I would respond with the suggestion to test for performance / optimal execution plan in your database environment.)
I hope that helps.

Sharepoint: SQL to find all documents created/edited by a user

I am looking for a query that will work on Sharepoint 2003 to show me all the documents created/touched by a given userID.
I have found tables with the documents (Docs) and tables for users (UserInfo, UserData)
but the relationship between seems a bit odd - there are 99,000 records in our userdata table, and 12,000 records in userinfo - we have 400 users!
I suppose I was expecting a simple 1 to many relationship with a user table having 400 records and joining that to the documents table, but I see thats not the case.
Any help would be appreciated.
Edit:
Thanks Bjorn,
I have translated that query back to the Sharepoint 2003 structure:
select
d.* from
userinfo u join userdata d
on u.tp_siteid = d.tp_siteid
and
u.tp_id = d.tp_author
where
u.tp_login = 'userid'
and
d.tp_iscurrent = 1
This gets me a list of siteid/listid/tp_id's I'll have to see if I can trace those back to a filename / path.
All: any additional help is still appreciated!
I've never looked at the database in SharePoint 2003, but in 2007 UserInfo is connected to Sites, which means that every user has a row in UserInfo for each site collection (or the equivalent 2003 concept). So to identify what a user does you need both the site id and the user's id within that site. In 2007, I would begin with something like this:
select d.* from userinfo u
join alluserdata d on u.tp_siteid = d.tp_siteid
and u.tp_id = d.tp_author
where u.tp_login = '[username]'
and d.tp_iscurrentversion = 1
Update: As others write here, it is not recommended to go directly into the SharePoint database, but I would say use your head and be careful. Updates are an all-caps no-no, but selects depends on the context.
DO NOT QUERY THE SHAREPOINT DATABASE DIRECTLY!
I wonder if I made that clear enough? :)
You really need to look at the object model available in C#, you will need to get an SPSite instance for a SiteCollection, and then iterate over the SPList instances that belong to the SPSite and the SPWeb objects.
Once you have the SPList object, you will need to call GetListItems using a query that filters for the user you want.
That is the supported way of doing what you want.
You should never go to the database directly as SharePoint isn't designed for that at all and there is no guarantee (actually, there's a specific warning) that the structure of the database will be the same between versions and upgrades, and additionally when content is spread over several content databases in a farm there is no guarantee that a query that runs on one content database will do what you expect on another content database.
When you look at the object model for iteration, also note that you will need to dispose() the SPSite and SPWeb objects that you create.
Oh, and yes you may have 400 users, but I would bet that you have 30 sites. The information is repeated in the database per site... 30 x 400 = 12,000 entries in the database.
If you are going to use that query in Sharepoint you should know that creating views on the content database or quering directly against the database seems to be a big No-No. A workaround could be some custom code that iterates through the object model and writes the results to your own database. This could either be timer based or based on an eventtrigger.
You really shouldn't be doing SELECTs with Locks either i.e. adding WITH (NOLOCK) to your queries. Some parts of the system are very timeout sensitive and if you start introducing locks that the system wasn't expecting you can see the system freak out.
But really, you should be doing this via the object model. Mess around with something like IronPython and experimentations with the OM are almost downright pleasant.

Resources