I've spent a lot time trying to figure this one out, but without luck - so I will try to post the question here.
I am running 2 ASP.NET websites on the same server. Both websites are running on IIS 7.5 + .NET 4. The sites use the SSRS Report Viewer to show reports from an another server.
We recently moved both the websites and RS to new servers (switching from RS 2005 to RS 2008 and switching from IIS 7.0 to IIS 7.5). However, after moved to the new servers, one of the websites are unable to view the reporting services, as we get the following error:
request failed with HTTP status 401
The strange thing is, that the Report Viewer is configured exactly the same way in the two websites (simply copy pasted between the two). Further, using the "working website", we are able to view the reports belonging to both websites - and using the other website, we are unable to view any of the reports.
The authorization looks like this in both cases:
Credentials:
[Serializable]
public sealed class ReportServerCreditentials : IReportServerCredentials
{
public WindowsIdentity ImpersonationUser
{
get { return null; }
}
public ICredentials NetworkCredentials
{
get
{
string userName = ConfigurationManager.AppSettings["ReportViewerUser"];
string password = ConfigurationManager.AppSettings["ReportViewerPassword"];
string domain = ConfigurationManager.AppSettings["ReportViewerDomain"];
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;
return false;
}
}
Report Viewer usage
public partial class ReportServicesViewer : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
string reportingFolder = ConfigurationManager.AppSettings["ReportingFolder"];
showReport(string.Format("/{0}/{1}", reportingFolder, Request.QueryString["report"]));
}
}
private void showReport(string reportPath)
{
RevReport.ServerReport.ReportServerUrl = new Uri(ConfigurationManager.AppSettings["ReportServer"]);
RevReport.ServerReport.ReportServerCredentials = new ReportServerCreditentials();
RevReport.ServerReport.ReportPath = reportPath;
}
}
In aspx:
<rsweb:ReportViewer ID="RevReport" runat="server" Height="100%" Width="100%" Font-Names="Verdana" Font-Size="8pt" ProcessingMode="Remote" ZoomMode="Percent" ZoomPercent="100"></rsweb:ReportViewer>
Other observations
At one point, we tried to monitor the traffic between the website and RS using Fiddler, but somehow the communication actually worked in this case.
However, when I tried this at a later point, Fiddler gave the following response:
[Fiddler] The socket connection to <servername> failed. <br />ErrorCode: 10061. <br />No connection could be made because the target machine actively refused it 10.0.0.17:443
I am not sure how exactly to interpret this, as we are not using SSL for the Website <-> RS communication.
Any advice would be greatly appreciated.
I had the similar issue when we built new SSRS server. Web application was not able to connect to report server. I was able to solve the issue by doing these:
Enable Kerberos Authentication on the server
Set spn(server principal names) on the server
enable the impersonation in web application
Related
I have a MVC Web Application makes use of Windows Authentication and Exchange Web Services. While in development, this worked great, since the application pool in IIS on my development machine is set to run under my windows user and the Exchange Server is on the same domain.
On the web server, though, all our applications are set to run under a system user that has access to all the database servers etc. The database connection uses Integrated Security, so I cannot impersonate a user over an application level.
I've been trying to impersonate the current windows user through the code as follows:
public abstract class ExchangeServiceImpersonator
{
private static WindowsImpersonationContext _ctx;
public Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
var tcs = new TaskCompletionSource<string>();
EnableImpersonation();
try
{
tcs.TrySetResult(CreateMeetingImpersonated(from, to, subject, body, location, begin, end));
}
catch(Exception e)
{
tcs.TrySetException(e);
}
finally
{
DisableImpersonation();
}
return tcs.Task;
}
public abstract string CreateMeetingImpersonated(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end);
private static void EnableImpersonation()
{
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
_ctx = winId.Impersonate();
}
private static void DisableImpersonation()
{
if (_ctx != null)
_ctx.Undo();
}
}
Then, the class that implements the abstract methods:
public class ExchangeServiceExtensionsBase : ExchangeServiceImpersonator
{
private ExchangeService _service;
public ExchangeService Service
{
get
{
if (this._service == null)
{
this._service = new ExchangeService(ExchangeVersion.Exchange2013);
this._service.Url = new Uri(WebConfigurationManager.AppSettings["ExchangeServer"]);
this._service.UseDefaultCredentials = true;
}
return this._service;
}
set { return; }
}
public override string CreateMeetingImpersonated(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
//this.Service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, from);
Appointment meeting = new Appointment(Service);
string meetingID = Guid.NewGuid().ToString();
meeting.Subject = subject;
meeting.Body = "<span style=\"font-family:'Century Gothic'\" >" + body.Replace(Environment.NewLine, "<br/>") + "<br/><br/>" +
"<span style=\"color: white;\">Meeting Identifier: " + meetingID + "</span></span><br/><br/>";
meeting.Body.BodyType = BodyType.HTML;
meeting.Start = begin;
meeting.End = end;
meeting.Location = location;
meeting.ReminderMinutesBeforeStart = 60;
foreach (string attendee in to)
{
meeting.RequiredAttendees.Add(attendee);
}
meeting.Save(SendInvitationsMode.SendToAllAndSaveCopy);
return meetingID;
}
}
Then, the methods are accessed as follows:
public static class ExchangeServiceExtensions
{
public static async Task<string> CreateMeetingAsync(string from, List<string> to, string subject, string body, string location, DateTime begin, DateTime end)
{
ExchangeServiceImpersonator serviceImpersonator = new ExchangeServiceExtensionsBase();
return await serviceImpersonator.CreateMeetingAsync(from, to, subject, body, location, begin, end);
}
}
This still works on my local dev machine, but no matter what I do, the user accessing from the server keeps getting an access denied from the exchange server:
The request failed. The remote server returned an error: (401) Unauthorized.
I've tried leaving it on default credentials:
this._service.UseDefaultCredentials = true;
And attempting to manually set the credentials to the current (supposedly impersonated) user:
this._service.Credentials = new WebCredentials(CredentialCache.DefaultNetworkCredentials);
Also, I've tried using the Exchange ImpersonatedUserId object using the email address:
this._service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, from);
which returns the following exception:
The account does not have permission to impersonate the requested user.
By default and as a security measure, Windows will prevent you from delegating your credentials from the web server to Exchange. This means you cannot impersonate the user accessing your web site.
This is known as the "server double hop" scenario. The first "hop" is from the user's machine to the web server, and the second "hop" is from the web server to the Exchange server (Google will give you lots of hits on server double hop).
This is a good thing because it will prevent any hackers from moving around your servers.
The reason it is working on your development machine is that there is only one "hop" from your local web server to the Exchange server.
To solve it you need to allow the web server to delegate the credentials to the Exchange server. This is called Kerberos delegation and must be set up by your system administrator somehow in the Active Directory (which is beyond my knowledge).
I tried to change the AD object setting to Trust this computer for delegation.. (you need AD admin rights) but that didn't solve the problem.
My breakthrough was to set the Identity of the Application Pool (Advanced Settings...) to NetworkService. It worked also with LocalService and LocalSystem, but be careful because they have elevated rights.
What surprised me, that it didn't work with Custom account, when I entered the AD admin account that in reality got all the rights for the exchange system.
general infos about my application:
ASP.CORE 2.1 webservice
Windows Server 2016
IIS 10.0.x
internal corporate network
I have added the web service to my WPF windows phone store app, when i run my app in emulator it works, but sometime it get creshes cause lack of internet connectivity.
i'm checking my emulator IMEI is registerd or not in database using WCF service on main_pageload event
my code looks like this
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
SchoolWebService.SchoolAppWebServiceSoapClient proxy = new SchoolAppWebServiceSoapClient();
proxy.CheckIMEIRegisteredOrNotCompleted += new EventHandler<CheckIMEIRegisteredOrNotCompletedEventArgs>(proxy_CheckIMEIRegisteredOrNotCompleted);
proxy.CheckIMEIRegisteredOrNotAsync(strIMEI);
}
in this service im checking the mobile IMEI registerd or not. i have checked by debugging the app it goes upto proxy.CheckIMEIRegisteredOrNotAsync(strIMEI);
when it leave the context it throuw the error
An exception of type 'System.ServiceModel.CommunicationException' occurred in System.ServiceModel.ni.dll but was not handled in user code
please suggest me some advice,,,thanks in advance
To check if the Internet connection is available I just simply create a method to check it and execute it then application is launching or page is loading. This method I create in App.xaml.cs:
public bool CheckInternetConnection()
{
bool connection = true;
ConnectionProfile currentConnection = NetworkInformation.GetInternetConnectionProfile();
if (currentConnection == null)
{
connection = false;
}
return connection;
}
Then in some page_loaded event I execute it:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
bool connection = ((App)Application.Current).CheckInternetConnection();
if (connection == false)
{
MessageBox.Show("Internet connection is not available", "Internet connection", MessageBoxButton.OK);
Application.Current.Terminate();
}
}
Now then a client don't have the Internet connection available it won't crash, but it will show a message for the user. I hope it will help.
I'm trying to connect to a Report (rdlc file) using ASP.NET Web Applications. I'm working with VS2010 and the Report Server is version 2008.
I have the following URL to the report which works fine:
http://server url/Products/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/Products/Dashboards/Product_tool.rdl&Source=Server Url/Products/Dashboards/Forms/AllItems.aspx&DefaultItemOpen=1
When i enter that URL in my browser it first asks for a username password. When i log in then the Report shows up just fine.
Now i need to display this report in a Report Viewer. So i added a Report Viewer control to my aspx page. I configured the URls for it like so:
Report Server:** http://server url/Products/_layouts/ReportServer
Report Path:** /Products/Dashboards/Product_tool.rdl
I'm not really sure if that is even correct..?
In any case, in my PageLoad i have the following line of code:
eportViewer1.ServerReport.ReportServerCredentials = new ReportCredentials("myuser", "mypass");
The ReposrtCredentials class is taken from: http://social.msdn.microsoft.com/Forums/en-US/vsreportcontrols/thread/c65abca7-0fdb-40fb-aabe-718f63377a55/ (from Phil)
Now when i run my Web Application i get the following error:
The attempt to connect to the report server failed. Check your
connection information and that the report server is a compatible
version.
Now i'm not sure if the URL i supplied to the Report Viewer is right? Or what the problem else could be.
Anyone any idea..?
In order to Integrate SSRS Reports into an ASP.NET application, follow these steps.
Firstly, Implement IReportServerConnection2 interface. I did something like this:
public sealed class CustomReportServerConnection : 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[Utility.Constants.AppConst.REPORT_USER].ToString();
if (string.IsNullOrEmpty(userName))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_USER_NAME);
// Password
string password = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_PASSWORD].ToString();
if (string.IsNullOrEmpty(password))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_PWD);
// Domain
string domain = ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORTS_DOMAIN].ToString();
if (string.IsNullOrEmpty(domain))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_DOMAIN);
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[Utility.Constants.AppConst.REPORT_SERVER_URL].ToString();
if (string.IsNullOrEmpty(url))
throw new Exception(Utility.Constants.AppConst.MESSAGE_MISSING_URL);
return new Uri(url);
}
}
public int Timeout
{
get
{
return int.Parse(ConfigurationManager.AppSettings[Utility.Constants.AppConst.REPORT_SERVER_TIME_OUT].ToString());
// return 60000; // 60 seconds
}
}
public IEnumerable<Cookie> Cookies
{
get
{
// No custom cookies
return null;
}
}
public IEnumerable<string> Headers
{
get
{
// No custom headers
return null;
}
}
}
Now in your Configuration AppSettings place following keys ( or provide these values from wherever you want):
<add key="ReportServerUrl" value="http://sqlServerURL/ReportServer_SQL2008R2"/>
<!--Development TargetReportFolder-->
<add key="TargetReportFolder" value="/AppReporting/"/>
<add key="ReportServerTimeOut" value="600000"/>
<add key="ReportViewerServerConnection" value="FullyQualified Name of ur CustomReportServerConnection,ProjectName"/>
<add key="ReportsUser" value="ReportUser"/>
<add key="ReportsPassword" value="reportPassword"/>
<add key="ReportsDomain" value="myDomain"/>
Now , in your .aspx page, drag a reportViewer something like this:
<rsweb:ReportViewer ID="RptViewer" runat="server" AsyncRendering="False" SizeToReportContent="true"
ProcessingMode="Remote" Width="100%" BackColor="#F7F8F9" OnReportError="RptViewer_ReportError"
OnReportRefresh="RptViewer_ReportRefresh1" Height="">
</rsweb:ReportViewer>
and configure your ReportViewer in the codeBehind..
place your ReportParameter properly.
it shud give you an idea...
point is, you need to authenticate properly, hence writing your custom ReportServerConnection
When you configure your report viewer,check whether the account you use has permission to view the report because it is necessary that you have access when using server report.
Check out this link too. They will be of help : http://forums.asp.net/t/1562624.aspx/1
I have a SSRS 2008 R2 report running on the reporting server. When I access the report using the Report Manager or Web Service URL it works ok.
http://mycomputer/ReportServer
and
http://mycomputer/Reports
When I add a ReportViewer to a WebForms web site and point it to
http://mycomputer/reportserver
with a report path to my report it gives me an access denied error when running the web site using VS.net's web server.
The permissions granted to user 'mycomputer\myusername' are insufficient for performing this operation. (rsAccessDenied)
The following is the exact code I'm using in the aspx page.
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<rsweb:ReportViewer ID="ReportViewer1" runat="server" ProcessingMode="Remote" Font-Names="Verdana"
Font-Size="8pt" InteractiveDeviceInfos="(Collection)" WaitMessageFont-Names="Verdana"
WaitMessageFont-Size="14pt" Width="712px">
<ServerReport ReportPath="/MyReports" ReportServerUrl="http://mycomputer/reportserver" />
</rsweb:ReportViewer>
mycomputer \ myusername is an Adminstrator on the machine. I also added it as an Administrator in the ReportManager.
I am running it using IE in Administrator mode.
What else could be causing the access denied issues?
I've read other people having issues, but most of them are not for 2008R2 so I haven't been able to figure out how to try what they did. There is no IIS to configure and no IUSR to give access to the reports.
SSRS logs just show the same error message without any other information.
Creating an instance class that implements IReportServerCredentials should fix the problem. Add the following class and call it as follows:
ReportViewer1.ServerReport.ReportServerCredentials = new ReportServerCredentials("username", "pwd", "domain");
/// <summary>
/// Local implementation of IReportServerCredentials
/// </summary>
public class ReportServerCredentials : IReportServerCredentials
{
private string _userName;
private string _password;
private string _domain;
public ReportServerCredentials(string userName, string password, string domain)
{
_userName = userName;
_password = password;
_domain = domain;
}
public WindowsIdentity ImpersonationUser
{
get
{
// Use default identity.
return null;
}
}
public ICredentials NetworkCredentials
{
get
{
// Use default identity.
return new NetworkCredential(_userName, _password, _domain);
}
}
public bool GetFormsCredentials(out Cookie authCookie, out string user, out string password, out string authority)
{
// Do not use forms credentials to authenticate.
authCookie = null;
user = password = authority = null;
return false;
}
}
Thanks to Phil Clewes: link
Actually what I needed was a step by step guide but anyway..
I have to show some rdl reports in a web-site using the ASP.NET report vievew and do all the necessary configurations for the Reporting Services. The users of the page should not deal with ANY authorization.
Here is my code for the report viewer:
rprtView.ServerReport.ReportServerCredentials = new ReportServerCredentials();
rprtView.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote;
rprtView.ServerReport.ReportServerUrl = new Uri(#"http://mydomain/reports");
rprtView.ServerReport.ReportPath = #"/MyReports/PurchaseOrder";
rprtView.ShowParameterPrompts = false;
ReportParameter[] parameters = new ReportParameter[1];
parameters[0] = new ReportParameter();
parameters[0].Name = "OrderNumber";
parameters[0].Values.Add(orderNumber);
rprtView.ServerReport.SetParameters(parameters);
rprtView.ServerReport.Refresh();
Here is my overload for IReportServerCredentials
public class ReportServerCredentials : IReportServerCredentials
{
public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
{
authCookie = null;
userName = password = authority = null;
return false;
}
public WindowsIdentity ImpersonationUser
{
get { return null; }
}
public ICredentials NetworkCredentials
{
get { return new NetworkCredential("myUserName", "myPassword"); }
}
}
I am able to login to "http://mydomain/reports", the default web site of the SSRS, using "myUserName" and "myPassword" (I am not sure if this is related). Still I am getting MissingEndPoint exception at SetParameters() method above. It says:
"The attempt to connect to the report server failed. Check your connection information and that the report server is a compatible version."
I am also responsible for configuring the Reporting Services for the necessary configuration for this scenario and I have heard that this issue is related to the config files in SSRS but I have no idea what to write in them. Any help is much appreciated!
The string provided for rprtView.ServerReport.ReportServerUrl should be for the Report Server service, not the Report Manager application.
Change this:
rprtView.ServerReport.ReportServerUrl = new Uri(#"http://mydomain/reports");
to this:
rprtView.ServerReport.ReportServerUrl = new Uri(#"http://mydomain/reportserver");
This page has some high-level info on the Report Manager interface, Report Server web service, and how they relate.