January 2006 - Posts

OT: Quotable Quotes

Red-Gate Software's Phil Factor links to some programming quotable quotes, and includes nuggets from one of my favorite IT books: Fred Brooks' The Mythical Man-Month (Amazon). I read the 20th Anniversary Edition of this book about 2 years ago and was amazed at how astute Brooks' observations on the computer software industry were, especially for a book written in the 1970's. The problems do not seem to have changed; and I clearly remember thinking at the time - "Hasn't anybody learnt?"

I actually enjoyed TMMM so much I wrote an e-mail to Fred Brooks thanking him, and he took the time to reply to my mail (which raised his already-high credibility with me a lot).

Oh, here's some other "quotable quotes" that I've picked up in the past year or so:

"A manager once said, 'If it is more difficult than plucking a tissue from the Kleenex® box, my staff won't use it!'"
John Terpstra

"Its not a question of time management anymore - I dont have any time left to manage"
http://geekswithblogs.net/ansari/archive/2004/08/30/10391.aspx

“We spent the 90's trying to figure out how to get email…and the 00's trying to figure out how to not get email.”
http://blogs.msdn.com/kclemson/archive/2004/09/17/231085.aspx

"You know why does it take less than one second to search the ENTIRE FREAKING INTERNET and 5 minutes to search my computer for one lousy filename."
Vin Buddy http://geekswithblogs.net/mwatson/archive/2004/10/05/12215.aspx

“Monday is a hard way to spend one-seventh of your life.”
Willem Odendaal http://dotnetjunkies.com/WebLog/willemo/archive/2004/10/11/28212.aspx

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning."
Richard Cook

"The Internet combines the excitement of typing with the reliability of anonymous hearsay."
America (The Book): A Citizen's Guide to Democracy Inaction http://www.amazon.com/o/ASIN/0446532681/diabeticbooks

Keeping Track of Report Server Custom Security Settings

Reporting Services allows many nested levels of folders, just like Windows, and when you apply security settings to a folder the settings flow down to child items - which can be other folders, reports, and items like Excel or Word files. However when you change security settings on a child item you disengage it from the parent, so that any changes from then on to the parent won't affect the child (unlike Windows security, where you can "inherit" the parent settings and add child settings).

In my mind this makes security settings in Reporting Services hard to keep track of. Items either inherit the parent security settings, or have their own. This creates a problem if you want to change security settings on a global level, as if you make a change to a parent, any children that have seperate or custom security settings will not reflect the changes. Maintaining lots of different security settings on folders and reports could also become a maintenance problem very quickly.

However, the security settings in Reporting Services are very thorough. If you do not explicitly grant access to a report or folder to a user, that user will not even be able to see a link to the report. Manually browsing or typing in the URL to the report or folder won't get them there either - it's like the item does't exist! This can be helpful in some circumstances.

So I came up with the following 2 queries (and went on to make them into a Reporting Services report) that will show the items that do not inherit parent security and allow you to keep track of them, for the times when you absolutely, positively, must use Report Server security settings.

The first query returns the items on the Report Server that have custom security settings (to run this, you'll need to have access to the ReportServer database):

Disclaimer: use at your own risk. The following queries work for me -  I don't make any guarantees for anyone else.

USE ReportServer
GO
-- *********************************************************
-- Query 1: list all items that have security changed from parent item
-- *********************************************************
SELECT  C.ItemID,   --primary key and identifier, UNIQUEIDENTIFIER, NOT NULL
        C.Path,     --full path from root, which can be used in an expression like
                    --"http:///Reports/Pages/Folder.aspx?ItemPath=X" (X needs to be URL-encoded), NVARCHAR(425), NOT NULL
        C.[Name],   --name of item, NVARCHAR(425), NOT NULL
        C.ParentID, --ID of parent (links back to ItemID), UNIQUEIDENTIFIER, can be NULL
        C.Type,     --type of item in the "Catalog" table - DataSource = 5, Folder = 1, LinkedReport = 4, Report = 2, Resource = 3, Unknown = 0                     --else (e.g. PDF, DOC), INT, NOT NULL
        C.Hidden    --1 for hidden, 0 for visible, BIT, can be NULL
FROM    --get data from the Catalog table
        dbo.[Catalog] C WITH (NOLOCK)
WHERE   --don't get user folders ("My Reports")
        (NOT (C.Path LIKE N'/Users Folders%')) AND
        --only get changed items: Catalog.PolicyRoot setting of 1 means that the item has
        --specific permissions set, 0 means it inherits the parent settings
        (C.PolicyRoot = CONVERT(BIT, 1)) AND
        --don't get the root item (top-level folder)
        (C.ParentID IS NOT NULL)

I would not recommend querying the live ReportServer database, but rather copying the data out to another database on some sort of schedule for querying. You never know what Reporting Services is doing under the hood with it's own database.

That said, the query above returns data from the "Catalog" table for items (folders, reports, data sources, etc.) that have custom security settings. The query below will return the users that have access, given an ItemId:

DECLARE @ItemId UNIQUEIDENTIFIER --item to search for
SET @ItemId = ''
-- *********************************************************
--Query 2: list users who have access to a specific item
-- *********************************************************
SELECT DISTINCT
        C.Path, U.UserName
FROM    dbo.[Catalog] C WITH (NOLOCK) INNER JOIN
            dbo.Policies P ON C.PolicyID = P.PolicyID INNER JOIN
            dbo.PolicyUserRole PUR ON P.PolicyID = PUR.PolicyID INNER JOIN
            dbo.Users U ON PUR.UserID = U.UserID
WHERE   --get the passed item only
        (C.ItemID = @ItemId)

Used together, these two queries can help keeping track of which items on a Report Server have custom security settings. Enjoy!

UPDATE: Updated Item Types in 1st query thanks to Lutz Roeder's .NET Reflector