none
Implementing IReportServerCredentials - Getting Blank ReportViewer RRS feed

  • Question

  • I am in need of help getting this to work.  I am implementing IReportServerCredentials to allow all reports to be run as one Windows user.  Reports server is a separate server from the webapp server. 

     

    I am doing exactly this:

    http://msdn2.microsoft.com/en-us/library/microsoft.reporting.webforms.ireportservercredentials(VS.80).aspx

     

    It looks like the login is working fine.  But all I see on the page are the reports controls (export, next page, etc.).  The actual report is not displayed.  Another thing that makes me wonder about rights - the images are not displayed in the control either (printer icon, next page icon, etc.).

     

    This report displays fine through the Report Manager pages logged in with the same user account.

     

    Any help would be greatly appreciated.

     

    Thanks.

    Thursday, June 14, 2007 8:26 PM

Answers

  • OK so I finallly figured this one out - thought I would come back and post my findings.

    Basically I did not need to use IReportServerConnection - IReportServerCredentials was working properly.  My main reason for only getting text (for one page) and no images...I was not logged in to my webapp.  I was testing from anonymous pages.  This let my inital request work and pass the correct credentials (async=true) but for the reguests for images and toolbar items it was passing the service user.  Also async=false would not work.

    So after logged in to my webapp (using SQL Membership) this worked fine as it passed the correct credentials every time.  Also async=false will work if needed.

    My main reporting need was for authenticated users.  We were looking at adding some sample reports to the anonymous portion - but just as an enhancement so no big loss and long as logged in users can run reports. 

    Thanks for the help.
    Friday, January 11, 2008 5:58 PM

All replies

  • OK, probably a stupid question but... have you done the web config setup for hosting the report viewer control?

     

    http://msdn2.microsoft.com/en-us/library/ms251661(VS.80).aspx

    Friday, June 15, 2007 3:59 PM
  • I am not implementing IReportServerConnection because I did not think it was necessary with the session enabled. 

    Here is what I do have in the web config related to reporting services:

    Code Snippet

    <httpHandlers>
        <add path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=00000000000000" validate="false"/>
    </httpHandlers>
    <appSettings>
        <add key="MyReportViewerUser" value="xxxxxxxxxx"/>
        <add key="MyReportViewerPassword" value="xxxxxxxxxxx"/>

        <add key="MyReportViewerDomain" value="xxxxxxxxx"/>
    </appSettings>


    I am specifying the connection information in the ReportViewer control.  Do I need to use IReportServerConnection to get this working? 

    Thanks.
    Friday, June 15, 2007 7:36 PM
  • Just because you're establishing the connection as shown in http://msdn2.microsoft.com/en-us/library/microsoft.reporting.webforms.ireportservercredentials(VS.80).aspx doesn't mean that the report is actually *using* that connection as it talks to the server.

     

    I understand that you have sessions turned on, but I don't think that tells the report viewer what you want to do. 

     

    So... have you told your ReportViewer.ServerReport instance about your established connection, via its .ReportServerCredentials property?

     

    It *sounds* like that's what is missing...

     

    >L<

    Friday, June 15, 2007 11:25 PM
  • Lisa,

    I have not done that.  I will try that soon to see if it helps.

    I was doing some more testing with my current config and found our more info.  In some cases it does look like it is connecting successfully - but still blank report viewer.
    1. If I set AsyncRendering="true", then I see no entry in the logs (both C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\LogFiles and the ExecutionLog table in the ReportServer database).
    2. If I set AsyncRendering="false" then I do see entries in the logs.  In the ExecutionLog table in the ReportServer database I can see that the status was"rsSuccess" and that it was run under the user account I am passing. 
    3. If I change the ReportPath="/DirectorsDB/DB_WebStats" (valid) to ReportPath="/DirectorsDB/DB_WebStat" (invalid report name) I get the error "The item '/DirectorsDB/DB_WebStat' cannot be found. (rsItemNotFound)" which is expected and I think demonstrates that I am connecting.
    I would want to use AsyncRendering - but first things first...

    Thanks.
    Monday, June 18, 2007 5:22 PM
  • >>

    If I set AsyncRendering="false" then I do see entries in the logs.  In the ExecutionLog table in the ReportServer database I can see that the status was"rsSuccess" and that it was run under the user account I am passing. 

    <<

     

    Yes.. my question is whether that connection is being stored and used after it is made for use with the additional requests that the control is going to make to the server.  That is what the ReportViewer.ServerReport.ReportServerCredentials property is for...

     

    >L<

    Monday, June 18, 2007 9:32 PM
  • ok I have implemented IReportServerConnection2 - but I still have the same result. I will post all of the relevant code in hope that it will help.

    Another observation - I get rsSuccess in the ExecutionLog when running the report via URL access or from the ReportViewer control on a page.  But I noticed that the ExecutionLog.RowCount is different (URL = 60240, ReportViewer = 4).  Why - I do not know.

    My Report ASPX Page

    <rsweb:ReportViewer ID="ReportViewer1" runat="server" Height="400px" ProcessingMode="Remote" Width="400px" BorderColor="Red" BorderStyle="Solid" BorderWidth="2px" SizeToReportContent="True" AsyncRendering="false" Enabled="true">
    <ServerReport ReportPath="/DirectorsDB/DB_WebStats" />
    </rsweb:ReportViewer>



    My Report ASPX Code Behind

    using System;
    using System.Data;
    using System.Configuration;
    using System.Collections;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using SqlReportingServices;
    using System.Net;
    using System.Security.Principal;
    using Microsoft.Reporting.WebForms;
    using BoardMember.Reports;


    public partial class AP_TestReport : System.Web.UI.Page
    {
    protected void Page_Init(object sender, EventArgs e)
    {
    ReportViewer1.ServerReport.ReportServerCredentials = new BMIReportServerConnection();

    }
    }



    IReportServerConnection2 implementation

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using SqlReportingServices;
    using System.Net;
    using System.Security.Principal;
    using Microsoft.Reporting.WebForms;
    using System.Collections.Generic;

    /// <summary>
    /// Handle report server connection and credentials here.
    /// </summary>

    namespace BoardMember.Reports
    {
    [Serializable]
    public sealed class BMIReportServerConnection : IReportServerConnection2
    {
    public WindowsIdentity ImpersonationUser
    {
    get
    {
    // Use the default Windows user. Credentials will be
    // provided by the NetworkCredentials property.
    return null;
    }
    }

    public ICredentials NetworkCredentials
    {
    get
    {
    // Read the user information from the web.config file.
    // By reading the information on demand instead of
    // storing it, the credentials will not be stored in
    // session, reducing the vulnerable surface area to the
    // web.config file, which can be secured with an ACL.

    // User name
    string userName =
    ConfigurationManager.AppSettings
    ["BMIReportViewerUser"];

    if (string.IsNullOrEmpty(userName))
    throw new Exception(
    "Missing user name from Web.config file");

    // Password
    string password =
    ConfigurationManager.AppSettings
    ["BMIReportViewerPassword"];

    if (string.IsNullOrEmpty(password))
    throw new Exception(
    "Missing password from Web.config file");

    // Domain
    string domain =
    ConfigurationManager.AppSettings
    ["BMIReportViewerDomain"];

    if (string.IsNullOrEmpty(domain))
    throw new Exception(
    "Missing domain from Web.config file");

    return new NetworkCredential(userName, password, domain);
    }
    }

    public bool GetFormsCredentials(out Cookie authCookie,
    out string userName, out string password,
    out string authority)
    {
    authCookie = null;
    userName = null;
    password = null;
    authority = null;

    // Not using form credentials
    return false;
    }

    public Uri ReportServerUrl
    {
    get
    {
    string url =
    ConfigurationManager.AppSettings[
    "BMIReportServerUrl"];

    if (string.IsNullOrEmpty(url))
    throw new Exception(
    "Missing url from the Web.config file");

    return new Uri(url);
    }
    }

    public int Timeout
    {
    get
    {
    return 60000; // 60 seconds
    }
    }

    public IEnumerable<Cookie> Cookies
    {
    get
    {
    // No custom cookies
    return null;
    }
    }

    public IEnumerable<string> Headers
    {
    get
    {
    // No custom headers
    return null;
    }
    }
    }
    }



    Web.config

    <appSettings>
    <add key="ReportViewerServerConnection" value="BoardMember.Reports.BMIReportServerConnection, APP_CODE"/>
    <add key="BMIReportViewerUser" value="xxxxxxxx"/>
    <add key="BMIReportViewerPassword" value="xxxxxxxx"/>
    <add key="BMIReportViewerDomain" value="sql-dev1"/>
    <add key="BMIReportServerUrl" value="http://sql-dev1/ReportServer"/>
    </appSettings>


    Again - thanks for the help. I am sure it is something insanely stupid that I am missing...

    Tuesday, June 19, 2007 4:35 PM
  • It may not be anything stupid you're doing (and I'm not reading your code very closely because I don't think I will spot it if you are <s>).

     

    But I do see that you are assigning the connection in Page_Init.  Sometimes that's too early to do certain kinds of tasks.

     

    Can you possibly move that later in the "life" of the page or of the reportviewer control?  Here's what I'm thinking: suppose you assign the server URL or do a .Reset() later or something (I'm not even checking whether there is a .Reset for the webforms reportviewer, but you get the idea -- you've initialized certain significant factors of the report form later in the life of the page or control and this has the effect of nulling out the credentials you've assigned.

     

    I notice that in the IReportServerCredentials Interface topic they assign the ReportServerCredentials property *after* they assign the ReportServer URL and ReportPath properties...  that's why I'm wondering about this.

     

    >L<

    Tuesday, June 19, 2007 5:21 PM
  • Lisa,

    I moved the connection assignment to Page_Load, ReportViewer1 OnInit, and ReportViewer1 OnLoad without any change in results. I had that in Page_Init because the link in my first post had it there as well. I was just following the examples exactly aside from changing a few names.

    But after implementing IReportServerConnection2, I am not sure I need it anywhere since the web.config loads it? I see the same results that way too.

    The report I was trying to display was only a graph - so I decided to try a simple text only report. That worked as far as seeing the text content. But same issues for images, report viewer buttons, and it only worked when AsyncRendering="false". This was with no code in my code-behind page; everything being handled in the web.config or ReportViewer in my aspx page.

    Here is a screenshot of the report page.

    So I am really not sure what to try next. Most examples out there use impersonation - but our app is using SQL Membership. In addition some of reports will be on parts of the site that do not require a login. So I was going down the road of running all reports as one Windows user. Turning anonymous access on is not an answer because other users are accessing this via Report Manager (and because of the security concerns). If there is another valid solution I would be open to try it.

    Thanks.
    Tuesday, June 19, 2007 8:53 PM
  • >>Page_Load, ReportViewer1 OnInit, and ReportViewer1 OnLoad

     

    All of those events are earlier than anything I had in mind, unfortunately... look at the help topic I mentioned earlier and you will see why:

     

    If memory servers (don't have it in front of me right now) they are creating the report viewer instance in code.  Whether that's correctly remembered or not, you can see that the credentials are set *after* the report path and url are set up. 

     

    That careful an example made me think that, if the internal initialization processing of the control takes a different sequence, the setting up of the path and url might wipe out the credentials (IOW, it might have to be done later).

     

    I understand that there was no code-behind in what you were trying to do, and that looking at the web.config instructions in the docs one would think it wasn't needed.  But it may *take* code, the way that example shows, for the thing to work.


    FWIW... I have heard all kinds of things that make me think what you are trying to do is difficult and that MS haven't really thought through other scenarios than integrated security with RS .  See this thread http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=409854&SiteID=1 for one example of these discussions, and some code that may or may not work for you.  One gentleman definitely did it in a ReportViewer load event, if I'm not mistaken.  Others indicated that the authentication handshakes were causing timeouts, which I suppose might be true in your case as well, no matter how simple the page and the report.

     

    At one point I tried to write a digest of information for somebody who was starting out with this -- it was on a different forum so I will dig that up and you can see what you think.  At least some of this and certainly the code in one or two of the MS blog posts might help you.

     

    >L<

     


    Hey there Ed,

     

    You have probably read this background article on your topic already but
    JIC:
    http://www.devx.com/dotnet/Article/27133

     

    As far as security goes,
    http://www.webhost4life.com/kb/question.php?qstId=209 will show you how you
    can do it if you don't *care* about security <shrug>.

     

    One good idea would be to be sure and use SSL for this purpose on top of
    whatever else you decide.

     

    Another good idea would be to write a security extension for forms
    authentication -- (but read this short post first
    http://msmvps.com/blogs/anguslogan/archive/2004/10/03/14772.aspx)

     

    I think there is a sample of doing this
    http://blogs.msdn.com/bimusings/archive/2005/12/05/500195.aspx -- if you
    can't find the sample read this blog post
    http://weblogs.asp.net/plip/archive/2006/09/21/Microsoft-Documentation-_2D00_-Where-is-the-sample-code_3F00_.aspx

    and here is an article (with source) doing something like what you need
    http://www.sqlmag.com/Articles/ArticleID/93830/93830.html

     

    I am wracking my brains for where I saw a good general overview on extension
    writing for RS from an MS blog -- here it is, it's not long and it's very
    useful perspective)
    http://blogs.msdn.com/bryanke/archive/2004/03/16/90797.aspx

     

    Last but not least, security issues have to be discussed with this caveat:
    receiving permissions have to be handled differently if you are integrating
    with Sharepoint.  So if you're doing that be sure to ask the question "is
    this applicable in a Sharepoint integration scenario" before sweating over
    it!

     

    HTH,

     

    >L<

    "Ed" <Ed@discussions.microsoft.com> wrote in message
    newsBig Smile11FD871-A11D-4472-B5ED-CCC27ED6F09A@microsoft.com...
    > Hi,
    >  I am doing some researches about how the reporting services can be use on
    > the public (internet) instead of just intranet.  Could someone please give
    > me
    > a hint (link / sample) about how this can be achived and how security is
    > this
    > on the internet.
    >
    > Thanks
    >
    > Ed

    Tuesday, June 19, 2007 10:56 PM
  • OK so I finallly figured this one out - thought I would come back and post my findings.

    Basically I did not need to use IReportServerConnection - IReportServerCredentials was working properly.  My main reason for only getting text (for one page) and no images...I was not logged in to my webapp.  I was testing from anonymous pages.  This let my inital request work and pass the correct credentials (async=true) but for the reguests for images and toolbar items it was passing the service user.  Also async=false would not work.

    So after logged in to my webapp (using SQL Membership) this worked fine as it passed the correct credentials every time.  Also async=false will work if needed.

    My main reporting need was for authenticated users.  We were looking at adding some sample reports to the anonymous portion - but just as an enhancement so no big loss and long as logged in users can run reports. 

    Thanks for the help.
    Friday, January 11, 2008 5:58 PM
  • Doh!  Head slapper time.

     

    Thanks for taking the time to post this.  I am sure it will help lots of people!

     

    >L<

    Saturday, January 12, 2008 12:37 AM