CometD Secure Requests - java

I am using CometD and I have a service setup (Java on the server side) as follows:
http://localhost:8086/service/myService/get-player-details?params={id:1234}
This works fine in practice but what concerns me is that any user can query my service using the above URL and retrieve another players details.
What would be the suggested way of guarding against such an issue? Would authorizers be the correct approach?

If the URL you posted is a mapped to CometD, then I strongly discourage you to use those kind of URLs to pass information such as params in the URL.
First, this will not work if you use other transports that are not HTTP, such as WebSocket.
Second, as you note that URL may expose information that you don't want to expose.
I recommend that you change the way you retrieve information from the server to not use URLs but only messages.
If all your communication with the server happens via messages, CometD on the server already validates that the message comes from a client that was allowed to handshake. You just need to enforce the right authentication checks at handshake time using a SecurityPolicy as explained the in authentication section.
The messages will have this form, using the CometD JavaScript client library:
cometd.publish("/service/player", { action:"get", playerId: 1234 });
There may be variations of this pattern where you want to put the "action" into the channel itself, for example:
cometd.publish("/service/player/get", { playerId: 1234 });
In this way, you have more little services (each responding to a different channel and therefore to a different action), which may be desirable.
Reading the examples of the services section may give you additional information.
I don't recommend to put the playerId into the channel for two reasons:
to avoid to create too many channels
to have this information promptly available in the code, so you don't need to parse the channel (although CometD support use of parameters in channels); parsing is more costly than just doing message.get("playerId").
To send the response to the client, the server can just call:
#Service
public class GetPlayer
{
#Session
private LocalSession sender;
#Listener("/service/player/get")
public void perform(ServerSession session, ServerMessage message)
{
Map<String, Object> player = retrievePlayerInfo(message.get("playerId"));
session.deliver(sender, message.getChannel(), player);
}
}
Note usage of ServerSession.deliver() to return the response to that specific client.
What above guarantees you (with a proper SecurityPolicy) that only authenticated clients can send and receive messages.
What you need to do now is to put in place the right authorizations, in particular that player 123 cannot play as player 789 by hacking the CometD messages that it sends.
This is the job for Authorizers, see the section and the examples in the Authorizers documentation.
What you must do is to establish a relation between the user that authenticated with the playerIds that she's allowed to see. That is application specific and it's the core of your Authorizer implementation.
With proper SecurityPolicy and Authorizers in place, your application is safe from the concerns of your question.
Strictly speaking, Authorizers may be enough, but typically if you want an authorization policy to be enforced, you also need authentication, which is provided by the SecurityPolicy.

Related

How to route Client to Client in Chat application using Java Spring Stomp over WebSocket

I try to implement multiclient chat that will have one general open room and the possibility for private messaging between active users. I wanted to use WebSocket for this purpose but I stumbled upon a problem that I cannot solve: How to notify other clients that a new one has appeared and give them information about his username (username will be important for the UI purpose except routing) and sessionId. I have one solution that is suboptimal at best:
#MessageMapping("/greeting")
public void addUserAndNotifyOthers(#Header("simpSessionId") String sessionId, #Payload String username) {
userToSessionMap.put(username, sessionId);
simpMessagingTemplate.convertAndSend("topic/greeting", username);
}
After the handshake, the client will broadcast his username, in the controller I will keep a map that routes the username to the sessionId of the client. I can see drawbacks to this: an additional message must be broadcasted, and as it will be received by the very client that sent it, there must be additional logic that checks the sender. Is there better way to handle this kind of case? I have seen that interceptors are often used for keeping sessionIds of the clients but I struggle to find a solution to this with their use.

How to maintain SseEmitters list between multiple instances of a microservice?

Language: Spring Boot, JS
Overview: I am implementing server sent events functionality in my application which will be deployed in cloud foundry,
wherein based on a new message in a queue(which I have subscribed in my micro-service), I will send some update to my client/browser(which is using EventSource).
For this, I am maintaining a SseEmitters List(for mainitaining all the active SseEmitter) on my server side. Once I receive a new message from the queue, based on the id(a field in the queue message), I will emit the message to corresponding client.
PROBLEM: How will the above scenario work, when I scale my application by creating multiple instances of it. Since only one instance will receive the new queue message, it may happen that the active SseEmitter is not maintained in that particular instance, how do I solve this?
To solve this problem, following approaches can be observed.
DNS concept
If you think about it, knowing where your user (SSE Emitter) is, is like knowing where some website is. You can use DNS-look-alike protocol to figure out where your user is. Protocol would be as follows:
Whe user lands on any of your instances, associate user with that instance. Association can be done by either using external component, e.g. Redis or a distributed map solution like Hazelcast.
Whenever user disconnects from SSE, remove association. Sometimes disconnect is not registered properly with Spring SSEEmiter, so disassociation can be done when sendig message fails.
Other parties (microservices) can easily query Redis/Hazelcast to figure on which instance user is.
Message routing concept
If you're using messaging middleware for communication between your microservices, you can use routing feature which AMQP protocol provides. Protocol would be as follows:
each SSE instance creates their own queue on boot
user lands on any of SSE instances and instance adds exchange-queue binding with routing key = user uid
Whenever user disconnects from SSE, remove association. Sometimes disconnect is not registered properly with Spring SSEEmiter, so disassociation can be done when sendig message fails.
Other parties (microservices) need to send message to the exchange and define routing key. AMQP broker figures out which queue should receive message based on the routing key.
Bindings are not resource intesive on modern AMQP brokers like RabbitMQ.
Your question is old, and if you didnt figure this out by now, hope this helps.

How to implement one-way operation in Java Web Services?

How to implement one-way operation in Web Services (using Java or Spring annotations)?
I have tried to add one way as given below
#WebService
public interface DanduServices {
#Oneway
public void saveDanduInformation(#WebParam(name = "serv") ServDTO Serv, #WebParam(name = "dandu") DanduDTO danduDto);
but it is still request-response not asynchronus or one way.
Could anyone suggest to make a operation one-way in service endpoint and let other operations behave as per request-response?
You need to think in terms of the protocol as well though. In HTTP when you send a request you wait for a response, if no response comes back after an amount of time then you will receive a time-out error. So when you talk about one-way (you should rather say async request maybe) you really need to specify exactly what you mean. Do you want to have confirmation that your message was received i.e. have the server respond back with an OK status code and go off and complete it's task but you not wait for the task to be completed? Then you would need to spawn another thread. Spring has AOP for this the same way it has for transactions with #Transactional. Instead you annotated your method with #Async and return a Future<Something>. You'll also need #EnableAsync in your config. Refer to this article for an example Hot To Do #Async
If you don't even care about if the server received your request you don't want to use TCP/HTTP but instead UDP which is used in VOIP (phone over internet) for instance and is quicker, but it will depend on your client.

GWT-RPC or RequestFactory for Authentication?

I'm trying to build a login screen for my GWT app. When you click the login button, the credentials (username & password) need to be sent to the server for authentication. I'm wondering what server communication method is a best fit for this: GWT-RPC or RequestFactory.
My understanding is the RequestFactory is more efficient and recommended over GWT-RPC, but it's more of a data/entity/persistence framework than a request-response framework like RPC. So although many GWT afficionados recommend using RequestFactory over GWT-RPC, I don't think RequestFactory can be used for this scenario. After all, I don't want to CRUD a login request, I want to send credentials to a server, perform secured authentication, and return a response to the client.
Am I correct? Is GWT-RPC my only option? or
Can RequestFactory be used. If so, how (need to see a code example of both client and server code)?
You can use either, although RF is very used with EntityProxy, it also is thought to work with ValueProxy which mean transmit any type. RF facilitates as well execution of remote procedures passing Proxy types or primitive types.
Said that, I would use the technology used primarily in my app. If you are using RPC send your login/password in a RPC request, but if you are using RF use it, so as you dont mix things, although you can mix RF, RPC, and plain Ajax without problems.
What you have to be aware of, is that normally, in applications requiring authentication you have to use a filter to check whether the user has a valid session when requesting RPC or RF, so in the case of sending a request for login, you have to jump somehow the auth filter.
Related with security, both scenarios are the same, you have to do the request in an https enabled environment.
[EDIT]
This could be the interface for the client and the remote implementation of a RF call for login, as you can see it is really easy, you can add any method you need to these classes:
#Service(value = LoginUserService.class)
public interface LoginUserRequest extends RequestContext {
Request<Boolean> login(String username, String password);
}
public class LoginUserService {
// Using static you dont need to provide a Locator for the service
static Boolean login(String username, String password) {
return true;
}
}
Related with auth filters for RF, you can take a look to this: GWT RequestFactory authentication functions
With both technology you can send such information to server side, but as already you pointed out the RequestFactory is dedicated to entity management. In your case is better to use GWT-RPC because in order to only send the credentials server side, and eventually retrieve the authentication result, you don't need the RequestFactory surplus (delta transmission, entity management).
For authentication, I would (almost) always use RequestBuilder, i.e. a simple HTTP(S!) POST. Why? Because this way you can implement a general authentication mechanism, that can not only be used by GWT apps. You gain the flexibility to add a simple HTML login page, single sign-on, standard server-side mechanisms (e.g. Spring security), etc.
A simple GWT re-login dialog is also no problem with RequestBuilder - to submit just username/password, GWT-RPC or RF is simply not necessary.

Designing RESTful login service

I went through a similar question here. But I am yet not clear over concepts. Here is my scenario...
My client (a mobile device app) has a login screen to enter username, password. After submission, he should see the list of books in the database plus the list of books subscribed by that user.
I am having a /LoginService which accepts username, password & checks a mysql database for credential validation. Only after authorization....I have a /BookService ; GET on which returns all the books in database.
Should I use GET, POST or PUT on my loginservice ? Since a login request is a read-only operation, I should use GET - but this sounds stupid for browser(as the submitted data is visible).
What are accesstokens (mentioned in the linked answer above), and how to generate them using Java ? I am using Jersey for development. Are they a secure way of authorization ?
Thanks !
As far as I understand you are trying to implement stetefull communication between client and server. So you login with first request and then use some kind of token to make further requests.
Generally I can recommend you to have stateless communication. This means, that you authenticate and authorize each request. In this scenario you don't need LoginRestService. Important points here are:
Client can provide userName and password through HTTP Headers (non-standard, something like UserName: user and Password: secret).
At the server side you can use
Use AOP: just wrap you BooksService with AuthAdvice (which you should write yourself). In advise you access somehow (with Jersey functionality) HTTP request, take correspondent headers from it, authenticate and authorize user (that you load from DB), put user in ThreadLocal (so that it would be available to the rest of your app) if needed and just invoke correspondent method or throw exception if something wrong with credentials.
Use Jersey functionality: (sorry I'm not very familliar with Jersey, I'm using CXF, but conceptually it should be the same) just create some kind of AuthHendler and put it in request pre-processing pipeline. In this handler you need tho make exactly the same as in AuthAdvice
Now each of your request would be authenticated and authorized when it reaches BooksService. Generally stateless implementation is much better for scalability.
If you want to go statefull way, than you can just use HttpSession. LoginService.login() should be POST request because you actually making some side-effects at the server. Service will perform authentication of your user according to provided username and password and put loaded User object to session. At this point, the server side session is created and client has session ID in the cookies. So further requests should automatically send it to the server. In order to authorize requests to BooksService you still need some kind of Advice of Handler (see stateless solution). The only difference: this time user is taken from the HttpSession (you should check that you are logged in!).
Update: And use HTTPS! :)
I've got nothing to dispute in Easy Angel's answer, but got the impression you'd like some additional comment on the concepts too.
The problem is clearer if you think in terms of resources rather than services. Think of your proposed login as generating a new authorization resource, rather than querying a login service. Then you see that POST makes perfect sense.
The authorization token would be a key for your user into the session object (as explained in EA's answer). You'd probably want to generate it by concatenating some information that uniquely identifies that user and hashing it. I certainly agree that a stateless authentication method would be preferable, if you're aiming to get all the benefits of REST.
Use what is available in HTTP: HTTP AUTH over SSL.
Protect all your resources with HTTP AUTH and the browser will take care of providing a login for the user.
If you need session information on top of that, use cookies or a session parameter.
Cookies were made for exactly these kinds of purposes and usually work well.

Categories