The scenario is simple: I have a reportviewer control and want to show & print a ServerReport. The application needs to be able to connect to the reporting service over the internet and the client machines do not need to be in the same domain.
This is the same authentication scenario that applies to viewing reports through HTTP using internet explorer and a URL to the reportserver virtual directory: Internet Explorer asks for a user and password.
Howerver, I want to specify the credentials programatically so the users don't need to enter them manually. Since the ReportViewer is connecting to the ReportServer website through HTTP (I guess its calling the webservice or even just displaying the HTML returned by the reportserver aspx), this should be pretty easy, just as its easy to setup a NetworkCredential(user, pass) for authentication when calling a webservice over http.
Why do we need to implement an interface (IReportServerCredentials) that needs to return a WindowsIdentity just for that Whats the problem with the webservice proxy model that only involves one line of code for specifying the credentials
Where can I find any information about this interface (which I already implemented using intellisense but have no idea whats the semantics for each method/property) Specifically, how do I create a WindowsIdentity representing a remote user on the reportserver machine when both machines are not in the same domain This is just a "new NetworkCredential(user, pass)" using the httprequest model!
I've googled for "IReportServerCredentials" and only got 1 hit for a forum post by Rajeev saying one needs to implement it... no information whatsoever anywhere about how to do it.

ReportServerCredentials
Subhash Subramanyam
Hi Tudor,
I had tried returning basic credentials from the IReportServerCredentials implementation but the viewer displays an error. Anyways, note in this way you're forcing us to use an uterly insecure method of authentication, sending the username and password in clear text over the wire.
From your answer I'm guessing its impossible to create a WindowsIdentity representing a remote user, at least thats what I remember from the last time I fiddled with user objects and active directory. I *think* it might be possible to create it when both machines are in the same domain, using the AD api, but I dont really see a way when both machines are in different / no domains.
My scenario is pretty usual: a customer's company already has a myriad of reports on the report server and we want to made them accesible from their client application, even on the road (read: mobile clients, notebooks, etc), which dont really belong to the domain.
So you're really leaving us with only two alternatives: continue to use Internet Explorer and the html interface, or convert all the reports on the report server to rdlc and embed them on each client application, which obviously we won't be doing due to the cost of translation plus the nightmare it would be to update any report's definition and deploy the updates.
I don't know why exactly you don't use the same model used by the rest of the framework (e.g. WebClientProtocol.Credentials or WebRequest.Credentials), since I assume you're connecting to the report server using HTTP and using framework classes for that purpose, but if at all possible I think it would simplify a lot for end users.
Juan
snegidhan
Storing credentials anywhere is specifically what we are trying to avoid, for security reasons.
If the user your page is running as has privileges to view the report then you can return null for ImpersonationUser.
Ronald Huereca
If the report is being executed asynchronously the credentials are required even after the page has finished executing. The reason for requiring you to supply an object that implements the IReportServerCredentials interface is so that ReportViewer can call into this object when it needs the credentials. The ReportViewer does not store credentials anywhere.
Please let us know if you have further questions or comments.
brandontyler
Thanks for responding. I did see that example, but wondered if there was cleaner way to do this than using those DllImport functions.
I'm confused on how this whole interface is used. There appears to be multiple methods to authenticate, but when I trace my code, it appears to run through all of them.
Can I implement this method and stuff it with my own credential
public ICredentials NetworkCredentials
{
get
{
return null; // Not using NetworkCredentials to authenticate.
}
}
Andre Rentes
Hi Marie,
I think this is what you are looking for, it works for me.
http://blogs.msdn.com/bimusings/archive/2005/11/18/494436.aspxNic
RyanSmith
Hello.
I WISH I could get to credential issues. I am struggling with a RS (2005) problem where I can't get the web methods to run. For example, I am using Froms auth and can get to Report Manager/Report Server just fine. I can conntect to the Reporting Services instance using MS Sql Server Management Studio.
When I attempt to execute a web method, like ListChildren() or ListRenderingExtensions(), I am getting an error message that reads "Object moved to here." The word "here" is a link to:
logon.aspx ReturnUrl=/reportserver/reprotexecution2005.asmx.
I have been working with MS support for a couple of weeks now and we are not able to make any progress.
Any ideas
Thank you.
chmarroc
Hi Juan,
I don't suppose you have a webforms version of this code I tried to implement it in my web app, but had lots of errors.
Marie
V Batishchev
First of all, I'm talking about the Windows Forms ReportViewer, so no page is involved in the user interface, the user is not accesing any page, unless you implied that the Winforms ReportViewer connects to a webserver using HTTP.
When I asked why didnt you use a NetworkCredential object (an in-memory object, not "physically stored" anywhere), instead of requiring us to implement IReportServerCredentials, you said it was because you needed those credentials for later reuse. So my question in the last message was: "why dont you then just remember the NetworkCredentials object, what does that have to do with requiring a custom object ". I wasnt suggesting storing the credentials anywhere, unless you meant you dont even want to have them in memory at runtime, in which case you're in the exact same position using a custom object, which is even less secure since the user implementation of it could be insecure.
And my crucial question is: since IReportServerCredentials requires to return a WindowsIdentity, to a WINDOWS FORMS ReportViewer, so it can connect to a remote server "SERVER1" as user "joe", how do I create a WindowsIdentity object representing "SERVER1\joe" so my ReportViewer, running as "CLIENTMACHINE\marie" can connect to the server with the specified credentials
Please note this is the most common authentication scenario in the world, where a user on the internet needs to provide a user name and a password to a web server. This is made extremely easy when dealing with HttpRequests and Webservices, you just need to create a NetworkCredential with one simple line of code:
NetworkCredential credentials = new NetworkCredential(username, password, domain);
webServiceProxy.Credentials = credentials;
There's no requirement for a WindowsIdentity using this model.
iicDotnet
That should work, it may be a bug in the version you are testing.
>>Anyways, note in this way you're forcing us to use an uterly insecure method of >>authentication, sending the username and password in clear text over the wire.
Passing credentials this way is not any less secure. The type of authentication is determined by the server, not the client. If the server is configured for NTLM or Digest, the client will send the hash on the wire, if the server is configured for Basic auth, then it will.
Thanks
Tudor
Sam Z. Glassenberg
Tudor,
Thanks for the clarification.
Here's my IReportServerCredentials implementation in case anyone needs it. I haven't yet tested wether the password is sent in clear-text (or base64) or the hash against the default ReportServer virtual directory installation.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Reporting.WinForms;
using System.Security.Principal;
namespace x
{
public class ReportViewerCredentials : IReportServerCredentials
{
public ReportViewerCredentials()
{
}
public ReportViewerCredentials(string username)
{
this.Username = username;
}
public ReportViewerCredentials(string username, string password)
{
this.Username = username;
this.Password = password;
}
public ReportViewerCredentials(string username, string password, string domain)
{
this.Username = username;
this.Password = password;
this.Domain = domain;
}
public string Username
{
get
{
return this.username;
}
set
{
string username = value;
if (username.Contains("\\"))
{
this.domain = username.Substring(0, username.IndexOf("\\"));
this.username = username.Substring(username.IndexOf("\\") + 1);
}
else
{
this.username = username;
}
}
}
private string username;
public string Password
{
get
{
return this.password;
}
set
{
this.password = value;
}
}
private string password;
public string Domain
{
get
{
return this.domain;
}
set
{
this.domain = value;
}
}
private string domain;
#region IReportServerCredentials Members
public bool GetBasicCredentials(out string basicUser, out string basicPassword, out string basicDomain)
{
basicUser = username;
basicPassword = password;
basicDomain = domain;
return username != null && password != null && domain != null;
}
public bool GetFormsCredentials(out string formsUser, out string formsPassword, out string formsAuthority)
{
formsUser = username;
formsPassword = password;
formsAuthority = domain;
return username != null && password != null && domain != null;
}
public WindowsIdentity ImpersonationUser
{
get
{
return null;
}
}
#endregion
}
}
Cheers,
Juan
dhopton MSFT
That was beta code. They changed it (I'd dare to say following my suggestion of using NetworkCredentials); in RTM (the final ReportViewer control distributed with VS2005) all I need to do is this:
No need to implement an interface just to pass the credentials,ReportServerCredentials is already instantiated once you have a ServerReport object.
The_Assimilator
First, you only have to worry about report server credentials if you want to use a different set of credentials than the process you are running the control in.
For winforms it means the process, for webforms it also depends on whether you use identity impersonate = true.
Then, I think you can achieve what you want by returning the user name and password from IReportServerCredentials.GetBasicCredentials. We will use the user name and password that you provide to send the request to the server, w/o logging on locally
IReportServerCredentials.WindowsIdentity is useful if you want to make the server request as a different Windows user on the machine that runs the control.
It is useful, because you can create a WindowsIdentity from an impersonation token, meaning you don't necessarily have to have the user name as password for that user.
We are still looking at the usability aspects of passing credentials.
Thanks for your feedback,
Tudor
=============================================================
Tudor Trufinescu
Dev Lead
Microsoft Sql Server Reporting Services
Mageaere
Thanks all!
After stumbling around for days now It looks like I have the answer!!!!!
this info should be in the MSDN docs on using the report control!!!
Brog
I don't really follow. If you need the credentials for later use all you need to do is to store the NetworkCredential, you dont need to use a custom object for that.
Anyways, since we need to implement IReportServerCredentials, how exactly are we supposed to create a WindowsIdentity representing a user of a remote machine
I'm on MACHINE_A, and I need to provide credentials for MACHINE_B\joe. Both machines are standalone boxes, ie dont belong to any domain. How exactly do I create a WindowsIdentity representing MACHINE_B\joe to return from IReportServerCredentials.ImpersonationUser to a ReportViewer running on MACHINE_A
Regards,
Juan