Authenticating against ReportExecution2005.asmx in .NET Core
Asked Answered
C

4

6

I'm trying to execute an SSRS report in .NET Core.

Since .NET Core doesn't let you add service references, you have to use the WCF Connected Service to add a reference to the WSDL so it can generate .NET Core compatible code. This is what I did for ReportExecution2005.asmx (SQL Server 2016 if it matters).

I tried using the following to authenticate against the service:

var rsExec = new ReportExecutionServiceSoapClient(ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap,
                                                  new EndpointAddress("http://server/ReportServer/ReportExecution2005.asmx"))
                    {
                        ClientCredentials =
                        {
                            Windows =
                            {
                                AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation,
                                ClientCredential = new NetworkCredential("username", "password")
                            }
                        }
                    };

Also tried setting the Username object instead of Windows object, but either way the result is the following error:

MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM'.

Looking at Fiddler, the code isn't passing the credentials along.

This is the code that got generated off the WSDL

public ReportExecutionServiceSoapClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress)
   : base(ReportExecutionServiceSoapClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
{
    this.Endpoint.Name = endpointConfiguration.ToString();
    ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}

static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);

I may be mistaken, but isn't this calling the private method ConfigureEndpoint with the ClientCredentials object before the ClientCredentials object has even been set?

I'm not seeing any other way to configure the ClientCredentials or call ConfigureEndpoint, so how exactly are you supposed to authenticate? The other constructors are basically the same thing, except for one which takes in a Binding instead of an EndpointConfiguration. Any ideas?

Complainant answered 30/1, 2017 at 18:15 Comment(4)
Also, I know I can just put this into a .NET Framework library and reference it from there, but I'd like to try and get it working just using .NET Core.Complainant
How is your security model set up? Are you using a local user on the ssrs instance to request from ssrs? If so is does that user have permission to do so?Puton
Another thing is to check your wfc binding's transport security configuration,.Puton
@RossBush, it is a local account with permissions. I tested the service using the same credentials under .NET 4.6 and equivalent code and was able to execute the report without issue. As for the WCF binding, I'm afraid I don't actually know much about that. I haven't tinkered with anything on the server itself, pretty much just installed SSRS using the default options.Complainant
R
4

After fighting with this for a day, I found an approach that seems to work, by using the only constructor that does not immediately call ConfigureEndpoint as pointed out in the question. If I create a binding that specifies NTLM, and I pass that binding along with a manually created endpoint, it works:

var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly)
{
    Security =
    {
        Transport = new HttpTransportSecurity {ClientCredentialType = HttpClientCredentialType.Ntlm}
    }
};

var reportService = new CssbiReportService.ReportExecutionServiceSoapClient(binding,
    new EndpointAddress("http://myserver/ReportServer/ReportExecution2005.asmx"));

This is working for me in .NET Core.

Roveover answered 26/1, 2019 at 22:47 Comment(0)
A
0

Edit: update the code for .NET Core

Unfortunately, I don't have SSRS here to test the code right now.

But, try this code (no error check):

// parameters of report (if any)
ParameterValue[] parameters = {new ParameterValue {Name = "ApontamentoID", Value = "364"}};

// connect to the service
ReportExecutionServiceSoapClient webServiceProxy =
  new ReportExecutionServiceSoapClient(
    ReportExecutionServiceSoapClient.EndpointConfiguration.ReportExecutionServiceSoap,
    "http://report_server_url/ReportExecution2005.asmx?wsdl");

// logon the user
await webServiceProxy.LogonUserAsync("username", "password", null);

// ask for the report
await webServiceProxy.LoadReportAsync("/report_path", null);
await webServiceProxy.SetExecutionParametersAsync(parameters, null);

// you can use RenderStreamRequest too
RenderRequest request = new RenderRequest("pdf", null);
RenderResponse response = await webServiceProxy.RenderAsync(request);

// save to the disk
System.IO.File.WriteAllBytes(@"c:\temp\output.pdf", response.Result);

// logoff the user
await webServiceProxy.LogoffAsync();

// close
await webServiceProxy.CloseAsync();
Arapaima answered 30/1, 2017 at 19:29 Comment(4)
Is this .NET Core code? I can't put the ReportExecutionserviceSoapClient in a using statement because it doesn't implement IDisposable.Complainant
ops. sorry! now I read that you're using .net core! my bad! I'm using NET 4.6.1.Arapaima
I update the code! can you check? Maybe there's something missing, but I did not find any examples or better documentation (like everything about ssrs).Arapaima
thanks for the update. When I call LogonUserAsync, I get the same error mentioned in the original question. It looks like I have to be authenticated to be call that method.Complainant
R
0
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly)
{
    Security =
    {
        Transport = new HttpTransportSecurity {
           ClientCredentialType = HttpClientCredentialType.Ntlm
        }
    }
};


yourClient = ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress) {
                ClientCredentials =
                { ...

^^^ This for NTLM.

Also, I was getting read-only errors trying to set some properties on the client after it had been created. In case it helps someone, properties must all be set at client-creation time to avoid this as per "yourClient" above.

Rauch answered 11/3, 2022 at 23:5 Comment(0)
C
0

I had the same problem, for me the following addition was helpful:

ReportExecutionServiceSoapClient rsClient = new ReportExecutionServiceSoapClient(rsBinding, rsEndpointAddress);

rsClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
Chaparral answered 1/8, 2022 at 11:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.