I am building a ServiceStack service that runs on several dozen embedded devices. I'd like to ensure that all communication to the device occurs over an encrypted channel. I've researched various SSL/TLS options, but managing several dozen different certs, or publishing a single cert to dozens of device, seems like a lot of overhead.
I've been looking at the Encrypted Messaging feature, but it appears that this only offers a transparent overlay, which would allow either a plain DTO or an encrypted DTO to be sent.
Is there any way to restrict my endpoints to ONLY accept EncryptedMessage DTOs, while preserving the ability to process them internally? Some sort of filter that can tell the original DTO came from an EncryptedMessage originally maybe?
I've considered the Service Gateway, but it seems like I'd have to have two separate AppHosts - one to receive the encrypted data and one (internal only) to process & respond. Seems like there should be a better way.
I've just marked Encrypted Messaging Requests as Secure in this commit which will allow you to use the Restricting Services Attribute to ensure only secure Requests are made with:
[Restrict(RequestAttributes.Secure)]
public class SecureOnlyServices { }
[Restrict(RequestAttributes.InSecure | RequestAttributes.InternalNetworkAccess,
RequestAttributes.Secure | RequestAttributes.External)]
public class InternalHttpAndExternalSecure { }
This change is available from v4.5.13 that's now available on MyGet.
Earlier versions of ServiceStack can check the IRequest.Items dictionary to determine if it's an Encrypted Messaging Request with:
var isEncryptedMessagingRequest = base.Request.Items.ContainsKey("_encryptCryptKey");
if (!isEncryptedMessagingRequest)
throw new HttpError.Forbidden("Only secure requests allowed");
Related
I try to configure client communicating with SOAP service written in Java, yet I failed so far. While it's pretty easy to connect with that service using SoapUI (I just need to put these two certificates in adequate places and it just works) it's pretty far from being easy (and intuitive) in C#.
Service uses two different certificates - one for signing message (binary token) and one for TLS encryption. I implemented my own classes for that thing using this tutorial:
https://learn.microsoft.com/pl-pl/dotnet/framework/wcf/extending/how-to-use-separate-x-509-certificates-for-signing-and-encryption
Thanks to that I'm able to connect and send request, but that's not the end of the problems. Next error was "The incoming message was signed with a token which was different from what used to encrypt the body. This was not expected."
According to my research I should just erase whole Security header and configure my client to allow unsecured response. Therefore I should implement my own MessageEncoder what I actually did using this:
https://learn.microsoft.com/pl-pl/dotnet/framework/wcf/samples/custom-message-encoder-custom-text-encoder
I only added one extra function that should erase security header, just like #nuronce did in this thread:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/16de05ed-3776-40e5-b576-139603e4b374/the-incoming-message-was-signed-with-a-token-which-was-different-from-what-used-to-encrypt-the-body?forum=wcf
But that's still not the end of the problems... Right now it says: "The message version of the outgoing message (Soap11 (http://schemas.xmlsoap.org/soap/envelope/) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)) does not match that of the encoder (Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)). Make sure the binding is configured with the same version as the message."
That's weird because in every place with MessageVersion property in my custom encoder classes it's set to MessageVersion.Soap11 as default value that should not be modified, because I don't change anything in my CustomTextMessageEncodingBindingSection.
For every solution WCF gives me another problem and I'm losing my patience for that, because these solutions are not so easy to find and adjust to my needs. I'm also pretty sure that even if I go through my current problem - I will find another one, maybe harder or even impossible to resolve.
Are there other .NET libraries that will allow me to use two different certificates by default and save my code from growing, hard to understand convolutions? And if there is none, how can I deal with WCF?
There is very little documentation (that I found) on how the distributed RedisEvents work in ServiceStack.
The documentation says:
One limitation the default MemoryServerEvents implementation has is being limited for use within a single App Server where all client connections are maintained. This is no longer a limitation with the new Redis ServerEvents back-end which utilizes a distributed redis-server back-end to provide a scale-out option capable of serving fan-out/load-balanced App Servers. If you’re familiar with SignalR, this is akin to SignalR’s scaleout with Redis back-end.
It also says how to add the plug-in, but then there is nothing else on how events are distributed, how you post a distributed event and how you handle what node to react to it and post to channel that will reach the correct end-client.
Am I missing something or is there almost no documentation on this?
The documentation for RedisServerEvents is at: http://docs.servicestack.net/redis-server-events
There is no difference in API between using an In Memory or Redis Server Events backend which works transparently behind the IServerEvents API. The only difference is in registration where you need to register RedisServerEvents with your configured IRedisClientsManager:
var redisHost = AppSettings.GetString("RedisHost");
if (redisHost != null)
{
container.Register<IRedisClientsManager>(
new RedisManagerPool(redisHost));
container.Register<IServerEvents>(c =>
new RedisServerEvents(c.Resolve<IRedisClientsManager>()));
container.Resolve<IServerEvents>().Start();
}
This replaces the default Memory IServerEvents with the RedisServerEvents implementation which sends API calls over Redis Pub/Sub to notify all App Servers configured with the same RedisServerEvents configuration who will send the Server Event to the connected clients on their local /event-stream.
I have a web application which is a mesh of a few different servers and 1 server is the front-end server which handles all request external incoming requests.
So some of these request will have to be passed along to different servers and ideally the only thing I want to change is the host and Uri fields of these request. Is there a way to map an entire incoming request to a new outgoing request and just change a few fields?
I tried something like this:
// some controller
public HttpResponseMessage get()
{
return this.Request.Rewrite("192.168.10.13/api/action");
}
//extension method Rewrite
public static HttpResponseMessage Rewrite(this HttpRequestMessage requestIn, string Uri) {
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpRequestMessage requestOut = new HttpRequestMessage(requestIn.Method, Uri);
requestOut.Content = requestIn.Content;
var headerCollection = requestIn.Headers.ToDictionary(x => x.Key, y => y.Value);
foreach (var i in headerCollection)
{
requestOut.Headers.Add(i.Key, i.Value);
}
return httpClient.SendAsync(requestOut).Result;
}
The issue I am having is that this has a whole slew of issues. If the request is a get Content shouldn't be set. THe headers are incorrect since it also copies things like host which shouldn't be touched afterwards etc.
Is there an easier way to do something like this?
I had to do this in C# code for a Silverlight solution once. It was not pretty.
What you're wanting is called reverse proxying and application request routing.
First, reverse proxy solutions... they're relatively simple.
Here's Scott Forsyth and Carlos Aguilar Mares guides for creating a reverse proxy using web.config under IIS.
Here's a module some dude named Paul Johnston wrote if you don't like the normal solution. All of these focus on IIS.
Non-IIS reverse proxies are more common for load balancing. Typically they're Apache based or proprietary hardware. They vary from free to expensive as balls. Forgive the slang.
To maintain consistency for the client's perspective you may need more than just a reverse proxy configuration. So before you go down the pure reverse proxy route... there's some considerations.
The servers likely need to share Machine Keys to synchronize view state and other stuff, and share the Session Store too.
If that's not consistent enough, you may want to implement session stickiness through Application Request Routing (look for Server Affinity), such that a given session cookie (or IP address, or maybe have it generate a token cookie) maps the user to the same server on every request.
I also wrote a simple but powerful reverse proxy for asp.net / web api. It does exactly what you need.
You can find it here:
https://github.com/SharpTools/SharpReverseProxy
Just add to your project via nuget and you're good to go. You can even modify on the fly the request, the response, or deny a forwarding due to authentication failure.
Take a look at the source code, it's really easy to implement :)
I am using a WCF service client generated by slsvcutil form Silverlight toolkit version 4. I've also tried version 3 with the same problems. When I use a client instance running on http with no user credentials it runs without problems. But I need to switch to https for productive servers and send user credentials that are hardcoded for my application. I use the following code for that:
var binding = new BasicHttpBinding (BasicHttpSecurityMode.TransportCredentialOnly);
var endpoint = new EndpointAddress (AppSettings.FlareEndPoint);
_service = new TopicAnalystAPIClient(binding, endpoint);
_service.ClientCredentials.UserName.UserName = "xxx";
_service.ClientCredentials.UserName.Password = "xxx";
When I call a method on that service pointing to http with no authentication it works. When I use the this code against http/https with the credential I get "There was an error on processing web request: Status code 401(Unauthorized): Unauthorized" exception. I've checked that the credentials are correct, I am able to open the service reference in my browser. I've also tried several combinations of http/https and SecurityMode value. I've also tried it on four different servers always with the same result.
What can be the problem?
A lot of permutations are possible. BasicHttpSecurityMode.TransportCredentialOnly should be usable without SSL [1] using HTTP itself. This means the server will send one (or more) authentication method(s) to the client (e.g. basic, digest, ntlm) and Mono (including MonoTouch) should be providing support for the most of them.
It is possible that the linker (if used) removes one of them. In that case you could try building and testing without linking (or skip linking of System.Net.dll).
It's also possible that the authentication method that the serve insist on is not supported. You could find which one is used by running a network trace (e.g. wireshark) or, maybe, it will show up in more details in the server log (along with the 401 error).
[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode%28v=vs.95%29.aspx
A have a web-accessible (via basicHttpBinding) WCF service which I also want to access from other .NET services on the same machine with as higher performance as possible. I understand that the netNamedPipeBinding is ideal for this, but wonder what the best configuration would be given that I'm only even going to be communicating with other .NET processes.
For example, I needn't necessarily use an encoding such as SOAP as this is perhaps too bulky and I don't need the compatibility with any other clients other than a .NET client. I also don't think I need any security.
What would be the best binding configuration for this purpose (or any other configurations for that matter)
As you have noted, the NetNamedPipeBinding binding is optimised for same-machine communication:
Provides a secure and reliable binding
that is optimized for on-machine
communication.
Ref. : System-Provided Bindings
In chapter one of Juval Lowy's book, "Programming WCF Services", he provides a useful decision-activity diagram for choosing the right binding:
"The first question you should ask
yourself is whether your service needs
to interact with non-WCF clients. If
the answer is yes, and if the client
is a legacy MSMQ client, choose the
MsmqIntegrationBinding that enables
your service to interoperate over MSMQ
with such a client. If you need to
interoperate with a non-WCF client and
that client expects basic web service
protocol (ASMX web services), choose
the BasicHttpBinding, which exposes
your WCF service to the outside world
as if it were an ASMX web service
(that is, a WSI-basic profile). The
downside is that you cannot take
advantage of most of the modern WS-*
protocols. However, if the non-WCF
client can understand these standards,
choose one of the WS bindings, such as
WSHttpBinding,
WSFederationHttpBinding, or
WSDualHttpBinding. If you can assume
that the client is a WCF client, yet
it requires offline or disconnected
interaction, choose the NetMsmqBinding
that uses MSMQ for transporting the
messages. If the client requires
connected communication, but could be
calling across machine boundaries,
choose the NetTcpBinding that
communicates over TCP. If the client
is on the same machine as the service,
choose the NetNamedPipeBinding that
uses named pipes to maximize
performance. You may fine-tune binding
selections based on additional
criteria such as the need for
callbacks (WSDualHttpBinding) or
federated security
(WSFederationHttpBinding)."
Certainly the Named Pipe transport is the best choice.
Transport security with EncryptAndSign is enabled by default on the standard NetNamedPipeBinding. You certainly want to remove this, as doing so will speed things up without any real impact on security, for the reasons I discuss here.
I also suspect, but have not yet confirmed, that changing the message encoding binding element may help. This is because the default is the WCF proprietary 'binary encoding with in-band dictionary', which is an encoding of an XML infoset which aims to reduce redundant bytes e.g. in opening and closing element tags: a worthy aim when network IO is involved, but maybe wasted CPU effort when message transfer is entirely in-memory (provided the messages are not too big). Thus changing to a plain text encoding might also provide a speed improvement.
I Understand this is a pretty old question, but it still worth answering. As already mentioned named pipes are fastest and you need to disable security, but the most dramatic effect you'll get if you get rid of data contract serialization and switch to stream-based transfer mode.
Use something like this as binding configuration:
new NetNamedPipeBinding
{
MaxReceivedMessageSize = 524288000,
ReceiveTimeout = TimeSpan.MaxValue, // never timeout
SendTimeout = TimeSpan.MaxValue, // never timeout
ReaderQuotas =
{
MaxStringContentLength = 655360000
},
TransferMode = TransferMode.Streamed,
Security = new NetNamedPipeSecurity
{
Mode = NetNamedPipeSecurityMode.None,
Transport = new NamedPipeTransportSecurity
{
ProtectionLevel = ProtectionLevel.None
}
}
}
Define your service messages like this:
[MessageContract]
public class CallRequestMessage
{
[MessageHeader]
public string Arg1;
[MessageHeader]
public int ParametersLen;
[MessageBodyMember]
public Stream Parameters;
}
[MessageContract]
public class CallResponceMessage
{
[MessageHeader]
public int ResultCode;
[MessageHeader]
public int ResultsLen;
[MessageBodyMember]
public Stream Results;
}
[ServiceContract]
public interface ILocalServiceAPI
{
[OperationContract]
CallResponceMessage Call(CallRequestMessage message);
}
The downside of this method is that now you have to serialize your data yourself. I prefer using protobuf serialization directly to MemoryStream. Place this stream to your CallRequestMessage.Parameters.
Don't forget to transfer ParametersLen/ResultsLen in the message header as Stream is endless (while reading you'll may receive 0 bytes, but unlike normal streams you should continue reading).