Saturday, January 31, 2009

Sql Reporting Services 2005 - The request failed with HTTP status 401: Unauthorized.

When calling a render method for a report ala:

result = ws.Render(report, format, historyid, devinfo, parameters, credentials, showhide, out encoding, out mimetype, out reporthistoryparams,
out warnings, out streamid);

you receive:

The request failed with HTTP status 401: Unauthorized.



[WebException: The request failed with HTTP status 401: Unauthorized.]
System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) +551137
System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) +204
TestReportingServices.localhost.ReportingService.Render(String Report, String Format, String HistoryID, String DeviceInfo, ParameterValue[] Parameters, DataSourceCredentials[] Credentials, String ShowHideToggle, String& Encoding, String& MimeType, ParameterValue[]& ParametersUsed, Warning[]& Warnings, String[]& StreamIds) in c:\Projects\BidTrackerReporting\TestReportingServices\Web References\localhost\Reference.cs:1426
TestReportingServices._Default.btnGenerateReport_Click(Object sender, EventArgs e) in c:\Projects\BidTrackerReporting\TestReportingServices\Default.aspx.cs:80
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +105
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +107
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1746




Line 1424: [return: System.Xml.Serialization.XmlElementAttribute("Result", DataType="base64Binary")]
Line 1425: public byte[] Render(string Report, string Format, string HistoryID, string DeviceInfo, ParameterValue[] Parameters, DataSourceCredentials[] Credentials, string ShowHideToggle, out string Encoding, out string MimeType, out ParameterValue[] ParametersUsed, out Warning[] Warnings, out string[] StreamIds) {
Line 1426: object[] results = this.Invoke("Render", new object[] {
Line 1427: Report,
Line 1428: Format,



The wrong (or none) credentials are specified to connect to the PHYSICAL files on your system (not the database). If using a console application (or windows form) this may work ok for you, but switching to asp.net it may fail. Your current credentials will be passed over in the interactive console or windows form application so you may not have a problem there, but in asp.net will be running under the identity of either the app pool, network service, or IUSR_MachineName and thus won't have enough permissions. Thankfully, the solution is easy though. I've seen all sorts of articles for using custom permissions, but it's straight forward, just add new network credentials to the proxy class that is generated for the webservice
/reportserver/reportservice.asmx

just add this to an instance of your proxy class (of course filling in your details:
ws.Credentials = new System.Net.NetworkCredential("your login", "your password", "your domain");

Now, there is another way around this. In IIS (I'll use IIS 7 here since that is what is on my box) you can just enable permissions for a particular user on the files. In one case, you can make it generic, and add permissions for the IUSR account for read access to the reportserver folder.
Set these permissions on C:\Program Files\Microsoft SQL Server\MSSQL.4\Reporting Services\ReportServer (or whatever folder it is on your system)


Then in IIS, enable anonymous access for the folder.
I tried setting "physical path credentials" in IIS 7 as well, then the application wouldn't have to pass them in, however then you still have the ability for users to view /reportserver, but it didn't work as would be expected - ie access still denied.

so as for allowing all IUSR - I DONT RECOMMEND THIS.

Why?

1. if you do not disable the reportserver for outside access then ANYONE can view at least some details about your reports by simply navigating to https://yourserver/reportserver (although they may not be able to run your reports if you require prompting for credentials or dont store any credendtials and expect them to be passed in as part of the app)
2. Why not just include the account in the code your application uses to access the reports?
3. Who wants the risk when dealing with reports?


but if you really want to try this and enable it only for local access (this may be just fine for your environment if you are running this system on a separate network that a webserver in a dmz accesses and the report server is not accessible to the outside world. Although if the web server is compromised then an attacker could access the report server. As of now in Vista's IIS 7 UI, you cannot set the ip restriction - they left the UI element for it out. If you want to set this in Vista, you need to install IIS 7 Admin Pack. You MUST FIRST INSTALL SP1 for Vista otherwise you can cause the admin console to fail. There's a nice blog about the pack at:
http://blogs.msdn.com/carlosag/archive/2008/03/24/IISAdminPackRequestFiltering.aspx
The module in question is IpRestrictionModule
for the admin pack see:
http://www.iis.net/downloads
http://www.iis.net/downloads/default.aspx?tabid=34&g=6&i=1682


If you want to limit to a particular address in IIS see:
--------------------------------
http://technet.microsoft.com/en-us/library/cc730889.aspx
--------------------------------
To configure an IPv4 address restriction for the management service
Open IIS Manager. For information about opening IIS Manager, see IIS 7.0: Open IIS Manager.

In the Connections pane, click the server node in the tree.

In Features View, double-click Management Service.

On the Management Service page, in the Actions pane, click Stop to stop the management service.

Select the Enable remote connections box.

Under IPv4 Address Restrictions, use one of the following procedures:

Click Allow to allow an IPv4 address or range of IPv4 addresses to connect to the management service.

Click Deny to deny an IPv4 address or range of IPv4 addresses from connecting to the management service.

In the Add Allow Connection Rule dialog box or Add Deny Connection Rule dialog box, use one of the following procedures, and then click OK:

To allow or deny a specific IP address, click Specific IPv4 address, and then type the IPv4 address in the box.

To allow or deny a range of IP addresses, click IPv4 address range, type an IPv4 address in the box, and then type a subnet mask in the Subnet mask box.

In the Actions pane, click Apply and then click Start.

---------------------------------------------


Now for the better solution, try the following code.
This was just from some local testing, but should work:

byte[] result;
string report = "/SomeCustomReportFolder/SomeReport";
localhost.DataSourceCredentials[] credentials = null;
string showHide = null;
string encoding="";
string mimeType="";
string format = "PDF";
string historyId = null;
string devinfo = "";
localhost.Warning[] warnings = null;
localhost.ParameterValue[] reportHistoryParams = null;
string[] streamId = null;
localhost.SessionHeader sh = new localhost.SessionHeader();

localhost.ReportingService ws = new TestReportingServices.localhost.ReportingService();
ws.SessionHeaderValue = sh;
ws.Credentials = new System.Net.NetworkCredential("your login", "your password", "your domain");

localhost.ParameterValue[] parameters = { new TestReportingServices.localhost.ParameterValue() };
parameters[0].Name = "parameter name"; //Case SENSITIVE!!!
parameters[0].Value = "parameter value";
result = ws.Render(report, format, historyid, devinfo, parameters, credentials, showhide, out encoding, out mimetype, out reporthistoryparams,
out warnings, out streamid);



enjoy : )

Tuesday, January 27, 2009

Fixing Sql Reporting Services for FireFox

Sql Reporting Services has an issue with firefox in which reports will show about one inch tall in the report viewer. There is an easy fix for this, but it seems to depend on the version of firefox.
It seems to be the support of attributes on IFrame in firefox.
I'm running on 3.05 and the following works for me:

Load
C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\Pages\reportviewer.aspx

make sure this is in the body tag (prob is by default):

<body style="margin: 0px; overflow: auto">

and the report viewer line should have this added to it: style="display:table;"
so:
<RS:ReportViewerHost style="display:table;" ID="ReportViewerControl" runat="server" />

Some say add one of the following to the ReportingServices.css, however that did not work for me. The above fix did however.


.DocMapAndReportFrame
{
min-height: 660px;
min-width: 1280px;
}
.MenuBarBkGnd
{
min-width:1000px;
}

Sunday, January 25, 2009

Making sure you don't process page_load code when doing ajax

When you perform an async call using ajax, you will cause page_load to fire.
There are two ways around this I use.

During ajax, we are having a postback, so Page.IsPostBack is true, and also ScriptManager.IsInAsyncPostBack is true as well. These two items generally point to ajax.
if (!Page.IsPostBack && !ScriptManager.IsInAsyncPostBack)


If you want to be certain - then you can name your controls with a particular prefix, for example "ajax" so a button could be ajaxLoadDynamicData.

In your Page_Load:

Control ctl = PostBackInformation.GetPostBackControl(this.Page);
if ((ctl != null) && (ctl.ID.IndexOf("ajax", 0, StringComparison.InvariantCultureIgnoreCase) > -1))
{
return;
}

PostBackInformation.GetPostBackControl is not built in - I don't recall where I got it or customized it from (there are several references to it on the net)


public static System.Web.UI.Control GetPostBackControl(System.Web.UI.Page page)
{
Control control = null;
string ctrlName = page.Request.Params["__EVENTTARGET"];
if (ctrlName != null && ctrlName != String.Empty)
{
control = page.FindControl(ctrlName);
}
// if __EVENTTARGET is null, the control is a button type and we need to
// iterate over the form collection to find it
else
{
string ctrlStr = String.Empty;
Control c = null;
foreach (string ctl in page.Request.Form)
{
// handle ImageButton controls ...
if (ctl.EndsWith(".x") ctl.EndsWith(".y"))
{
ctrlStr = ctl.Substring(0, ctl.Length - 2);
c = page.FindControl(ctrlStr);
}
else
{
c = page.FindControl(ctl);
}
if (c is System.Web.UI.WebControls.Button
c is System.Web.UI.WebControls.ImageButton)
{
control = c;
break;
}
}
}
return control;
}


so depending on your scenario you can detect when doing a postback from an ajax (or any) control and ignore processing.

Saturday, January 24, 2009

Generating 'Wait' Images

Ever want a neat image on your page to display during some wait operation (ie ajax)?


Go to:
http://www.ajaxload.info

and you can generate one for free. nice!

Thursday, January 22, 2009

Enabling POP3/IMAP in Exchange Server 2007

There are plenty of articles on the net for this, but these are my notes, mostly for my own reference.. and if someone else runs into the same issues I do.

Scenario: Exchange 2007 currently only used via OWA (outlook web access). Users outside of the network want to use the full functionality of Exchange.



error: Exchange 2007 POP3 "Connection not valid in this state"


1. Start the microsoft exchange pop3 and imap service. set the service state to automatic. This can be done in the exchange shell, or just load it up in services.msc and set the service there. Start them both.
Make sure the ports are set (should be by default) in the Exchange Management Console
server configuration - client access - pop3 and imap4

2. Make sure IMap and/or Pop3 its set on the user's account. In Exhange System Manager, you can set a user's avaialble access (OWA/IMAP/POP3, etc)
3. Test it out via a telnet session. As of this point - it will fail since by default plain text passwords is not allowed. you must use ssl,tls.
The error you will receive when you try a telnet session is: "Command is not valid in this state"
So: enable plain text and test through telnet.

from an exchange command shell run: get-PopSettings

UnencryptedOrTLSBindings SSLBindings LoginType X509CertificateName
------------------------ ----------- --------- -------------------
{0000:0000:0000:0000:0... {0000:0000... SecureLogin lois

Note the LoginType us SecureLogin. In this simple configuration we will allow plain text login.
Run this command in the Exchange Shell:
Set-PopSettings -LoginType PlainTextLogin
If you don't do this, you will
Restart the exchange pop3 service. You can do the same for imap - set the login and restart the service.

Then try something like this (for pop3):
telnet localhost 110

type these commands (replace with your info)
user test
pass sometestpwd
stat
list


+OK QPOP (version 2.53) at myserver.local.com starting.
user test
+OK Password required for test.
pass sometestpwd
+OK testhas 2 messages (784 octets).
stat
+OK 2 784
list
+OK 2 messages (784 octets)


ok - good. pop3 is working.


4. enable firewall port 110 to allow remote clients in and test remotely via a setup in outlook.

No problem so far.. it is all working ok. I then try to use ssl, tls, secure password authentication (spa) and even with ports open it fails. I did get a message about the cert on the server and accepted it:

After that I could not make a valid connection. I am still investigating that one.
Similiar errors receives are:
Log onto incoming mail server (IMAP): General authentication failed. None of the authentication methods supported by your IMAP server (if any) are supported on this computer.

Monday, January 19, 2009

More issues with Sql Reporting Services - The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel

Problem: Installed on a new server, and cannot go to:

https://localhost/reports

I receive: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

Odd, as ssl is ok (and the root ca authority which is the server itself has been added as a trusted root on the system).

This is interesting in my case, the web service identity wasn't set and it wouldn't allow me to set it to the "ReportServer" app pool, I received an error

ReportServicesConfigUI.WMIProvider.WMIProviderException: A virtual directory must first be created before performing this operation.
at ReportServicesConfigUI.WMIProvider.RSReportServerAdmin.SetWebServiceIdentity(String applicationPool)



I tried to apply default settings and received:

System.Runtime.InteropServices.COMException (0x80004005) at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) at System.Management.ManagementObject.InvokeMethod(String methodName, ManagementBaseObject inParameters, InvokeMethodOptions options) at ReportServicesConfigUI.WMIProvider.RSReportServerAdmin.ResetVirtualDirectoryMappings()

awesome.

Since this is a shared server, I tried to create a new virtual directory so I could use a specific virtual dir and app pool I'd create. Upon giving a name to create, the config tool crashed.

most awesome.

Upon loading the tool and trying to set web service identity again, it let me do it for the Report Server, but failed for the Report Manager with:

ReportServicesConfigUI.WMIProvider.WMIProviderException: A virtual directory must first be created before performing this operation.
at ReportServicesConfigUI.WMIProvider.RSReportManagerAdmin.SetReportManagerIdentity(String applicationPool)

yes, a virtual directory indeed exists and somehow it doesn't recognize it.

ok.. lets go back a bit. Im not sure when sp2 was installed on this machine and I have seen issues with sp2 having to be installed again, but thats usually a different error along the lines of:

Sql errorystem.Data.SqlClient.SqlException: Could not find stored procedure 'GetDBVersion'. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)

So I just deleted the virtual directories from IIS for ReportServer and Reports, recreated them in the config tool, and chi was restored to the universe.

installed the certificate to:

Enterprise Trust\Local Computer and verified it was trusted root authority.

same issue.


Turning of ssl for that folder and trying with http://localhost/reports

same issue.

In Reporting services configuration manager -> Report server virtual directory -> Certificate name, nothing is specified (plus thats the /ReportServer url)


Based on some readings, I reset IIS since some people had an issue unchecking ssl until they restarted IIS. No go for me.

I checked everything with the certificate. The server's certificate is from Exchange 2007 - IE auto generated when it was installed. I checked in trusted root certification authorities and the server's root ca certificate was in there.
I checked in IIS - the certificate was OK, not expired and showing up as OK as well.

since I was trying to connect to localhost/reports I used the system name:
http://lois/reports

same problem.

so at this point, ssl is off from the sql server reporting services configuration tool, and I've unchecked it from the virtual directory in IIS.

So whats the solution?
In the file notepad d:\Program Files\Microsoft SQL Server\MSSQL.2\Reporting Services\ReportManager\RSWebApplication.config
there are two items which need addressing

1. ReportServerUrl, which in my case was blank and ReportServerVirtualDirectory which was set to Reports

According to MS, they are mutually exclusive, IE you can only set one or the other. So I removed the virtual directory entry and set the report server url, and saved it and voila.. it worked:

<reportserverurl>http://lois/reportserver</reportserverurl>
<reportservervirtualdirectory></reportservervirtualdirectory>


another note: if you have generated your own certificate, the system you are deploying from won't be able to deploy to the target server as well. You will receive the same error in addition (in visual studio) viewing the extended error information you may see:
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. "
"The remote certificate is invalid according to the validation procedure. (System)"

So, navigate from your system to the report server. View the certificate and import it into the trusted root certification authorities, and then on the certificate path tab (right click on the document and choose properties) check to make sure there are no Xs on the certificate issuer. If there is - import it from there into the same store - trsuted root certification authorities.


OH but wait!
I can see all the report definitions, but when I attempt to run them I receive:
The request failed with HTTP status 401: Unauthorized.

hmm. I tried all different auth options, and removing ssl.

nothing.
If I turned off integrated auth and turned on anonymous access, I'd receive
The permissions granted to user 'ABBSATT\reportuser' are insufficient for performing this operation.


now.. if I used the url to go to the report server using ssl directly, it worked just fine. That was the clue I wasn't using the correct url in the rswebapplication.config

So, I went into the reporting services config tool, and did the "Apply Default Settings" on each so I could start from scratch.

Again (as expected) I was back to:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

I went into rswebapplication.config and changed the url I modified above to https://......
instead of http, and voila. it worked. all good... in all scenarios.


Network provider issues and Sql Server Reporting Services

I installed reporting services on my new laptop.
I tried running it, and it hung for a long time and came back with an error:

Logon failed. (rsLogonFailed)Could not load file or assembly 'BCMLogon, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417)Required permissions cannot be acquired.

hmm. why is a library made by broadcom being an issue just connecting to sql reporting services on a local machine. I changed some settings in IIS for authentication to allow everything same as the actual report server which I could get in to configure items, just not run a report.



Finally the light went off - this library is:
"BcmLogon: Provides credential information (user name, password, domain) used by wireless management software for login to wireless networks. Optionally enables wireless login at startup for SSO environments.Dell Wireless WLAN Card Logon Provider"

As such inthe system its a network provider. A quick search of the registry for BCMLogon shows:

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider]
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\HwOrder]"ProviderOrder"="LanmanWorkstation,RDPNP,webclient,BCMLogon"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\NetworkProvider\Order]"ProviderOrder"="LanmanWorkstation,RDPNP,webclient,BCMLogon"

Hey.. its last in the chain here (and you can verify by going into your network connections, advanced menu, and then advanced settings, and then provider order.
Dell Wireless WLAN Card Logon Provider is indeed the last one.

now in my case, I dont need it.. so the fix is simple. I renamed the dll in c:\windows\system32. I can still acess my wireless network just fine.

I did try configuring this assembly, permissions were ok on the file itself, and it should be full trust, so not sure where is was breaking down, but the fix worked for me.. for now and its late anyways : )