Chris Chris - 10 days ago 5
C# Question

Running all SSRS reports through one report user ignoring own users domain

I have the following code which returns the reports from my SSRS server, afterwards I then store the paths to each individual list which allows users to run them from within the application. The below works fine.

NetworkCredential serviceCredentials = new NetworkCredential()
{
UserName = username,
SecurePassword = EncryptionManager.DecryptToSecureString(password),
Domain = domain
};

reports = new ObservableCollection<object>(reportsManager.FindReports(reportsWebService, reportsFolderName, serviceCredentials));



//FindReports
ReportingService2005 rs = new ReportingService2005();
rs.Url = reportsWebService;
rs.Credentials = serviceCredentials;

CatalogItem[] catalogItems = rs.ListChildren(@"/" + reportsFolderName, false);


However the problem is when a user selects a report to view it shows the following error:


The permissions granted to user are insufficient for performing this
operation.


I understand that the quick fix to this would be to add the users domain into the security section on the Report server, however this is not appropriate.

My question is I can supply credentials to allows a specified user to access the report folder is it possible to pass this along so that user can run a report?

Each of my reports use built in connection strings NOT windows authentication.

Edit: I am using Reporting WinForms.

Answer

Windows Forms

In a windows forms project you can pass a suitable System.Net.NetworkCredential to ServerReport.ReportServerCredentials.NetworkCredentials property of ReportViewer. This way, all reports will be executed using the passed credential:

reportViewer1.ServerReport.ReportServerCredentials.NetworkCredentials =
    new System.Net.NetworkCredential("username", "password", "domain");

Web Forms

The solution for a Web Forms is different. In a Web Forms project, to pass a suitable credential to RePortViewer you need to implement IReportServerCredentials. Then you can assign the value to ServerReport.ReportServerCredentials property of ReportViewer control. This way, all reports will be executed using the passed credential.

Example

Here is a simple implementation. It's better to store username, password and domain name in app config and read them from config file:

using System;
using System.Net;
using System.Security.Principal;
using Microsoft.Reporting.WebForms;
[Serializable]
public sealed class MyReportServerCredentials : IReportServerCredentials
{
    public WindowsIdentity ImpersonationUser { get { return null; } }
    public ICredentials NetworkCredentials
    {
        get
        {
            return new NetworkCredential("username", "password", "domain");
        }
    }
    public bool GetFormsCredentials(out Cookie authCookie, out string userName,
        out string password, out string authority)
    {
        authCookie = null;
        userName = password = authority = null;
        return false;
    }
}

Then in Page_Load pass the credential this way:

protected void Page_Load(object sender, EventArgs e)
{
    if(!IsPostBack)
        this.ReportViewer1.ServerReport.ReportServerCredentials = 
            new Sample.MyReportServerCredentials();
}

Note

In cases which you want to use ReportViewer with no session state you can also implement IReportServerConnection. In this case you need to add a key value in appsettings section of config file to introduce the implementation this way:

<add key="ReportViewerServerConnection" value="YourNameSpace.YourClass, YourAssemply" />

In this case, you don't need code in Page_Load and the config would be enough. For more information take a look at this great blog post by Brian Hartman.