How to validate Token Id before calling any web methods? - wcf

I am passing the TokenId as Soap Header for all the requests.
<soapenv:Header> <tem:TokenIdentity>12345</tem:TokenIdentity> </soapenv:Header>
for example I have 5 webmethods.
I would like that ValidateTokenId() method which shoule be called automatically before accessing any webmethods.
Anybody done this before?

I got the solution to validate the token
WCF Service implemented(IDispatchMessageInspector) the following two methods to take care of Soap header validation and
Logging the SOAP Requests and SOAP Responses.
AfterReceiveRequest
So all the incoming SOAP requests are automatically called for ValidateToken() method and will be logged too.
BeforeSendReply
All the response SOAP messages are logged here.
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
int headerIndex1 = OperationContext.Current.IncomingMessageHeaders.FindHeader("TokenIdentity", "");
XmlReader r = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(0).ReadSubtree();
XElement data = XElement.Load(r);
var tokenValue = (string)data;
ValidateToken(tokenValue);
//Log the Request with Log4Net or something
//Console.WriteLine("IDispatchMessageInspector.AfterReceiveRequest called.");
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
//Log the Response with Log4Net or something
//Console.WriteLine("IDispatchMessageInspector.BeforeSendReply called.");
}
#endregion

Related

WCF client call api with Bearer token (.net core 3.1) - unauthorized call

I am trying to call a soap api that requires a bearer authorization token and a subscription key from .net core but I am getting the following exception that I don't understand.
MessageSecurityException: The HTTP request is unauthorized with client
authentication scheme 'Anonymous'. The authentication header received
from the server was ''.
I have verified that the subscription key and token is working with SoapUI. This is the SoapUI call:
POST {{URL}} HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "{{ACTION}}"
Authorization: Bearer Tplen
Subscription-Key: {{KEY}}
Content-Length: 343
Host: {{HOST}}
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/12.0.1)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="{{REPLACED}}">
<soapenv:Header/>
<soapenv:Body>
<ser:REPLACED>
<!--Optional:-->
<ser:REPLACED>VALUE</ser:REPLACED>
</ser:REPLACED>
</soapenv:Body>
</soapenv:Envelope>
This is my code to call the endpoint:
var binding = new BasicHttpsBinding();
var factory = new ChannelFactory<ITestContractChannel>(binding, new EndpointAddress(url));
factory.Endpoint.EndpointBehaviors.Add(new Test());
var channel = factory.CreateChannel();
var result = await channel.GetTestAsync("1");
Using Test endpoint behavior
public class Test : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new TestHeaderInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
And following code to add the headers
public class TestHeaderInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
var httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add("Subscription-Key", key);
httpRequestMessage.Headers.Add("Authorization", "Bearer "+ token);
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
return null;
}
}
According to the error message you provided, I think this may be because your custom headers were not successfully added to the message. I think you can try to use OperationContextScope to add custom headers. There is an example in this link. You can refer to it:
IClientMessageInspector BeforeSendRequest method is not working when setting header using OperationContextScope

How do you reject a message in WCF?

I'm moving to Azure which uses a security token to authenticate a user. So now I'm passing the security token in the header of the message and reading it using an IDispatchMessageInspector behavior on the server side. The basics mechanics work pretty well, but when the token can't be authenticated I need to reject it just as if it had failed the UserNamePasswordValidator. Any ideas how I finish this code:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (!this.IsAuthenticated(securityToken))
{
<Return Error Message Structure>
}
}
Simple option is to throw a FaultException.
object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
try
{
if (!this.IsAuthenticated(securityToken))
{
throw new FaultException<string>("some message");
}
}
catch (FaultException e)
{
throw new FaultException<string>(e.Message);
}
return null;
}
If you want something more elegant and control over the HttpStatus code that is returned (default is 500) then you can implement a Endpoint Behavior Extension which registers a Dispatch Message Inspector that watches for faults. See following post:
http://www.shulerent.com/2016/05/31/returning-custom-http-status-codes-for-wcf-soap-exceptions/

The equivalent of Fiddler SOAP request/response stored in database

I write a lot of WCF services to other services. I have had trouble with getting Fiddler to log the SOAP messages before but now I have that working. But my boss wants something without Fiddler at all where I can take the SOAP message going out and the one coming in logged to the database. I have looked a lot at WCF Logging and Diagnostics and extending it with Database Source Listener but I cant find an implementation of a Database Source Listener to use.
I don't think that's what he even wants. He wants the equivalent of Fiddler's SOAP request/response displays written to the database. Can anyone help me please?
You have two possibilities:
Write custom WCF Trace Listener, calling database procedure to store logging data:
public class AsyncMSMQTraceListener : TraceListener
{
public override void TraceData(TraceEventCache eventCache, string source,
TraceEventType eventType, int id, object data)
{
// eventType like for example TraceEventType.Information
var message = data.ToString();
// Here call datbase save log with message
}
public override void Write(string message)
{
}
public override void WriteLine(string message)
{
}
}
but in this way you'll get trace messages, where request/response is only a part of it.
Write custom Message Inspector class:
public class ConsoleOutputMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
// Here you can use buffer.CreateMessage().ToString()
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
reply = buffer.CreateMessage();
// here you can use buffer.CreateMessage().ToString()
}
}
Note: Regardless which method you choose, I would suggest to make some kind of an asynchronous call to the database to not block normal service flow.

WCF REST services IErrorHandler

I have a WCF REST service which is consumed on the client by the classical :
WebResponse response = request.GetResponse();
I want to intercept any errors that appear in the service and deliver them to the client. By default behavior, when an exception occurs in the service an faultexception is thrown and the channel is faulted, therefore on the client I receive a Bad request.
I want to be able to return the client the stackstrace and override the behaviour not to fault the channel.
For that I have implemented the IErrorHandler
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
fault = Message.CreateMessage(version, string.Empty, String.Format("An unknown error has occurred. The error identifier "), new DataContractJsonSerializer(typeof(string)));
fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
fault.Properties.Add(HttpResponseMessageProperty.Name, HttpStatusCode.Accepted);
}
}
the question is even if I register this on the service, I can debug the errorhandler, but the channel is still faulted so I still receive a bad request in the client.
I use the following factory for the client:
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
ServiceEndpoint ep = host.AddServiceEndpoint(serviceType, new WebHttpBinding(), "");
host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
return host;
}
The question is how can I prevent the channel from getting faulted in the errorhandler.
It should work. I have the same situation and I set the fault also in the ProvideFault method. The only thing I can think of is that I am not seeing you create a FaultException from which you'd call CreateMessageFault().
Here is an example:
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
// we don't want the communication channel to fault, so we'll provide a general purpose fault with the exception provided.
var fe = new FaultException(error.Message);
MessageFault msg = fe.CreateMessageFault();
fault = Message.CreateMessage(version, msg, "YourActionNamespace");
}

Logging requests/responses in a WCF REST service

I'm looking for a way to log both requests and responses in a WCF REST service. The WCF REST starter kit comes with a RequestInterceptor class which can be used to intercept requests, but there does not seem to be an equivalent for responses. Ideally, I'd like to be able to intercept a response just before it's sent over the wire, e.g. when the underlying service method returns. Any suggestions?
Notice that if you want to intercept the raw message, and not the parameters, you can inject your implementation of IDispatchMessageInspector instead of the IParameterInspector extension point that Dani suggests.
There is a technic in WCF:
you create InstrumentedOperationAttribute that derives from Attribute, IOperationBehavior.
Inside you implement:
public void ApplyDispatchBehavior(
OperationDescription operationDescription,
DispatchOperation dispatchOperation
)
{
dispatchOperation.ParameterInspectors.Add(
new ServerPI()
);
}
and the ServerPI() class is what does the magic:
you do everything you need in beforecall and aftercall methods:
class ServerPI : IParameterInspector
{
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
Guid result = (Guid)correlationState;
// ...
}
public object BeforeCall(string operationName, object[] inputs)
{
string parameter1 = inputs[0] as string;
return Guid.NewGuid();
}
}