MicrosoftВ® SQL Server(TM) 2005 Reporting Services Step by Step (Step by Step (Microsoft))
Another way to customize Reporting Services is through its security extension. By default, Reporting Services uses Windows integrated security. As you have seen, this means a user must have valid credentials (a user name and password) for either a local logon on the Report Server or for a domain logon on the domain containing the Report Server.
There are times, however, when creating Windows credentials for each Reporting Services user is not desirable or even feasible. You may want to expose reports on an Internet site or an extranet site. You may want to use the Report Manager as part of a web application that makes use of a different security model, such as forms authentication. In these situations, you can consider using the Reporting Services security extension to implement a security mechanism for the Report Manager and the Report Server web service that better fits your needs. As noted in Chapter 2, the Enterprise Edition of Reporting Services is required to use the Reporting Services security extension.
Authentication and Authorization
Before we discuss the security extension, let’s look at the way security functions in Reporting Services. Security in Reporting Services has two parts: authentication and authorization. Authentication determines whether or not you can come in. Authorization determines what you can do once you are inside.
Authentication
Think of security like a trip to an amusement park as shown in Figure 12–8. If you are a big amusement park fan like me (I can’t get enough of those roller coasters!), you probably purchase the multiday pass. Because the pass can only be used by the person who originally purchased it, you must prove you are the rightful owner of that pass when you get to the main gate. You may even have to show a picture ID to prove you are who you say you are.
This is the process of authentication. You must prove you have the appropriate credentials to gain access. At the amusement park gate, you need two things to gain entrance: a pass and some type of identification to prove you have the right to use that pass. The same is true for authentication in the computer world. First, you need some type of pass that has rights to get you in the gate. This usually takes the form of a user name, or more accurately, a user account identified by a user name. You must have a valid user account to log on.
Second, you must have some way to prove you are the rightful owner of that user account. This is often done by specifying a password along with the user name. In areas where security needs to be tighter, this proof of ownership might take the form of an electronic card or a thumbprint scan.
In the default setup for Reporting Services, we are essentially outsourcing the main gate operations. Windows takes care of authenticating the user for us. If Windows says the user is okay, they must be okay. As you will see in a moment, when we implement custom security, we take back this job of authentication for ourselves.
Persisting Authentication
Because we are dealing with web interfaces—the Report Manager web application and the Report Server web service—we have one more authentication issue to deal with. Each time a user makes a request through either of these interfaces, the authentication has to be done again. This is just the nature of the HTTP requests we use with both web applications and web services. It is a bit like having to come in through the main gate of the amusement park every time you want to go on a different ride.
When we are using Windows authentication, the authentication process is completely transparent to the users. Because of this, having to redo the authentication each time a user requests a different Report Manager screen or executes a different report is not a big deal. However, if you create a logon screen as part of your custom security, this will be a different story. No user wants to reenter their user name and password each time they execute a report or navigate from one folder to another.
What we need is some way to remember we have already authenticated a particular user. We need the electronic equivalent of the ultraviolet-light-sensitive hand stamp used at the amusement park for exit and reentry. In computer terms, we need to persist the authentication.
For the custom security extension created in the section “Creating a Custom Security Extension,” we use a browser cookie to persist the authentication. If the cookie is not present in an HTTP request, the logon screen is displayed. This should happen only at the beginning of a user session. Once we authenticate the user, we can send the cookie information to the user’s browser and instruct it to create a cookie. The browser sends this cookie along with all subsequent HTTP requests made to Reporting Services. If the cookie is present, the logon information is taken from the cookie and the user does not see the logon screen.
Authorization
Let’s return to our amusement park analogy. You passed through the main gate and are ready to ride that killer coaster. However, some limitations exist on just who can go on each ride. You must be taller than a certain height to go on the wild rides. You must be shorter than a certain height to go on the kiddie rides.
This is the process of authorization. You must prove you have rights to perform a certain activity before you can do that activity. At the amusement park, you must prove to the ride operator that you are taller or shorter than the height marking painted on the sign. If your head does not come above the line, you do not have the right to perform the activity of riding the roller coaster.
As you saw in Chapter 11, Reporting Services uses role-based authorization. Your logon account is assigned to a certain role for each folder, report, or resource. This role includes rights to perform certain activities on that item. Being assigned to the Browser role for a report means you are authorized to view that report.
The role assignments are stored in the Report Catalog within Reporting Services. When using the default security setup, Reporting Services checks the role assignments in the Report Catalog each time you try to perform a task. It determines from these role assignments whether or not you are authorized to perform that task, and then either lets you proceed or brings the process to a screeching halt.
When we implement custom security, you must perform this authorization check yourself. Fortunately, Reporting Services enables you to continue to use the role information stored in the Report Catalog. Therefore, if you want, you can still use the screens in the Report Manager to create and edit role assignments, and you can have those changes stored in the Report Catalog. Your custom security implementation can then use the information in the Report Catalog to determine authorization. If this does not fit your needs, you can create your own method for determining what a user is authorized to do.
Issues with Custom Security
Before you see how to create and deploy a custom security extension, we need to discuss several issues related to custom security. Changing the security mechanism for an enterprise application should not be done lightly. Before implementing a custom security extension, make sure you cannot fulfill your business needs without it, and then look at each of the following issues.
Tried and True
Windows integrated security is the default security model for Reporting Services and is, in fact, the only security model that comes with the product. Reporting Services was designed with Windows integrated security in mind. Therefore, it is the only thoroughly tested security model and the only one proven to provide a secure environment.
If you implement your own custom security extension, you are taking the responsibility of creating a secure environment on your own shoulders. You are responsible for the design, testing, and implementation of an environment that ensures the proper security for your Report Server. Remember, a custom security extension includes both authentication and authorization. Not only do you need to keep out those people who are not allowed to enter your Report Server environment, but you also have to restrict the activities of those users you do let in.
All or Nothing
When you implement a custom security extension, you completely replace the security mechanism on a Reporting Services installation. You cannot use your custom security extension for some users and the default behavior for others. This is an all-or-nothing proposition. Once you replace the default security mechanism, all authentication and all authorization comes through your custom code.
Validate All User Input
Care should be taken to validate all user input to prevent problems. This is especially true when you are creating a security interface. You should take steps to ensure that your custom security extension is not vulnerable to invalid characters and buffer overruns as a means of gaining unauthorized entry.
In addition to serving as the means for a security attack, special characters can also cause a problem if you are using the MyReports feature. As discussed in Chapter 11, when the MyReports feature is enabled, a virtual user folder is created from the user name of each Reporting Services user. The MyReports folder is then mapped to the appropriate user folder as each user logs on. User names containing any of the following characters can cause problems with these virtual user folders:
: ? ; @ & = + $, \ * > < | . " / '
Using the Secure Sockets Layer
Anytime you are transmitting authentication information, you should use Secure Sockets Layer (SSL) to protect that transmission. When you use SSL, your data is encrypted before it is transmitted between the client and host computers. This helps prevent any interception or tampering with the authentication information while your data is in transit.
To use SSL, simply use https:// rather than http:// at the beginning of your URL. In addition, there is an SSL setting in the web application file and an SSL setting in the Internet Information Services management utility. These settings can be used to require all users to utilize an SSL connection when accessing the Reporting Services web application and web service.
Changing Security Models
Changing security models on your Reporting Services installation is not something to be done lightly. Any role assignments you created under a previous security model are removed when you change to a new model. Only the default system administration rights are present.
Changing back from a custom security extension to the default Windows integrated security, although possible, is not generally recommended. If you do so, you may experience errors when accessing items that had security roles assigned to them under your custom security extension. In addition, if you cannot successfully change back to Windows integrated security, you must reinstall Reporting Services.
Creating a Custom Security Extension
To demonstrate custom security in Reporting Services, we need to create our own code for both authentication and authorization. This code takes the form of several custom classes that implement Reporting Services interfaces. In addition, we create an override for some of the methods in the web service wrapper class to implement the cookie processing and persist our authentication.
If the previous paragraph sounds like Greek to you, then the custom security extension is probably not for you. You need a firm grasp of object-oriented programming (OOP) to understand the code samples in this section. Don’t feel bad if OOP is not your thing—many people lead happy and productive lives without knowing how to implement an interface or override a constructor!
We are going to look at a sample security extension that implements forms security for Reporting Services. Forms security enables you to present the user with a form on which they can enter their user name and password. You can then validate that user name and password against a database table or other data store where you are maintaining a list of valid user credentials. This sample can help you become familiar with the workings of a security extension in Reporting Services. The sample is based on Microsoft’s Forms Authentication Sample for Reporting Services. The original sample was written in C#. I have translated it into Visual Basic for consistency with the other examples in this book. Some revisions were also made to better fit with the Galactic Delivery Services examples.
Caution | The code provided here is merely a sample to aid in your understanding of the custom security extension. It is not intended to be used in a production environment. Discuss any intended security changes with your organization’s security manager, system administrator, or network administrator before proceeding. |
Preparing the Sample Code
The forms security sample consists of a single solution called FormsSecurity. This solution contains two projects—the FormsSecurity project and the StoreRSLogon project. The FormsSecurity project contains all the classes that implement the security extension along with the logon screens. The StoreRSLogon project contains code for a Windows application that enables you to assign user names and passwords to employees of Galactic Delivery Services.
First, three things need to be taken care of before we are ready to look through this sample code, so complete the following steps:
-
Download the FormsSecurity solution files and copy them to a test computer that contains both Reporting Services and Visual Studio 2005 with Visual Basic .NET.
-
Open the FormsSecurity solution.
-
Add a reference in the FormsSecurity project to the file:
Microsoft.ReportingServices.Interfaces.dll
The default location for this file is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer\bin
Note In this example, it is assumed you are using a copy of Visual Studio 2005 that is running on your Report Server.
-
Add a web reference to the ReportService web service on this computer. Name this web reference RSWebService. (Use the computer name rather than localhost when adding this reference. Testing has shown some unexpected results when using localhost for the web reference while building a custom security extension.)
-
Select Save All in the toolbar.
The AuthenticationExtension Class
The AuthenticationExtension class implements a Reporting Services interface called IAuthenticationExtension. The AuthenticationExtension class, along with a second class called CheckAuthentication, handles the authentication responsibilities. Some of the code from the AuthenticationExtension class is listed here (see the downloaded sample code for a complete listing):
Imports System Imports System.Data Imports System.Data.SqlClient Imports System.Security.Principal Imports System.Web Imports Microsoft.ReportingServices.Interfaces Namespace MSSQLRS.FormsSecurity Public Class AuthenticationExtension : Implements _ IAuthenticationExtension ' This function determines whether a user logon is valid. Public Function LogonUser(ByVal userName As String, _ ByVal password As String, _ ByVal authority As String) _ As Boolean Implements IAuthenticationExtension.LogonUser Return CheckAuthentication.VerifyPassword(userName, password) End Function ' GetUserInfo is required by the implementation of ' IAuthenticationExtension. ' The Report Server calls the GetUserInfo method for each request to ' retrieve the current user identity. Public Sub GetUserInfo(ByRef userIdentity As IIdentity, _ ByRef userId As IntPtr) _ Implements IAuthenticationExtension.GetUserlnfo ' If the current user identity is not null, ' set the userIdentity parameter to that of the current user. If (Not (HttpContext.Current Is Nothing)) And _ (Not (HttpContext.Current.User.Identity Is Nothing)) Then userIdentity = HttpContext.Current.User.Identity Else userIdentity = Nothing End If userId = IntPtr.Zero End Sub ' This function is called by the Report Server when it sets ' security on an item. The function calls VerifyUser to make ' sure this is a valid user name. Public Function _ IsValidPrincipalName(ByVal principalName As String) _ As Boolean Implements _ IAuthenticationExtension.IsValidPrincipalName Return VerifyUser(principalName) End Function ' Look up the user name in the database to make sure it is valid. Public Shared Function VerifyUser(ByVal userName As String) _ As Boolean Dim isValid As Boolean = False Dim conn As SqlConnection = New SqlConnection(ConnectionString) Dim cmd As SqlCommand = New SqlCommand("stp_LookupUser", conn) Dim sqlParam As SqlParameter Dim reader As SqlDataReader ' Look up the user name in the Employee table ' in the Galactic database. cmd.CommandType = CommandType.StoredProcedure sqlParam = cmd.Parameters.Add("©UserName", SqlDbType.VarChar, 255) sqlParam.Value = username Try conn.Open() reader = cmd.ExecuteReader ' If a row was returned, the user is valid. If reader.Read() Then isValid=True End If Catch ex As Exception Throw New Exception("Exception verifying password." & _ ex.Message) Finally conn.Close () End Try Return isValid End Function End Class End Namespace
GetUserInfo Method The GetUserInfo method of the AuthenticationExtension class is called by Reporting Services to determine the identity of the current user. This method reads the user’s credentials that are being persisted in the cookie. Going back to our amusement park analogy, the GetUserInfo method puts our user’s hand under the ultraviolet light to see if it has been stamped.
If GetUserInfo does not find a cookie with credential information, it returns an empty identity. When this occurs, the user is redirected to the logon page. The user then supplies the credentials and the authorization process can continue. If everything is working correctly, this should only occur once, at the beginning of the session.
Remember, GetUserInfo is simply extracting the credentials from the cookie. It is not determining the validity of those credentials. That is left to the LogonUser method.
LogonUser Method Once you have the credentials, either from the cookie or from the logon page, they must be verified. Reporting Services calls the LogonUser method to do this verification. In our implementation, LogonUser calls the VerifyPassword method in the CheckAuthentication class.
VerifyPassword looks up the user name in the Employee table of the Galactic database. It encrypts the password supplied as part of the user’s credentials and compares it with the encrypted password stored in the Employee table. If the two encrypted passwords match, the logon is valid. The result of this password match is returned to the LogonUser method, and then returned to Reporting Services.
IsValidPrincipalName and VerifyUser Methods The IsValidPrincipalName and Verify User methods are used to determine whether a user name is valid. The IsValidPrincipalName method simply calls the VerifyUser method to perform this task. The VerifyUser method looks for the user name in the Employee table of the Galactic database. If the user name is found in the table, it is valid.
The VerifyUser method is called by a method in the AuthorizationExtension class. This is done to validate the user name in a configuration file. The IsValidPrincipal-Name method is called from Reporting Services whenever you create a new role assignment. This is done to validate the user name entered for that role assignment, before the assignment is saved in the Report Catalog.
The AuthorizationExtension Class
The AuthorizationExtension class implements a Reporting Services interface called IAuthorizationExtension. The AuthorizationExtension class handles the authorization responsibilities. Some of the code from the AuthorizationExtension class is listed here (see the downloaded sample code for a complete listing):
Imports System Imports System.IO Imports System.Collections Imports System.Collections.Specialized Imports System.Globalization Imports System.Runtime.Serialization Imports System.Runtime.Serialization.Formatters.Binary Imports Microsoft.ReportingServices.Interfaces Imports System.Xml Namespace MSSQLRS.FormsSecurity Public Class AuthorizationExtension : Implements _ IAuthorizationExtension Private Shared m_adminUserName As String Public Function CheckAccess(ByVal userName As String, _ ByVal userToken As IntPtr, _ ByVal secDesc() As Byte, _ ByVal requiredOperation As FolderOperation) _ As Boolean Implements IAuthorizationExtension.CheckAccess Dim acl As AceCollection Dim ace As AceStruct Dim aclOperation As FolderOperation ' If the user is the administrator, allow unrestricted access. ' Because SQL Server defaults to case-insensitive, we have to ' perform a case insensitive comparison. If String.Compare(userName, m_adminUserName, True, _ CultureInfo.CurrentCulture) = 0 Then Return True End If acl = DeserializeACL(secDesc) For Each ace In acl ' First check to see if the user has an access control ' entry for the item. If String.Compare(userName, ace.PrincipalName, True, _ CultureInfo.CurrentCulture) = 0 Then ' If an entry is found, return true if the given ' required operation is contained in the ACE structure For Each aclOperation In ace.FolderOperations If aclOperation = requiredOperation Then Return True End If Next End If Next Return False End Function ' Overload for an array of folder operations Public Function CheckAccess(ByVal userName As String, _ ByVal userToken As IntPtr, _ ByVal secDesc() As Byte, _ ByVal requiredOperations As FolderOperation()) _ As Boolean Implements IAuthorizationExtension.CheckAccess Dim operation As FolderOperation For Each operation In requiredOperations If Not CheckAccess(userName, userToken, secDesc, operation) Then Return False End If Next Return True End Function ' This subroutine implements SetConfiguration as required ' by IExtension Public Sub SetConfiguration(ByVal configuration As String) _ Implements IAuthorizationExtension.SetConfiguration ' Retrieve the admin user and password from the config settings ' and verify it. Dim doc As XmlDocument = New XmlDocument Dim child As XmlNode doc.LoadXml(configuration) If doc.DocumentElement.Name = "AdminConfiguration" Then For Each child In doc.DocumentElement.ChiIdNodes If child.Name = "UserName" Then m_adminUserName = child.InnerText Else Throw New Exception("Unrecognized configuration element.") End If Next If _ MSSQLRS.FormsSecurity.AuthenticationExtension.VerifyUser( _ m_adminUserName) _ = False Then Throw New Exception("An attempt was made to load an " & _ "Administrative user for the Report Server that is not valid.") End If Else Throw New Exception("Error loading config data.") End If End Sub End Class End Namespace
SetConfiguration Method The SetConfiguration method reads a section of XML from the RSReportServer.config file. This XML information specifies the user name of the administrative user. This user name is stored in the m_adminUserName property of the AuthorizationExtension class.
The CheckAccess methods give this user all rights to all items. This ensures at least one user has rights to administer Reporting Services. This is necessary because, when you initially switch to your custom security extension, no role assignments exist for any of the items in Reporting Services.
CheckAccess Methods The AuthorizationExtension class has several CheckAccess methods, which are overloaded based on the last parameter, requiredOperation. The correct method is called, depending on which type of access is being checked.
For example, if the user is trying to delete a folder, the CheckAccess method is called with a requiredOperation parameter of type FolderOperation. The version of CheckAccess that checks rights on folder operations is executed. If the user is using the check boxes on the Report Manager View Details page to delete several folders at once, the CheckAccess method is called with a requiredOperation parameter that is an array of the FolderOperation type. The version of CheckAccess that checks rights on an array of folder operations is executed.
Only two of the CheckAccess methods—the method for a folder operation and the method for an array of folder operations—are printed here. The CheckAccess methods for reports, resources, and other types of report items are similar to the CheckAccess methods shown here for folder operations. You can refer to the source code to view the other overloads of the CheckAccess methods.
The CheckAccess method is called by Reporting Services to verify the user’s right to perform operations. It may be called once if the user is performing a specific operation. In other cases, the CheckAccess method may be called many times during the painting of a single screen. For example, if the user is viewing the Home folder, the CheckAccess method must be called for each item in the Home folder to determine if the user has rights to view that item.
The CheckAccess method first determines if the current user is the administrative user. If they are, the CheckAccess method returns true, indicating this user has rights to do whatever operation is being requested. The operation is then completed by Reporting Services.
If this is not the administrative user, the CheckAccess method walks through the security descriptor collection until it finds an entry for this particular user. It then walks through a second collection, which contains the rights assigned to this user. If it finds the rights to the requested operation, it returns true, allowing the operation to be completed. If it does not find the rights to the requested operation, it returns false, causing the operation to be aborted.
Deploying a Custom Security Extension
This section contains a process for deploying a custom security extension on a Report Server. If you want to complete this process solely for educational purposes, you should do so on a test installation of Reporting Services. That way, if anything goes wrong, either in deploying the custom security extension or in reverting back to Windows integrated security, you can reinstall Reporting Services without harming a production environment.
This process should not be tested on a production installation of Reporting Services with the intent to revert to Windows integrated security at its conclusion. As stated earlier, changing to a custom security extension, and then changing back to Windows integrated security, is not generally recommended. You have been warned. Don’t come crying to me if you screw up your production server!
Preparation
Caution | Create a backup of all configuration files as directed in the following procedure. Without these backups, you may be unable to return to a working environment if the custom security extension fails. |
To create a backup for all configuration files, follow these steps:
-
Add the reference and the web reference as instructed in the section “Preparing the Sample Code.”
-
Create a folder called RSSecurityBackup on the Report Server. This folder can be anywhere it will not be accidentally deleted. This folder will hold a backup copy of your Reporting Services configuration files for backing up your custom security extension.
-
In the RSSecurityBackup folder, create a folder called ReportServer and a folder called ReportManager.
-
Copy the following files from the Reporting Services\ReportManager folder to the RSSecurityBackup\ReportManager folder:
rsmgrpolicy.config RSWebApplication.config Web.config
The default location for the Reporting Services\ReportManager folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportManager
-
Copy the following files from the Reporting Services\ReportServer folder to the RSSecurityBackup\ReportServer folder:
RSReportServer.config rssrvpolicy.config Web.config
The default location for the Reporting Services\ReportServer folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer
Compiling and Deploying the Custom Security Assembly and Logon Pages
Now that you have created backup copies of your Reporting Services configuration files, you can compile and deploy the custom security assembly and the logon pages.
-
Open the FormsSecurity solution in Visual Studio 2005.
-
Select Build | Build Solution from the Main menu to build the assembly and the executable in this solution.
-
Copy the resulting MSSQLRS.FormsSecurity.dll assembly and the MSSQLRS .FormsSecurity.pdb debug database to the ReportManager\bin folder. The default location for this folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportManager\bin
-
Copy the same MSSQLRS.FormsSecurity.dll assembly and the MSSQLRS .FormsSecurity.pdb debug database to the ReportServer\bin folder. The default location for this folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer\bin
-
Copy the UILogon.aspx file to the ReportManager\Pages folder. The default location for this folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportManager\Pages
-
Copy the Logon.aspx file to the ReportServer folder. The default location for this folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer
Modifying the Reporting Services Configuration
In addition to placing the assembly and the logon pages in the appropriate location, you need to modify several Reporting Services configuration files and the IIS configuration to enable your custom security extension.
-
You begin by modifying three Report Manager configuration files. These three files can all be found in the following folder:
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportManager
-
Open the rsmgrpolicy.config file in a text editor, such as Notepad. This file contains the code access security configuration for the Report Manager.
-
Find the code group for the MyComputer zone. Change the permission set from Execution to FullTrust, as shown here:
<CodeGroup version="1" PermissionSetName="FullTrust" Description="This code group grants MyComputer code Execution permission. "> <IMembershipCondition version="1" Zone="MyComputer" />
This change is necessary to allow the custom security extension to access the database and to look up user information.
Caution As with all XML documents, the config files are case-sensitive. Pay close attention to the case of each entry you make in these configuration files.
-
Save your changes.
-
Open the RSWebApplication.config file in your text editor. This file contains custom configuration information for the Report Manager web application.
-
Find the <UI> entry and add the following, replacing {computername} with the name of your Report Server computer:
<UI> <CustomAuthenticationUI> <loginUrl>/Pages/UILogon.aspx</loginUrl> <UseSSL>False</UseSSL> </CustomAuthenticationUI> <ReportServerUrl>http://{computername}/ReportServer</ReportServerUrl> </UI>
This entry tells the Report Manager where to redirect a user who has not been authenticated. If you have SSL available on this server, change the <UseSSL> setting from False to True.
-
Save your changes.
-
Open the Web.config file in your text editor. This file contains the standard configuration information for the Report Manager web application.
-
Locate the <identity impersonate="true"/> entry. Change this entry to “false”, as shown:
<identity impersonate="false"/>
-
Save your changes.
-
Next, you modify three Report Server configuration files. These three files can all be found in the following folder:
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer
-
Open the RSReportServer.config file in your text editor. This file contains custom configuration information for the Report Server web service.
-
Find the <Security> and <Authentication> entries and modify them as shown:
<Security> <Extension Name="Forms" Type="MSSQLRS.FormsSecurity.AuthorizationExtension, MSSQLRS.FormsSecurity"> <Configuration> <AdminConfiguration> <UserName>Stanley</UserName> </AdminConfiguration> </Configuration> </Extension> </Security>
<Authentication> <Extension Name="Forms" Type="MSSQLRS.FormsSecurity.AuthenticationExtension, MSSQLRS.FormsSecurity"/> </Authentication>
These entries tell the Report Server web service what classes to use for authentication and authorization and which assembly contains those classes. The <Configuration> entry here contains the configuration information read by the SetConfiguration method, as discussed previously. Stanley is the administrative user.
-
Save your changes.
-
Open the rssrvpolicy.config file in your text editor. This file contains the code access security configuration for the Report Server.
-
Add a code group for the custom security assembly, as shown here:
<CodeGroup version="1" PermissionSetName="FullTrust"> <IMembershipCondition version="1" Url="$CodeGen$/*" /> </CodeGroup> <CodeGroup version="1" Name="SecurityExtensionCodeGroup" Description="Code group for the sample security extension" PermissionSetName="FullTrust"> <IMembershipCondition version="1" Url="C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ReportServer\bin\MSSQLRS.FormsSecurity.dll" /> </CodeGroup>
This code group uses URL membership to assign Full Trust rights to the custom security assembly. If Reporting Services is not installed in the default location, change the URL path as necessary.
-
Save your changes.
-
Open the Web.config file in your text editor. This file contains the standard configuration information for the Report Server web service.
-
Locate the <identity impersonate="true"/> entry. Change this entry to “false”, as shown:
<identity impersonate="false"/>
-
Locate the <authentication mode="Windows" /> entry. Replace it with the following:
<authentication mode="Forms"> <forms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="60" path="/"></forms> </authentication>
-
Add the following <authorization> entry immediately below the <authentication> entry:
<authorization> <deny users="?" /> </authorization>
-
Save your changes and close your text editor.
-
From the Administrative Tools area of the Control Panel, start the Internet Information Services management console.
-
Navigate to the entry for the Reports virtual directory. This virtual directory should be located under Default Web Site.
-
Right-click the Reports virtual directory and select Properties from the Context menu. The Reports Properties dialog box appears.
-
Select the Directory Security tab.
-
Click Edit in the Anonymous Access and Authentication Control area. The Authentication Methods dialog box appears.
-
Check the Anonymous Access check box.
-
Click OK to exit the Authentication Methods dialog box.
-
Click OK to exit the Reports Properties dialog box.
-
Right-click the ReportServer virtual directory and select Properties from the Context menu. The ReportServer Properties dialog box appears.
-
Select the Directory Security tab.
-
Click Edit in the Anonymous Access and Authentication Control area. The Authentication Methods dialog box appears.
-
Check the Anonymous Access check box.
-
Click OK to exit the Authentication Methods dialog box.
-
Click OK to exit the ReportServer Properties dialog box.
-
Close the Internet Information Services management console.
Reporting Services is now configured to use the custom security extension.
Restarting IIS
Anytime you make a change to the Reporting Services configuration files or to the custom security assembly, you need to restart IIS for these changes to take effect. Do not restart IIS if you have users in the middle of online sessions on your IIS server. You can restart IIS by using the following procedure:
-
Open a command window.
-
Type iisreset at the command prompt and press ENTER. The iisreset utility stops and restarts IIS.
-
Once IIS has restarted, close the command window.
Using the Custom Security Extension
To test the custom security extension, simply open your browser and go to the Report Manager. Rather than seeing the Report Manager, you see the logon page. Enter a user name and password, and then click Logon to log on to Reporting Services.
Two logons are set up in the Employee table of the Galactic database:
User Name | Password | Administrative User |
---|---|---|
Stanley | SR | Yes |
Ellen | EH | No |
The logon for Ellen does not have any security role assignments. Use the Stanley administrative logon to assign security roles to the Ellen logon.
Note | For the cookie to function properly, you need to access the Report Manager using the computer name rather than using localhost. |
Creating Logons
You can create additional nonadministrative logons using the StoreRSLogon application. You created this executable when you built the FormsSecurity solution. To create a new logon, do the following:
-
Run StoreRSLogon.exe.
-
Select a Galactic Delivery Services employee from the Employee drop-down list.
-
Enter a user name and password for this employee.
-
Click Save to save these credentials in the Employee table of the Galactic database. The password is stored in the Employee table as an encrypted value.
-
Exit the StoreRSLogon program.
Debugging the Custom Security Assembly
In some cases, the custom security code does not work perfectly on the first try. Hard to believe, but true. You have two tools to help you in this situation: the log files and the Visual Studio debugger.
The log files are helpful because they record any exceptions that might occur. Because we deployed the debug database file (PDB) along with the assembly file (DLL), the log file even contains the method name and line number where the exception occurred. If an exception occurs, check the most recent log file for the Report Server, the Report Manager web application, and the Report Server web services.
You can also use the Visual Studio debugger to set breakpoints and step through the custom assembly code. Debugging should only be done on a test or development server, never on a production server. To use the debugger, do the following:
-
Start Visual Studio 2005 and open the FormsSecurity solution.
-
Open Internet Explorer and navigate to the Report Manager. The logon page appears. Do not log on yet.
-
Return to Visual Studio and set the desired breakpoints in your code.
-
Select Debug | Processes from the Main menu. The Processes dialog box appears.
-
From the list of processes, select the aspnet_wp.exe process (or the w3wp.exe process if you are using IIS 6.0), and then click Attach. The Attach to Process dialog box appears.
-
Check the Common Language Runtime and Native check boxes.
-
Click OK to exit the Attach to Process dialog box.
-
Click Close to exit the Processes dialog box.
-
Switch to Internet Explorer, enter the user name and password, and click Logon.
-
When one of your breakpoints is encountered, the debugger stops execution and changes focus to Visual Studio.
-
You can now view variables and step through the code as you do with any other Visual Basic program.
-
When you complete your debugging session, click Stop Debugging in Visual Studio, and then close Internet Explorer.
Changing Back to Windows Integrated Security
If your custom security extension does not function properly or, if despite all the warnings, you want to change from your custom security extension back to Windows integrated security, use the following procedure:
-
Remove all role assignments you created using the forms security user names.
-
Copy all the files in the RSSecurityBackup\ReportManager folder to the ReportManager folder. Replace the existing files. The default location of the ReportManager folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportManager
-
Copy all the files in the RSSecurityBackup\ReportServer folder to the ReportServer folder. Replace the existing files. The default location of the ReportServer folder is
C:\Program Files\Microsoft SQL Server\MSSQL\Reporting Services\ ReportServer
-
Use the Internet Information Services management console to remove Anonymous access from both the Reports and the ReportServer virtual directories.
-
Use the iisreset utility program to restart IIS.
Other Extensions
In addition to the custom security extension, Reporting Services offers other APIs that enable you to extend its default functionality. You can develop your own data access extensions, rendering extensions, and delivery extensions. Examples showing how to utilize some of these extensions are included with Reporting Services. A number of third-party developers are using these APIs to create some capable add-ons for Reporting Services.
Категории