From the SignalR hub, i want to enforce the connecting client is the WinForm program I distributed. Is there a way to "challenge" the client from the hub, by asking for a secret, or code signing certificate, or checksum of the exe, or anything?
SignalR connection does not intended for such purposes - it just connects to a service hub. You can always challenge a user on WinForm side before connection run
if (secretValue == inputSecret) {
await hubConnection.Start();
} else {
// notify user that secret is incorrect
}
Related
I have a couple of questions regarding SignalR Core authorization on the server side;
My server is written in ASP.NET Core, and it uses SignalR CORE for sending notifications to users.
1) If a client has connected with an options object containing an AccessTokenProvider and the access token changes -- does the server re-authorize the user even when using a long-running connection like a socket? Ie does SignalR create a new User object on the server side when the client's access token changes, while a connection is alive? If not -- how should this be handled?
2) On the client side - if a connection is aborted either from server side or by the client requesting a stop, does DisposeAsync() have to be called and a new connection object created, or can the previous one be reused safely without disposing it?
Thanks.
1) When token expires, you will need to refresh the token. To do that you will need to abort the connection and make it again. This is stupid but server will drop the connection when token will be expired.
2) If it is manually aborted, the object is disposed and the new connection will be new. If connection will drop for like, internet connection issues, with automatic reconnect, it will have the same instance and maintain same connection (and same connectionId).
i read this article http://www.asp.net/signalr/overview/security/introduction-to-security#connectiontoken
JS Client
$.connection.hub.qs = { "token" : tokenValue };
$.connection.hub.start().done(function() { /* ... */ });
.NET Client
var connection = new HubConnection("http://foo/",
new Dictionary<string, string>
{
{ "token", tokenValue }
});
Inside a Hub you can access the community name through the Context:
Context.QueryString["token"]
Setting Headers on the .NET Client
var connection = new HubConnection("http://foo/");
connection.Headers.Add("token", tokenValue);
i notice that we can pass some token value from client side to hub function as query string.....if i pass the anything as query string is not safe. so tell me best way to pass token value in secured way from client to hub function as a result no one can hack/change or reuse that token value.
one guy said SignalR uses encryption and a digital signature to protect the connection token..
so please tell me is it true that signalr first encrypt token value and then pass from client side to hub?
suggest me how one can pass token value to hub in secure way. thanks
You can use headers in the javascript client like this for example:
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + yourToken };
Now not hacky and is a global setting you can do once at startup or successful auth response! Enjoy!
Now only if I can find a way to override this on a per-request basis so I can get a user emulation sandbox working for my users in administrative roles...
When the client initiates a connection the server creates and encrypts a connection token and sends it to the client. From this point on the client has to send the connection token each time it sends a request to the server. The server verifies the connection token when it receives a request. If you are asking how to prevent from using the same token by multiple clients then I think you need to look at authentication.
I setup SignalR in my application and it works very nice!
I have a Hub which is only supposed to push messages from the server to the client.
However, i can also call the method from the client back to the server, doing like this:
// this makes a call from the client to the server
$.connection.appplicationHub.server.productCreated();
Is there a way to prevent this?
This was a bad question.
To send messages from Server to Client, i don't need to create the method in the Hub class. Methods created in the Hub class are made for Client -> Server messages.
In order to send SignalR message to a specific user I create a Group for each user upon connection
public override Task OnConnected()
{
log.DebugFormat("Connected. Connection Id = {0} UserId = '{1}'", Context.ConnectionId, UserHelper.UserId);
Groups.Add(Context.ConnectionId, UserHelper.UserId);
return base.OnConnected();
}
Now when a message comes in I send it a group in the following way:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<AlertsHub>();
foreach (var recipient in recipients)
{
hubContext.Clients.Group(recipient).broadcastAlertMessage("Group", msg);
}
That works fine when deployed to a server, but for some reason not working when i access the server through our company load balancer (Citrix Netscaler SDX 11500) but eventually hitting the same sole box.
There is no issue sending messages to all clients
hubContext.Clients.All.broadcastAlertMessage("All", msg);
Also i can keep the connection IDs internally and send messages to a specific client works
hubContext.Clients.Client(AlertsHub.UserToConnectionIdDict["admin"]).broadcastAlertMessage("trageted client", msg);
Why "Group" message doesn't work?
By default, a SignalR server is only aware of and will only send messages to clients connected directly to itself. This is because each SignalR server manages its own messages using its own message bus. Without special configuration, SignalR has no way to know there are other clients connected to a different SignalR server at the same global address.
Fortunately SignalR has scaleout providers that allow you to configure all your SignalR servers in such a way that they can communicate with each other by sharing single message bus.
This "Introduction to Scaleout in SignalR" should provide you with the info you need to get SignalR working properly behind a load balancer: http://www.asp.net/signalr/overview/signalr-20/performance-and-scaling/scaleout-in-signalr
i recently had a look to the tutorial for custom authentication within a flex application. The login is managed by getting the ChannelSet from a RemoteObject:
private function creationCompleteHandler():void {
if (cs == null)
cs = ServerConfig.getChannelSet(remoteObject.destination);
}
// Login and handle authentication success or failure.
private function ROLogin():void {
// Make sure that the user is not already logged in.
if (cs.authenticated == false) {
token = cs.login("sampleuser", "samplepassword");
// Add result and fault handlers.
token.addResponder(new AsyncResponder(LoginResultEvent, LoginFaultEvent));
}
}
After that the channlset can be used with the login command of ChannelSet. How can i insure that this is using a secure connection? I know that there is a amf channel and a secure amf channel. But how to tell to provide the credentials in a secure connection?
Typically a ChannelSet is defined with a group of channels that define a fail-over strategy, rather than as part of a secure/non-secure segmentation.
Mixing encrypted & non-encrypted channels in the same channelset doesn't really make sense.
When a channelSet has multiple channels defined, the Flex client will attempt to connect on the first, and gracefully fail through to the next, and the next until a connection is established, or all channels are exhausted.
If you want to have both secure & non-secure channels defined, you would typcially define two channelsets - one for each:
<s:ChannelSet id="channelSet">
<s:AMFChannel url="http://myserver:8080/myapp/messagebroker/amf" />
</s:ChannelSet>
<s:ChannelSet id="encryptedChannelSet">
<s:SecureAMFChannel url="https://myserver:8080/myapp/messagebroker/amf" />
</s:ChannelSet>
public function logon():void
{
// Credentials are passed via https
encryptedChannelSet.login("username","password");
}
What isn't clear from the documentation is that assuming that both channelSet and encryptedChannelSet are part of the same messageBroker, the authentication state and user credentials are available across both channelSets.
Ie., although the client code suggests that credentials are supplied to only a single ChannelSet, on the server side, the FlexContext is what holds the authentication state, which is associated with the browser session, not a specific channel or channelSet.
So, after authenticating the encryptedChannelSet, destinations which are exposed to the channelSet which are secured and require user credentials are now accessible.