Securing a Spring messaging based websocket service - java

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.

Related

Spring push send message over WebSocket to unauthenticated user

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.

Web app security architecture

I have a Java Spring driven REST API server connecting with PostgreSQL database and a Spring Web Server in Java that is serving content from the REST API to the client using JavaScript (now browsers, but in the future also mobile apps).
I've read a number of articles and topics how one can secure a REST API, but I haven't been able to make a final decision yet. I don't want to have Basic Authorization, because it doesn't make sense as I would need to store credentials in JavaScript that can be easily accessed and read by anyone entering the webpage and developer console. I'd like not to show any credentials to the end user so I can't keep them on the client's side.
I've read a lot about JWT and almost decided to implement it, but I've heard it has some drawbacks and haven't been so sure since then if it's the option I would like to choose. I know there is also oAuth 1.0 or oAuth 2.0 but I don't know if I want to have something this complicated. I would also like to store hashed user credentials in my own database in order not to be depended to any other credential providers like social media or Google.
Now I'm making another layer on my web server as a proxy hoping that it will allow me to authenticate user on this proxy level using Spring Security and having some kind or cookies or something to authenticate, but I'm not so sure if its doable this way and it increases the respond time, adds complexity and needs me to write controller methods for these endpoints. My architecture now is of the following:
Client (browser) -> Webserver -> REST API server -> db
I've also denied all external connections and allowed only localhost access to REST API on tomcat level so that I'd have to implement the security level only on the web server allowing free information transit between the webserver and REST API as it is not reachable anyway.
Web server and REST API are on the same server running as Tomcat instances.
I'm also not so sure if this kind of architecture will allow me to authenticate mobile app clients through the web server.
I would be very grateful for any piece of advice you would have for me in this matter. I'm not so experienced in security, so I'm a bit lost what I should do. Does this kind of architecture any sense or should I simply ask REST API directly from any type of clients, be it a webpage or a mobile app from different IPs and secure Rest API only? And if I want to secure some subpages of my webpage or parts of mobile app should that be an completely other layer?
Thank you for your help.
You have already gone through OAuth, JWT tokens etc. If you don't want to use them,then you can create your own token based authentication system.(say 'TokenHandler').
How this TokenHandler will work ?
TokenHandler will be like a gateway server i.e your every REST API request will route through this server application. So you will address your confusion of mobile and web application call with a authToken in header. Main responsibility of this server applciation is to accept the token and validate against the database where all token details are maintain. This DB will have information regarding timestamp when token was last used to validate, to decide your validation rule .
How Token will get generated ?
Token can be any random 64 digit alphanumeric string and will be generated and updated in DB during every single login activity. Login webservice returns this token in response body.
What can be rules for validation ?
It can be depending on your business logic. I preferred to keep active session window of 15 mins. Means if you access the webservice you will get active window of 15 more minutes. If you didn't access any service for 15 consecutive minutes then from 16th Minute you will need to login again to access further calls. This part can change according to requirements.
How client side will handle this ?
Client side will store this token and pass this token with every request call. Token Handler will validate and redirects it's request to the application server . So your one token handler can be used to server authentication of multiple applcation servers. This you can achieve by application end point identifer.
I will like to discuss further if you have any questions or suggestions .
Use API Gateway Architecture Pattern for your use case -
http://microservices.io/patterns/apigateway.html .
The API Gateway (The webserver in your question) can act as single entry point for all desktop/mobile clients. You can use either session cookies or jwts to authenticate clients at gateway.
With respect to authentication between gateway and micro services, and between micro services, i would suggest mutual ssl - https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication. If you are using spring boot, this might help - http://www.opencodez.com/java/implement-2-way-authentication-using-ssl.htm
The problem with IP white-listing approach is that - it's not well suitable for cloud architecture as the IPs might change with every server reboot. Even if you are using dedicated IPs, you should be careful to secure the communication with SSL/TLS, else attackers can easily sniff your traffic.

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