Reputation: 95
We currently have a self-hosted ASP.NET Web Forms application that uses an SSRS reporting back end. The reports are accessed using the ReportViewer control 10.0.0.0. We have a business need to move this workload to Azure.
We migrated our databases to SQL Azure and set up an Azure Web Site (Web App) and the portion of the app used to maintain the data in the databases works fine. We set up a VM running SQL2016, configured SSRS and uploaded our report RDL and DataSources. The reports run fine through the SSRS web portal.
When we try and access the reports through the Web Application we are getting a 401: Unauthorized. We are using a local Windows login on the SSRS server for authentication (we tried a SQL server login, with the same results). The Windows login has been set up in the SSRS portal with access to the reports and has access to the database through SQL server. The Web application is not using impersonation (I explicitly turned it off to be sure).
I wrote a quick Windows Form application using the Windows version of the Report viewer control and this works fine. The setup code for the viewer control is essentially the same. I have tried the web version with and without specifying the "machine name" in the credentials for a local account.
I have included the setup code from the Web App below. At this point, I don't think it is a code problem as much as a Web setup issue. Any help or pointers will be greatly appreciated.
Eric.
Dim myCreds As System.Net.CredentialCache = New System.Net.CredentialCache
Dim storedParams As Microsoft.Reporting.WebForms.ReportParameterCollection = CType(Session("Current_ReportParams"), Microsoft.Reporting.WebForms.ReportParameterCollection)
With ReportViewer1
.Reset()
.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote
.ServerReport.ReportServerUrl = New Uri(ReportServer) 'Report Server URL
.ServerReport.ReportPath = String.Format("{0}/{1}", ReportPath, ReportFileName) 'Report Name
.ServerReport.SetParameters(storedParams)
myCreds.Add(New Uri(ReportServer), "Basic", New System.Net.NetworkCredential("user", "password", "machine"))
.ServerReport.ReportServerCredentials = myCreds
.ShowParameterPrompts = False
.SizeToReportContent = True
.ServerReport.Refresh()
End With
Upvotes: 0
Views: 1140
Reputation: 95
I will post this as an answer instead of a comment. In working with Microsoft Support, I modified my code somewhat. I added a class that implemented IReportServerCredentials that returned a NetworkCredential with the user name and password. We still persisted in getting the 401 error. We started running network traces and noticed that the credentials were not showing up in the trace as we expected. We did see, however, NTLM negation taking place and failing.
We verified the rsReportServer.config had basic authentication enabled and disabled NTLM and Kerberos authentication just to be safe. Still failed with a 401.
After several back and forths with MS and many Bingle searches, we discovered that the .ServerReport.SetParameters method makes a call to the SSRS server. We were setting our .ServerReport.ReportServerCredentials after this. Simply moving the .ServerReport.ReportServerCredentials before the .ServerReport.SetParameters method solved the issue. The updated code is below.)
So, this was a programming error and not a configuration error. This will affect any SSRS instance that is not in the same domain as the website calling the ReportViewer control.
Imports Microsoft.Reporting.WebForms
Imports System.Net
Imports System.Security.Principal
Public Class ucReportPreview
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
'gets the report viewer control from the session if it exists
If Not Session("Current_ReportFileName") Is Nothing Then
Dim sysOpt As New SystemOption
'Dim ReportServer As String = sysOpt.LookupValueByShortDescription("ReportServer")
'Dim ReportPath As String = sysOpt.LookupValueByShortDescription("ReportPath")
'Dim ReportFileName As String = Session("Current_ReportFileName").ToString
Dim ReportServer As String = "http://logsdon-ssrs/ReportServer"
'Dim ReportPath As String = "/InfoRail V5/IR-20141118"
Dim ReportPath As String = "/userinfo"
Dim ReportFileName As String = "Certification Requirements Due (By Employee)"
Dim myCreds As IReportServerCredentials = New MyReportServerCredentials("<userName>", "<password>", "<machine-or-domainName>")
If Not Session("Current_ReportParams") Is Nothing Then
Dim storedParams As Microsoft.Reporting.WebForms.ReportParameterCollection = CType(Session("Current_ReportParams"), Microsoft.Reporting.WebForms.ReportParameterCollection)
With ReportViewer1
.Reset()
.ServerReport.ReportServerCredentials = myCreds
.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote
.ServerReport.ReportServerUrl = New Uri(ReportServer) 'Report Server URL
.ServerReport.ReportPath = String.Format("{0}/{1}", ReportPath, ReportFileName) 'Report Name
.ServerReport.SetParameters(storedParams)
.ShowParameterPrompts = False
.SizeToReportContent = True
.ServerReport.Refresh()
End With
Else
Dim storedParams As Microsoft.Reporting.WebForms.ReportParameterCollection = CType(Session("Current_ReportParams"), Microsoft.Reporting.WebForms.ReportParameterCollection)
With ReportViewer1
.Reset()
.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Remote
.ServerReport.ReportServerUrl = New Uri(ReportServer) 'Report Server URL
.ServerReport.ReportPath = String.Format("{0}/{1}", ReportPath, ReportFileName) 'Report Name
.ServerReport.ReportServerCredentials = myCreds
.ShowParameterPrompts = True
.SizeToReportContent = True
.ServerReport.Refresh()
End With
End If
End If
End If
End Sub
Private Sub Page_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
'destroys the report viewer control in the session
Session("Current_ReportParams") = Nothing
End Sub
Protected Function GetReportName(Reportid As Integer) As String
Dim retval As String = String.Empty
'Dim rt As New ReportTableBLL(System.Web.HttpContext.Current.Session("ConnectionString"))
'retval = rt.GetReportfilenameByReportid(Reportid)
Return retval
End Function
End Class
Public NotInheritable Class MyReportServerCredentials
Implements IReportServerCredentials
Private _userName As String
Private _password As String
Private _domainName As String
Public ReadOnly Property ImpersonationUser() As WindowsIdentity Implements IReportServerCredentials.ImpersonationUser
Get
Return Nothing
End Get
End Property
Public ReadOnly Property NetworkCredentials() As ICredentials Implements IReportServerCredentials.NetworkCredentials
Get
Return New NetworkCredential(_userName, _password, _domainName)
End Get
End Property
Public Function GetFormsCredentials(ByRef authCookie As Cookie, ByRef userName As String, ByRef password As String, ByRef authority As String) As Boolean Implements IReportServerCredentials.GetFormsCredentials
authCookie = Nothing
userName = Nothing
password = Nothing
authority = Nothing
Return False
End Function
Public Sub New(userName As String, password As String, domainName As String)
_userName = userName
_password = password
_domainName = domainName
End Sub
End Class
Upvotes: 1