What's the expected way to set org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT to increase a tomcat websocket timeout? Tomcat documentation states the following:
This may be changed by setting the property
org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT in the user
properties collection attached to the WebSocket session.
The WebSocketSession I see available in the TextWebSocketHandler's afterConnectionEstablished method doesn't apear to have user properties. So, I assume that's not what the documentation means. In looking at TomcatRequestUpgradeStrategy, it appears to me that it never looks at an endpoint user properties. It also doesn't appear to me that you can overwrite TomcatRequestUpgradeStrategy since AbstractHandshakeHandler has a hardcoded class name for TomcatRequestUpgradeStrategy.
Please help.
org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT is an user property you need to set on WebSocket API's Session, not the Spring abstractions of this interface.
You can configure it in the afterConnectionEstablished method by casting the Spring WebSocketSession to NativeWebSocketSession and retrieving the underlying WebSocket API session:
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
if (session instanceof NativeWebSocketSession) {
final Session nativeSession = ((NativeWebSocketSession) session).getNativeSession(Session.class);
if (nativeSession != null) {
nativeSession.getUserProperties()
.put("org.apache.tomcat.websocket.BLOCKING_SEND_TIMEOUT", 60_000L);
}
}
}
Related
The spring app has a session bean, which contains certain data. That data is loaded from DB at init request to the controller, which is always a first request client calls at start up. That data is used for other requests by same user. Now, everything works fine on its own. However after trying to integrate the app into the system using zuul (which as far as I understand in this context simply redirects request from one url into another), it broke. Whenever a method is called after the init, the session bean's data is null.
Here is a snippet from service class:
#Autowired
TaskCache cache;
#Override
public void initUserSession() {
List<Task> data = loadTasks();
cache.setTasks(data);
LinearFilterStack<Task> fs = createFilterStack(data);
cache.setFilterStack(fs);
System.out.println(cache.hashCode()); //hashcode stays same
System.out.println(cache.getFilterStack() == null) //false
}
#Override
public List<Task> getTasks(Sort sort) {
System.out.println(cache.hashCode()); //hashcode stays same
System.out.println(cache.getFilterStack() == null) //true
LinearFilterStack<Task> fs = cache.getFilterStack();
List<Task> tasks = fs.filter(cache.getTasks()); //Obviously NPE
sortTasks(tasks, sort);
return tasks;
}
#Component
#Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.TARGET_CLASS)
public class TaskCache { ... }
And again, this only happens through zuul. I.e. if I use localhost:30022/rest/... it works, if I use localhost:8080/app/tasks/rest/... (which zuul redirects to localhost:30022/rest/...) I get NPE, because the cache bean loses its data after init request.
That could be caused by default behavior of Zuul that prevents passsing of cookie related headers.
The following is that default configuration of Zuul and it doesn't allow pass below headers to your downstream API servers.
zuul.sensitiveHeaders= Authorization,Cookie,Set-Cookie
So please try to define below properties. It will allow all your cookie related header to be passed to your API servers.
zuul.sensitiveHeaders= Authorization
You can find more details in section "Cookies and Sensitive Headers" of this document
I got a simple spring security application with a user administration.
An admin should be able to create/update/delete users on the database (via hibernate).
If a user is updated, I am reloading the authentication of the user which is currently logged in. That's done with the following code (according to this example):
SecurityContextHolder.getContext().setAuthentication(updatedAuthentication);
My question is:
What can I do if a user is deleted? If I delete a user, already active sessions remain active and I don't know how to update them. I can still navigate to every page I was able to go to before.
Is there a way to tell spring that a session should be revalidated or something like that? Did I miss anything important?
On each request you should check your database for User existence.
Steps :
Take the userid from session, check it is in the database or not.
If not in the database invalidate the session and redirect to login page again.
Wrap those above two stpes in a method and call it on each request. (If common method is there use that or create e Listener)
Also you can check the following link if it helps. http://forum.spring.io/forum/spring-projects/security/35809-how-to-let-admin-to-force-user-to-logout
Another helpful link is http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#list-authenticated-principals
SecurityContextRepository
From Spring Security 3.0, the job of loading and storing the security context is now delegated to a separate strategy interface
You can provide a NullSecurityContextRepository in order to avoid the storage of security context information.
I did something like this:
#EnableWebSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// Other security configuration...
http.securityContext().securityContextRepository(new NullSecurityContextRepository());
}
}
I am using Spring Session 1.0.1. I need to execute some logic when the user logs out, and I need to rely on the HTTP session being invalidated to cover the case where the user fails to explicitly log out.
The standard Spring Security SessionDestroyedEvent includes any applicable SecurityContext, but the Spring Session version of SessionDestroyedEvent only contains the session id. By the time this event fires, the session is no longer held by the SessionRepository so it can't be looked up by id.
Is there any way to retrieve the SecurityContext from the expired session using Spring Session?
Unfortunately there is not. The problem is that at the time Redis fires the event, the session is already gone. Furthermore, the event received from Redis does not contain the original information. This means there is no way to retrieve the SecurityContext.
For updates on this please track spring-projects/spring-session/issues/4
For sring-session 1.1+ with Redis
https://docs.spring.io/spring-session/docs/current/reference/html5/#httpsession-httpsessionlistener
You must configure HttpSessionEventPublisher and after that spring-session will propagate sessionDestroy event
#Configuration
#EnableRedisHttpSession
public class RedisHttpSessionConfig {
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
// ...
}
So you can use standard spting SessionDestroyedEvent listener
#Component
public class SessionDestroyListener implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
logger.debug("session destroyed {}", event.getId());
if(!event.getSecurityContexts().isEmpty()) {
...
}
}
}
I'm trying to integrate Hazelcast (lasted version - 3.3) session replication.
Our infrastructure consists of :
Apache 2.0 server for the load balancing
Tomcat 7 servers serving our web application
Our main reasons are:
Duplicate user session for high availability
Atmosphere web-socket PubSub servlet need share the same data in order to make full
broadcasting
integrating Hazelcast to our Environment:
each of the tomcat servers will serve as Hazelcast member
basically Hazelcast WebFilter is the first one that executes and its
wrap with : WebFilter->HazelcastSession->setAttribute() implements
HttpSession interface
each time setAttribute is called Hazelcast sync the session attribute
with the rest of the cluster members.
now - its seems like every spring bean we injecting scoped as session bean don't get replicated .
as a workaround :
Save only basic session information via #Context annotation
Dont use Spring session scope , only Singletons and inject the HazelcastInstance
I can Wrap the relevant data as Hazelcast structures
Also, when i looked on other stackoverflow i saw the following : Spring "session" scope of a bean?
The Spring session does not exactly match the HttpSession, and even
the Spring documentation on the #SessionAttributes annotation says
that it might be stored in the session or "some conversational
storage". I got that from [The Spring docs for 2.5][1] I've basically
quit trying to make sense of it, and just got on with my life, if I
want something stored in the HttpSession, I just have Spring inject
the HttpSession to me, assuming you're using Spring MVC its pretty
easy, instructions on the same page.
[1]:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
Its seems strange , Does Spring session beans not exactly match the HttpSession.setAttribute ?
How spring know how to #Inject the proper bean ?
Maybe Spring save the Beans in an internal data storage and only in
the Injection phase Spring getting the proper element using the same
session id attribute and bind the proper bean.
is there any way to control this behavior ?
Update :
debugging spring-web -> ServletRequestAttributes-> is using the
Server impl HTTPSession (For example - in Dev Jetty - org.eclipse.jetty.server.session.HashedSession)
this way the Bean is update in the HTTPSession but skipping the
HazelcastSession :-(
/**
* Update all accessed session attributes through {#code session.setAttribute}
* calls, explicitly indicating to the container that they might have been modified.
*/
#Override
protected void updateAccessedSessionAttributes() {
// Store session reference for access after request completion.
this.session = this.request.getSession(false);
// Update all affected session attributes.
if (this.session != null) {
try {
for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
String name = entry.getKey();
Object newValue = entry.getValue();
Object oldValue = this.session.getAttribute(name);
if (oldValue == newValue) {
this.session.setAttribute(name, newValue);
}
}
} catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
this.sessionAttributesToUpdate.clear();
}
thanks in advance ,
elad.
I'm using Spring-MVC with Spring Security for my web application. It includes user registration pages and private user panel. I have it set up currently with the following URL patterns:
whatever/myapp/login user log in
whatever/myapp/register?step=1 start registration
whatever/myapp/account/** private area views (pages)
whatever/myapp/pending view shown while post-registration processes complete
whatever/myapp/blocked account blocked view
whatever/myapp/register/retry if registration failed, allow retry
Essentially, these URLs below should require user authentication, i.e. require log-in:
whatever/myapp/account/** (private area pages)
whatever/myapp/pending (this page has a timer set to redirect to /account/home)
whatever/myapp/register/retry
This is quite straightforward to achieve using Spring security. However, regardless of user authentication through Spring security, private area pages should be accessible or not, depending on user's current account status (stored in my DB).
More specifically: if a user tries to access anything in the private area (/account/**), he should be shown the appropriate view (redirected to appropriate page), according to the status. I have these statuses defined:
suspended - relates to pending view
enabled - allow full access
disabled - not relevant here
retry_allowed- relates to retry view
blocked - relates to account-blocked view
Currently, I have a MVC interceptor setup to /account/**, that checks user status, and redirects to appropriate pages, but somehow I get the sense that this is not really the ideal or appropriate solution here, since I'm facing strange behavior, like multiple controller invocation... and also I'm not quite certain when to return true / false within preHandle() method. Here's the code snippet from the interceptor:
#Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object arg2)
throws Exception {
IPanelUser pUser = (IPanelUser) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
// check principal first and then load from DB
// "suspended" is initial status upon registration
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
// if suspended, load from DB and update status
Customer customer = this.customerService.getUserByUsername(pUser.getUsername());
if(customer != null)
pUser.getCustomer().setStatus(customer.getStatus());
// still suspended? redirect to pending
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) {
response.sendRedirect("../pending");
return false;
}
}
if(pUser.getCustomer().getStatus() == CustomerStatus.Blocked.getCode()) {
// redirect to blocked page
response.sendRedirect("../blocked");
SecurityContextHolder.clearContext();
return false;
}
if(pUser.getCustomer().getStatus() == CustomerStatus.AllowRetry.getCode()) {
// redirect to CC submission page
response.sendRedirect("../register/retry");
return false;
}
if(pUser.getCustomer().getStatus() == CustomerStatus.Enabled.getCode() ||
pUser.getCustomer().getStatus() == CustomerStatus.Disabled.getCode()) {
// do nothing
}
return true;
}
.
Is this a valid approach ? Any alternative suggestions ?
All options are valid, it depends on the level of abstraction you want.
In a Filter, you only have access to HttpServletRequest and HttpServletResponse objects, so you are very much coupled with the Servlet API. You also don't (directly) have access to all the great Spring functionality like returning a view to be rendered or a ResponseEntity.
In a HandlerInterceptor, it's again more of the same. You can do your redirection or request handling directly in the preHandle() where you don't have access to the ModelAndView or set a flag which you check in postHandle(). You would have access to the ModelAndView but not to some other Spring MVC functionality.
Spring Security is a good alternative, but I find it has a lot of configuration that I don't like too much.
One final alternative, that I like the most, is to use AOP (you can do this with Spring Security or Shiro as well). You create an annotation like #Private and you annotate your #Controller handler methods. You use AOP to advise these methods. The advice basically checks some session or request attribute for a flag (authorized or not). If you are allowed, you continue executing the handler method, if not, you throw an UnauthorizedException (or similar). You then also declare an #ExceptionHandler for that exception where you have pretty much complete control over how the response is generated: a ModelAndView (and related), a ResponseEntity, annotate the handler with #ResponseBody, write the response directly, etc. I feel like you have much more control, if you want it.