Spring push send message over WebSocket to unauthenticated user - java

I am using Spring with Spring-Security.
I have a situation where I would want to push send a message over WebSocket to a specific user by session before the user is authenticated.
Usually tutorials are on situations where messages are send reacting on some incoming messages so that doesn't really help me.
I tried to find a way to get access to the WebSocketSession object associated with some session but couldn't find a way to do so; honestly I am not even sure if that would be the way to go to implement what I want.
Is there any "common-practice" to achieve what I want in Spring?

Please take a look into Spring Security Filter Chain mechanics. You can hook into any step of the FilterChain using httpSecurit.addFilterBefore() httpSecurit.addFilterAt() httpSecurit.addFilterAfter(). Add your filter before the AUTH step and do what ever you want to do.
You will find good examples for this if you google up JWT and spring. There usually one has to put a custom filter for JWTTokenGeneration on username password auth.
You could use SSE to send a push notification to the socket in that filter step.

Related

Securing a Spring messaging based websocket service

I am working on this for 3 weeks now without a real solution and I really hope you can help me out.
A bit project background:
Webapp with a JavaScript/PHP based Client sends via SocksJS and Stomp a message to a "gate"
The gate is written in Java/Spring and uses #SendTo and #MessageMapping to send and recieve messages
The messages from the gate are sent to RabbitMQ and back to the client via "messageBrokerRegistry.enableStompBrokerRelay"
So far it works, messages being sent are coming back.
Now the advanced SECURITY part:
The messages should be secured via cookies containing a user and stuff...
WebSockets themselves dont support security as far as I understood. You have to secure your webapp just like a "common" webapp with BASIC auth or some like that. So I added a servlet filter with a class extending GenericFilterBean. If the user sent the correct cookie the page loads, else he gets a 403 error.
Now comes the PROBLEM:
Due to the fact that #SendTo sends messages to all subscribers and #SendToUser seems to send it just to one session I tend to use #SendToUser. BUT there seems no way to chose a rabbitMQ queue to be created. I want some like "/myqueue-user-123". This is not possible with #SendToUser, because the generated queue is random and based on the SessionID, which I could not override.
So what I tried (and i tried LOADS of stuff besides interceptors, events and so on), is using #SendTo without a value so that the client can decide the queue it has to send to.
What I need now is to evaluate that the user from the cookie correlates with "/myqueue/user-123". And if NOT, DO NOT SEND the message to him. Stop him from subscribing. Disconnect him, whatever.
But it seems to me that you can in no way
- stop messages from being sent, just "intercept" to log them not alter
- disconnect a websocket because it automatically tries reconnecting
- throw exceptions because the subscribe suceeds anyways (events are just events, not something to interfere).
I would be really thankful for any advice or tip. Because I am totally stuck here...
I understand your pain, i spend two days trying to understand the spring security mess concerning WebSocket.
Websocket dont officially support a way to authenticate, however, spring-security does (more or less).
I would advice you to authenticate at WebSocket level, not at HTTP, most of JavaScripts library for WebSocket (and stomp) don't sends headers along with the HTTP handshake.
You'll find a detailed guide on how to authenticate at the WebSocket level here. In the above example, i used Websocket Headers values to authenticate my clients, you can put your cookie value in these headers, or replace the cookie by localstorage.
Using this method you'll have access to the Principal in your controllers, this should solve the SendToUser issue.

Secure Rest-Service before user authentification

I have a web application that provides several rest services (Jersey). Most of the endpoints are secured by BASIC authentification. Further more I use SSL for transport and demand POSTs for every call.
The clients/consumers are android apps.
So far so good. The only service that seems to be vulnerable is the registration. It's the 'first' service to call and a user does not exist yet. So I cannot use OAuth, etc. I also have to keep the endpoint easy accessible to enable the user to regster.
How do I secure this service, so it's not spammed by a bot flooding my database?
How about these?
Use a registration link with a token in the request parameter. Ensure that the tokens expire after sometime. You could create a token endpoint url as well for a client to get a valid token.
Use a custom header or a dynamic custom header in your request. Additionally, you could check for a dynamic custom header to validate the request's authenticity.
Use registration confirmation workflows, such as an email / text verification as soon the registration is done. Run a process every day to delete any user accounts, which are not validated in say x days.
I do not think you can really secure the registration URL in a HTTP way. IMHO, anyone who has the registration url can be a right guy trying to register. So if you ask me, option 3 is better than others.

How to determine which user is making Rest requests from android application?

I am trying to build a Spray REST Web server for my mobile application on android (Eventually Iphones too). Currently, I am wondering how to determine from the server side which user is making REST Method requests. After some research I am understanding that android's SharedPreferences or an OAuth protocol can be utilized to handle user authentication. Still I am unsure how to create the entire picture of "This user is requesting some information". The message responses will be in JSON text, should the request's be in JSON as well?
I greatly appreciate all of your help, eagerly awaiting responses.
Currently, I am wondering how to determine from the server side which user is making REST Method requests.
The most adequate way to do this is to add auth layer to your server. There are many ways of how exactly you can do this, depending on security concerns you have to deal with.
Here is the list of auth schemes I would be looking into first of all:
Http basic auth (most simple one, stick with it if you can)
OpenID or OAuth (harder to implement, solves some problems that are out of scope of simply authenticating user. Note: OAuth is about authorization but can also be used to do authentication)
home-gown auth (may be implemented on different network layers, lots of options here. Do not recommend going here unless you really need to).
You can send more info from client side when user send request, you include unique info (Android ID, Ads ID for example)
server.address/request?command=abc&uid=UID...
. Another way is read IP address of the user and manage it by session.

Is there any solution can send message to a group of user (not all user) using spring4 websocket?

Recently, I use spring4 websocket to push message to end user.
I known that, there are 2 methods (convertAndSend, convertAndSendToUser) to send message in class SimpMessageSendingOperations .
But is there any way to send message to a group of user, and the user out of group cannot subscribe the message?
Thank you very much.
As of Spring Framework 4.0.x, it is possible to send messages to a group of users by:
explicitly sending messages to each user, using a for loop
sending messages to a particular topic, given those users subscribed to this topic beforehand.
As you mentioned, you don't want users that don't belong to that "group" to be able to subscribe to this topic. This calls, in fact, for authorization features.
With 4.0.x, security features are implemented at the HTTP level, for example during the HTTP Upgrade phase, before clients switch to websocket (see the websocket-portfolio application).
The feature you're asking for is implemented in Spring Security 4.0.0 (to be released, see this blog post for a full preview).

JAX-WS, Authentication and Authorization - How to?

What is the best way to do authentication and authorization in web services?
I am developing a set of web services, requiring role based access control.
Using metro - SOAP, simple java without EJBs.
I want to Authenticate the user just one time, using username and
password, to be matched against a data base. In the subsequent calls.
I would like to use some kind of session management. Could be some
session id, retrieved to the client at login, to be presented in all
calls.
So Far:
Read authentication using a database - but I want application level validation;
Read application authentication with jax-ws - but i don't want to do the authentication mechanism every time;
I think I can use a SOAP Handler, to intercept all the messages, and do the authorization control in the hander, using some session identifier token, that comes with the message, that can be matched against an identifier saved in the data base, in the login web method.
EDIT:
I still have some questions:
How to know the name of the web method being called?
What kind of token should I use?
How to pass this token between calls?
EDIT 2
Because of #ag112 answer:
I'm using Glassfish.
I use WS-Policy and WS-Security to encrypt and sign the messages. Using Mutual Certificate Authentication. I would like to complement this message level security between applications, with the authentication and authorization for the users also in message level.
I am just developing the services, and I don't know almost nothing the clients, just that they could be created in different languages.
At this point I think the most important thing is to do what ever I need to do to authenticate and authentication the users, I the most easy way to be implemented for the client applications.
#Luis: Here are my inputs.
Well exact solution for your problem depends upon kind of web service clients you expect, do you have control over web service client system, your app server etc.....but assuming you don't have any control over web service client, for you it is just a SOAP message over HTTP transport, here is probable solution.
You can of course performs session management & authentication at message level or transport level. It means either you can have session token and auth token information in SOAP message or you can use standard HTTP Session and HTTP authentication mechanism.
Of course transport level solution is much simpler and industry wide standard in case if transport layer is HTTP. For message level, ws specifications like ws-security can be used.
Your each web service request is simple HTTP GET/POST identified by a unique HTTP URI.
Typically in jax-ws metro environment, WSServlet is one which entry servlet for any web service call and which eventually delegates the call to right service provider implementation class. Since you application is going to be deployed in web server, you can exploit all session and authentication facilities provided by J2ee web container.
Since you are looking for role-based access control, I would use standard <web-resource-collection> in web.xml to specify which role you would like to have in case of particular HTTP URI. You can use standard JAAS login module which can do authentication and populates the JAAS subject with role. If user name/password are provided in SOAP XML, JAAS login module can also search/parse SOAP XML to retrieve those information. JAAS/app server will automatically create auth token and store it as cookie so that each subsequent request need not to go through authentication process again. This is all J2ee standard. You can find plenty of help on internet on this. Please let me know your app server so that I can provide you additional details.
If you still want to use SOAP message level session management, authentication & authorization process, then to provide you more details, may I know more details about your client side.
EDIT1:
Well based on your further inputs, here is my more thoughts:
Message security namely encryption and signature needs to happen each message travels between server and client. where as message authentication- you intend to do once and give a session token/auth token to client for subsequent calls.
Question still remains: if you put a unique session Identifier in SOAP response of first time authentication, do you expect client to parse SOAP response XML and ensure that client should send you session identifier each time in subsequent SOAP requests.
OR
You want to keep session management transparent to client and for client it needs to send username/password token first time and subsequent calls need not require any username/password token. In this case you would need to rely on transport based session management for e.g. HTTP cookies
Now what is the best for you depends upon your use case. Can you tell me what is expected use case flow? how another system (web service client) makes more than one service call to your system? Is another system user driven/some background process? What is exact need that you want only first service call to go through authentication process not subsequent calls?
PS: Glassfish server provides a way of configuring message authentication provider which automatically enables/disables message level authentication.
EDIT2:
I understand you do not want to store user credentials in client app and web service server need those user credentials.
OAuth is open standard protocol which allows site A to access user's private data on site B. Ultimate idea is site A gets auth token which has specific expiry time. So Token containing encrypted from of user credentials or jsession id help you avoid need of re-authentication. You only need to decide where you want to keep token at client app side
You can keep token as cookie if transport is HTTP protocol.
Having said that ofcourse passing user credentials each time seems bit easier and straight forward.
You can also go for OpenEJB.
It used JAAS with WS-Security.
I hope the link is useful.
After all the help, I create this answer to simplify, and summarize all the ideas that was discussed.
The questions has 2 requisites:
Message level security;
One time authentication.
With ag112 help, this is hard to do, or to elegant in any way. So here are to conclusions:
For message level security send the user
credentials every time (place it in SOAP header);
For one time authentication use transport level security, and do a
session management.
I prefer the first one, because the message level was the biggest requisite.
As had no answers, following #unhillbilly advise, I answer my own question, with the progress so far:
How to know the name of the web method
being called;
Using a SOAP handler, finding the name of the first element in the body.
What kind of token should I use;
I decide to use a 128 bits token, representing each session. The Webservices, continue to be session-less, the key is just for authorizations purposes.
How to pass this token between calls.
For the login web method the result has the token, in each subsequent calls, the token is a parameter.
is there a better answer?

Categories

Resources