Trying to follow WCF delegation example on MSDN but keep getting "impersonation level" exception - wcf

Near the bottom of this article (MSDN) in a section entitled "The following code example demonstrates how to use delegation." where MSDN shows an example of how to perform delegation. I have tried to take this example and apply it to my code. In my situation, I have a client app (WCFTestClient), a middle service and a back end service. The goal is is to have the client execute a WCF exposed method on the middle service which in turn calls another method on the back end service. I'm trying to get the identity of the execution on both middle service and back end service to be that of the user executing the client:
Client ----> Middle Service ----> Back End Service.
Here is the exception that occurs on the "channel.PreparePolicy" invocation:
Could not load file or assembly 'System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
Here is my code, taken most directly from the example. I did add one line that differs from the MSDN example in my attempt to debug channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
but to no effect.
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void PreparePolicy(string requestGuid, string policyName, ulong version)
{
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
if (callerWindowsIdentity == null)
{
throw new InvalidOperationException
("The caller cannot be mapped to a Windows identity.");
}
using (callerWindowsIdentity.Impersonate())
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
Uri uri = new Uri(String.Format("net.tcp://{0}:{1}/App", "10.192.12.159", 8080));
EndpointAddress backendServiceAddress = new EndpointAddress(uri);
ChannelFactory<Service> channelFactory = new ChannelFactory<Service>(binding, backendServiceAddress);
channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
Service channel = channelFactory.CreateChannel();
channel.PreparePolicy("alkdjf", policyName, version);
}
}

I was using the WCFTestClient as my client in this scenario. Turns out its not enabled to allow delegation. I wrote my own client and enabled it for delegation and everything worked fine.

Related

WCF Service unable to call from .NET Core

I am doing something wrong and I can't figure it out ... I made .NET Framework 4 console application to communicate with SOAP Service, with use of Topshelf I deployed service on a server and with simple URL access to a method or use of Boomerang tool, I can see service is returning value
URL: http://35.231.17.237:8066/ERPCommunicationService/OriginalService/IsServiceHealthy
But now, when I try to access same service, from .NET Core project, I keep getting error:
System.ServiceModel.ProtocolException:
The remote server returned an unexpected response: (405) Method Not Allowed.
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(
SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(
String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass1_0.
<CreateGenericTask>b__0(IAsyncResult asyncResult)
--- End of stack trace from previous location where exception was thrown ---
Code is simple, I successfully used service endpoint to connect it to .NET Core project, where I can see Reference.cs autogenerated file and all methods from service are there ...
Here is service call from client side (.net core):
public async Task<bool> IsServiceHealthy()
{
try
{
string servicesUrl = $"{_iConfiguration["servicesUrl"]}/IsServiceHealthy";
//My binding setup, since ASP.NET Core apps don't use a web.config file
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
binding.MaxReceivedMessageSize = 10485760;
binding.SendTimeout = new TimeSpan(0, 0, 0, 180);
binding.ReceiveTimeout = new TimeSpan(0, 0, 0, 180);
var rsExec = new OriginalService.OriginalServiceClient(binding,
new EndpointAddress(servicesUrl));
var clientFactory = rsExec.ChannelFactory.CreateChannel();
var response = await clientFactory.IsServiceHealthyAsync();
return response;
}
catch (Exception ex)
{
logging.LogError(ex.ToString());
throw ex;
}
}
And code from server side (.NET Framework 4):
Interface:
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
Implementation:
public bool IsServiceHealthy()
{
bool serviceResult = false;
byte[] test = new byte[200];
var client = new ChannelFactory<BisWebWS.BisWebWSSOAPPortType>("BisWebWSSOAPPort")
.CreateChannel();
BisWebWS.tauthStrct auth = ServisBasic.GetAuth();
try
{
var result = client.wsTest(new BisWebWS.wsTestRequest(test));
serviceResult = result.wsTestResult;
}
catch (Exception ex)
{
logger.LogError(ex.InnerException.ToString());
}
return serviceResult;
}
When ever I google shown error, everywhere it says its server side setup, but I am kinda stuck as I installed everything there is ... I am using MS Windows Server 2012 R2 Datacenter,
Thank you for shared idea how to fix this problem
The way that we call the service by using the proxy class is an Http Post request, while there is a GET decoration on the method. It requires an Http Get request instead of Post request. This might directly cause the issue.
[OperationContract]
[WebInvoke(Method = "GET",
RequestFormat = WebMessageFormat.Json,
UriTemplate = "/IsServiceHealthy")]
bool IsServiceHealthy();
If the server host the service by using Webhttpbinding, we could directly get the result by typing the service address in the browser address bar since the default request is an Http Get request (your link is not available).
This kind of service is called Restful-style service.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-web-http-programming-model
https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
The typical call is to construct an HTTP request with a request body by using HttpClient library.
We could also call the service by using the client proxy class, like what you do. However, we should keep the binding configuration consistent between the server and the client.
WCF: There was no endpoint listening at, that could accept the message
It is too complex to call the service by using client proxy class, it is better to send Http request with HttpClient when we call Restful style service.
Besides, we could also host the service by using BasicHttpBinding, this may simplify the call. There is no need to add webhttpendpoint behavior and no need to add additional [Webget] decorations.
Simply speaking, we should maintain the binding consistent between the server and the client when using client proxy.
Feel free to let me know if the problem still exists.

Xamarin.Forms Add Connected Service on WCF only generated async method

I just begun to do Xamarin.Forms with .Net Standard 2.0 (PCL) project. I'm trying to consume my WCF web service but never got it successfully done.
I have created a simple WCF as below
[ServiceContract]
public interface IWcfConnection
{
[OperationContract]
string GetHelloWorld();
}
the implementation as below
public class WcfConnection : IWcfConnection
{
public string GetHelloWorld()
{
return "Hello World";
}
}
It's a very simple WCF, when I go to my Xamarin.Forms and right click on the "Connected Service", there is no "Add Web Service", but only "Add Connected Service", so I selected that as below
Then select "Microsoft WCF Web Service Service Provider"
Select the option as below (I untick everything because if I add more than 1 service, it will crash)
When I look into the reference.cs created, there is only async method created.
public System.Threading.Tasks.Task<string> GetHelloWorldAsync()
{
return base.Channel.GetHelloWorldAsync();
}
1) May I know why only async is created? Is it for .net standard and core, only async services will be created? As I read somewhere.
2) If so, how do I consume the web service?
In my xaml.cs file, I did the following,
WcfConnectionService.WcfConnectionClient client = new WcfConnectionService.WcfConnectionClient(new WcfConnectionService.WcfConnectionClient.EndpointConfiguration());
string abc = client.GetHelloWorldAsync().GetAwaiter().GetResult();
But I'm getting error and unable to work accordingly. Anybody got any idea?
Unhandled Exception:
System.ServiceModel.FaultException`1[[System.ServiceModel.ExceptionDetail, System.ServiceModel, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Error in deserializing body of request message for operation 'GetHelloWorld'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'GetHelloWorld' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'GetHelloWorldAsync' and namespace 'http://tempuri.org/'
At the moment Xamarin apps aren't compatible with the Task-based asynchronous WCF proxy methods that the WCF Web Service Reference connected service provider generates for .NET Standard projects (bugzilla.xamarin.com Bug 51959).
Generate an older compatible style of WCF proxy methods via checked "Generate Synchronous Operations" checkbox on Configure WCF Web Service Reference screen:
Consume the web service:
KimlikServiceReference.KPSPublicSoapClient soapClient = new KimlikServiceReference.KPSPublicSoapClient(KimlikServiceReference.KPSPublicSoapClient.EndpointConfiguration.KPSPublicSoap);
//KimlikServiceReference.TCKimlikNoDogrulaResponse response = soapClient.TCKimlikNoDogrulaAsync(TCKimlikNo, Ad, Soyad, DogumYili).Result;
bool result = soapClient.TCKimlikNoDogrula(TCKimlikNo, Ad, Soyad, DogumYili);

WCF service discovery with message security

I have a client-server application based on WCF where I'm using ServiceDiscovery to find the server from the client. During development with security turned off discovery was working fine but when we turned on message security based on certificates the ServiceDiscovery stopped working.
When I searched for a solution I found this MSDN article, http://msdn.microsoft.com/en-us/library/dd456791%28v=vs.110%29.aspx where it says;
When using message level security it is necessary to specify an EndpointIdentity on the service discovery endpoint and a matching EndpointIdentity on the client discovery endpoint. For more information about message level security, see Message Security in WCF.
I have been searching, reading and writing code but I can't seem to get this into working code. Any ideas?
Exctract of original server code:
private Binding CreateBinding()
{
WSDualHttpBinding binding = new WSDualHttpBinding(WSDualHttpSecurityMode.Message);
// Set other binding properties
return binding;
}
private static void EnableServiceDiscovery(ServiceHostBase host)
{
host.AddServiceEndpoint(new UdpDiscoveryEndpoint());
host.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
}
Compact extract of original client code:
public IEnumerable<MyServiceEndpoint> FindServicesOnNetwork()
{
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var myServiceEndpoints = discoveryClient.Find(new FindCriteria(typeof (IMyService))).Endpoints;
discoveryClient.Close();
return myServiceEndpoints.Select(endpoint => new MyServiceEndpoint(endpoint.Address.Uri.ToString())).ToList();
}

The underlying connection was closed: An unexpected error occurred on a receive. while Using WCF

I am using mvc4 as my web application which inherits a WCF service i have an Entity framework and used Code first for database Now, Entity layer is inherited to both MVC as well as to WCF but Data Access layer is only inherited to the WCF, Now when ever i call the WCF method from my controller the method is called nicely and the method works fine into the WCF and returns the expected result but when it returns result to the MVC application it throws an exception of "The underlying connection was closed: An unexpected error occurred on a receive." can anyone please help me out, following is the code respectively:-
for Controller class
public ActionResult CustomerSearch()
{
APIServiceDaman.Customer ObjTestEn = new APIServiceDaman.Customer();
using (Objjj = new APIServiceDaman.Service1())
{
var ObjTestEn2 = Objjj.GetUserDetails(1, true);
}
return View(ObjTestEn);
}
for WCF:-
public X.Entities.Customer GetUserDetails(int CustomerID)
{
X.Entities.Customer objtest = new X.Entities.Customer();
using (ObjCustomerEvidence = new CustomerManager())
{
objtest = ObjCustomerEvidence.GetCustomerByID(CustomerID);
}
return objtest;
}
for DataAccess Layer:-
public Entities.Customer GetCustomerByID(int ID)
{
return DBContext.Customer.Where(c => c.ID == ID).FirstOrDefault();
}
First of all check your web.config setting for executionTimeout and maxRequestLength on both side WCF and your MVC4 client. for more information on this please refer this below link there is a good answer given by jlchereau, follow this steps and try to check it out again, it might help you out. also try to enable WCF tracing (Tracing) and find out the root of exception it will help you a lot to resolve your issue.
http://velodocaddin.codeplex.com/discussions/40792

Can Silverlight WCF client read exceptions from an ASMX web service?

I've seen no need to upgrade my services to WCF, but I have been using WCF clients for some time to access ASMX services from .NET 3.5 ASP.NET. I figured eventually I'd hit a wall in this mismatch and I just did - but with Silverlight.
When using Silverlight to access ASMX web services I get an error like this in a popup :
An exception occurred during the
operation, making the result invalid.
Check InnerException for exception
details.
If I'm debugging I get this error :
The remote server returned an error: NotFound.
If I look in Fiddler the exception/fault is there just fine :
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Server was unable to process request. ---> ID does not match</faultstring>
<detail /></soap:Fault></soap:Body></soap:Envelope>
How do I actually get to this exception in the Silverlight client.
I need the error to be accessible at runtime with no fiddler and no debugger.
There is a property includeexceptiondetailinfaults that belongs in <behaviors> in the web.config - but this is for server side only as far as I can tell.
Am I correct in assuming that I will need to convert my asmx to svc to be able to get actual exception details in the silverlight client?
If you're happy to wrap the asmx SOAP request in your own IHttpHandler, you can force-feed a Response.StatusCode = 200 after the System.Web.Script.Services.ScriptHandlerFactory does it's work. Here's a sample;
static void ProcessService(HttpContext context)
{
//
// I'm also using this to fake/hide the path of my asmx so that
// domain.com/xml becomes the service end-point..
//
string asmx = "/Services/Some.Service.asmx";
string method = context.Request.Path.Substring("/xml".Length);
//
// ScriptHandlerFactory and friends are sealed so have to use reflection..
//
IHttpHandlerFactory fact = (IHttpHandlerFactory)Activator.CreateInstance(Type.GetType("System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions"));
Type vpt = Type.GetType("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
System.Reflection.MethodInfo mi = vpt.GetMethod("Create", new Type[] { typeof(string) });
object vp = mi.Invoke(null, new object[] { context.Request.Path });
System.Reflection.FieldInfo fi = context.Request.GetType().GetField("_pathInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _virtualPath = vpt.GetField("_virtualPath", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
_virtualPath.SetValue(vp, method);
fi.SetValue(context.Request, vp);
IHttpHandler handler = fact.GetHandler(context, context.Request.RequestType, asmx, context.Server.MapPath(asmx));
try
{
// This will trap your asmx Exception and output 500 status and soap fault
handler.ProcessRequest(context);
// force 200 status for Silverlight to receive fault code
context.Response.StatusCode = 200;
context.ApplicationInstance.CompleteRequest();
}
finally
{
fact.ReleaseHandler(handler);
}
}
No client ever gets exceptions from web services. Web services don't send exceptions - they send faults.
The details of the fault are contained in the <detail/> element of the fault message. some platforms, including WCF, parse this information in order to translate from the fault to a platform-specific exception.
Since there is no information in the <detail/> element, no translation is likely to occur.