Session Fixation and Session Scoped Beans in JSF 2.3 with CDI - session

It's a common best practice to renew the HTTP session when logging in a user. This will force a new session ID, avoiding session fixation vulnerabilities.
Is there a preferred pattern for implementing this with CDI when #SessionScoped beans are involved? The difficulty is that by invalidating the current HTTP session, you'll then get a different session-scoped bean with the next request, but not until the next request.
For example, assume a session bean for storing user login information:
#Named("sessionbean")
#SessionScoped
public class SessionBean implements Serializable {
private int userId;
private String username;
private List<String> privileges;
// Accessors omitted
}
And another bean for managing the login:
#Named("loginbean")
#ViewScoped
public class LoginBean implements Serializable {
private String username;
private String password;
#Inject private SessionBean session;
#Inject private SessionManager sessionManager;
#Inject private PrivilegeManager privilegeManager;
public String doLogin() {
String destinationUrl;
if (validate(username, password)) {
FacesContext context = FacesContext.getCurrentInstance();
// force renewal of HTTP session
context.getExternalContext().invalidateSession();
// retrieve new session bean ** No longer works with CDI **
Application app = context.getApplication();
session = app.evaluateExpressionGet(context, "#{sessionbean}", SessionBean.class);
session.setUsername(username);
session.setSessionId(sessionManager.createNewSession(username));
session.setPrivileges(privilegeManager.getPrivileges(username));
destinationUrl = createLandingPageUrl();
} else {
destinationUrl = createFailureUrl("Unknown user or password");
}
return destinationUrl;
}
}
With Managed Beans this would retrieve a new SessionBean, but with CDI, the code above would just return the same SessionBean. Any recommendations or clever ideas?

The difficulty is that by invalidating the current HTTP session, you'll then get a different session-scoped bean with the next request, but not until the next request.
Then don't invalidate the session, but change the session ID. In other words, don't use HttpSession#invalidate(), but use HttpServletRequest#changeSessionId() (new since Servlet 3.1, which you should undoubtedly already be using given that you're using JSF 2.3).
In code, replace
// force renewal of HTTP session object
context.getExternalContext().invalidateSession();
by
// force renewal of HTTP session ID
((HttpServletRequest) context.getExternalContext().getRequest()).changeSessionId();
This basically changes the JSESSIONID cookie without changing the HttpSession. It's perfect for session fixation prevention.
Explicitly invalidating the session is usually only useful during logout.

I'm going to restrict this answer to be solely about CDI since I am not a security expert. I also don't know whether the general thing being asked for is a good idea or not. Regardless, here is how I think you would do what you're asking for.
Expressed in purely CDI terms, the question can be rephrased like:
I have an object that I know came from a particular Context. I know the lifecycle of objects produced by this Context. How can I properly tell the Context to invalidate the current object that it is managing, and load or create a new one?
The general approach is going to be:
#Inject a Provider<SessionBean> instead of SessionBean directly (this will let you ask CDI for the "new" object properly)
#Inject a BeanManager (so you can get the right Context that manages SessionScoped objects)
ask the BeanManager to give you the AlterableContext corresponding to the SessionScoped annotation
tell the AlterableContext to destroy the current bean's contextual instance
call Provider.get() to cause a new one to be created
So the relevant parts of your doLogin method might look like this (untested):
final AlterableContext context = (AlterableContext) this.beanManager.getContext(SessionScoped.class);
assert context != null;
final Bean<?> bean = beanManager.resolve(beanManager.getBeans(SessionBean.class));
assert bean != null;
context.destroy(bean);
final SessionBean newSessionBean = this.sessionBeanProvider.get();
assert newSessionBean != null;
I think that should work.

Related

Make Spring's #Cacheable content live only during user session

While using Spring's #Cacheable, how to make sure the cache does not last longer than the actual session timeout?
Suppose your caches are defined as below,
#Cacheable("cacheName1")
public Map<String, List<String>> getMethod1(){
}
#Cacheable("cacheName2")
public Map<String, List<String>> getMethod2(){
}
then call below method while the user clicks logout / session expires.
#CacheEvict(value = { "cacheName1", "cacheName2"}, allEntries = true)
public void evictAllCache(){
logger.info("All Cache Evict");
}
Extend CacheManager to handle bucket's name, e.g. #session_#name
Extend HttpSessionListener to make a clean up when session is destroyed
please find my draft sample of explicit cache per session below:
https://gist.github.com/pyanoveugen/b360622dc76136064b0215136f402837

Spring scopes behaviour with respective to single and multiple web request/session

Whenever I try to analysis to understand the spring scopes I am stuck up somewhere. Below is my understanding from my analysis and before conclude myself I would like to confirm with you. Please correct me if my understanding is wrong.
<bean id="signupController" class="com.crp.controller.SignupController"
scope="">
If scope is "request", then for every new request from client irrespective of session, the spring container will generate new instance. Once the request is completes then spring container will manage to close the life cycle of instance.
If scope is "session", then for first request of a session a new instance will be generated by spring container and maintain it for all the client request for that particular session. Once the session timed out then spring container will manage to close the life cycle of instance.
If scope is "prototype", new instance will be generated by spring container whenever the bean is requested irrespective of session. Developer should manage the life cycle of the instance because spring container will not manage life cycle of prototype scope.
If scope is "singleton", only one instance generated by spring container and maintain it to be available for all request irrespective of sessions. For every session a copy of singleton instance will be maintained so that the one session singleton object will not share by another session and spring container will manage the life cycle of the copy of singleton instance and close it when session timed out.
Note: I believe most of you may have different opinion in my understanding on singleton scope. Even I am also confused in the behaviour of singleton scope and getting different information during my analysis. Please share your thoughts
Thank you.
For singleton scope how container works for below implementation for multiple user (session) send request at same time.
Login.java:
public class Login {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
LoginController.java:
public class LoginController extends MultiActionController {
private Login login;
public ModelAndView submitLogin(HttpServletRequest request,
HttpServletResponse response) {
String userName = request.getParameter("username");
String password= request.getParameter("password");
getLogin().setUserName(userName);
getLogin().setPassword(password);
// TODO send login bean to DAO for executing further business logic.
}
public Login getLogin() {
return login;
}
public void setLogin(Login login) {
this.login = login;
}
}
context.xml:
<bean id="login" class="com.crp.bean.Login" scope="singleton">
</bean>
<bean id="loginController" class="com.crp.controller.LoginController" scope="singleton">
<property name="login" ref="login"></property>
</bean>
No, that's not entirely correct.
If scope is "request", then for every new request from client irrespective of session, the spring container will generate new instance.
No. The bean instance will only be created if the code calls a method on the bean (i.e. on the scoped proxy that wraps the actual bean instance). But you're right that every request has a bean instance that is different from the other requests, and that the bean is destroyed at the end of the request (i.e. its life-cycle hooks, if they exist, are called when the request ends).
If scope is "session", then for first request of a session a new instance will be generated by spring container and maintain it for all the client request for that particular session.
Same remark as for the request scope: the bean instance is created on-demand.
If scope is "prototype", new instance will be generated by spring container whenever the bean is requested irrespective of session.
Right. But note that you need to request a bean instance to the spring context to get a new instance. If you inject a prototype to a singleton bean, the singleton bean will keep a reference to this bean for all of its life, and the same prototype bean will thus be used every time the singleton bean calls it.
If scope is "singleton", only one instance generated by spring container and maintain it to be available for all request irrespective of sessions. For every session a copy of singleton instance will be maintained so that the one session singleton object will not share by another session and spring container will manage the life cycle of the copy of singleton instance and close it when session timed out.
No. That is completely wrong. No copy is made at all. A single instance is created, injected everywhere, and used concurrently everywhere. The bean is only destroyed when the application itself ends.

IllegalStateException when trying to .getSessionMap() from a Session Scoped Bean

I'm new to Java and JSF. I need help with an IllegalStateException. Here's the scenario:
In my current project i have this Session Scoped bean for the application menu:
public final class MenuBean implements Serializable{
private MenuModel model;
private FacesContext context = FacesContext.getCurrentInstance();
public MenuModel getModel() {
return model;
}
public MenuBean() {
updateMenu();
}
public void updateMenu(){
Map session = (Map<String,Object>) context.getExternalContext().getSessionMap();
EUser user = (EUser) session.get(UserBean.USER_SESSION_KEY);
...
}
private MethodExpression createMethodExpression(String action) {
...
}
}
At some point of my logic, i need to update the menu, so i do this:
ExternalContext extContext = context.getExternalContext();
Map sMap = (Map<String,Object>) extContext.getSessionMap();
MenuBean menu = (MenuBean) sMap.get("menuBean");
menu.updateMenu();
The bean constructs fine, but when i try to manually update it as shown above, i get and IllegalStateException on the 1st line of the update method updateMenu()
I don't understand what's wrong, since I can get the session map with that same call whe the menu is build in the first time.
Also, using the NetBeans debugger, i can see that the instance of MenuBean is correctly recovered.
Can you guys help me?
The FacesContext is stored in the HTTP request thread. You should absolutely not declare and assign it as an instance variable of an instance which lives longer than the HTTP request (and preferably also just not when it's already request based -it's bad design). The FacesContext instance is released and invalidated when the HTTP request finishes. In any subsequent HTTP request the instance is not valid anymore. There's means of an illegal state. That explains the IllegalStateException you're seeing.
You need to remove the following line:
private FacesContext context = FacesContext.getCurrentInstance();
And fix your code to get it only threadlocal in the method block:
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
// ...
You can always assign it as a variable, but that should only be kept threadlocal:
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
// ...
Unrelated to the concrete problem, using #ManagedProperty has been easier in this particular case.
public final class MenuBean implements Serializable {
#ManagedProperty("#{user}")
private EUser user;
// ...
}
JSF will then inject it for you.

Does JSF store my helper class, which is referenced in my ManageBean in the session too?

Just a doubt regarding how JSF session management works
I got a managedbean as :
#ManagedBean(name="loginBean")
#SessionScoped
public class LoginBean implements Serializable
{
private String userName;
//getter and setter
private String password;
//getter and setter
// Getting through spring injection
#ManagedProperty(value="#{userBO}")
private UserBO userBO;
//setter method
public fetchUserDetails(){
User user = userBO.getUSer(this.userName);
//some processing
}
// more methods
.
.
.
}
So now since the bean is sessionScoped, will JSF keep my "userBO" object in the session too?
I believe that variables with both the setters and getters are likely to be stored in the session. Correct me if I am wrong.
Or do I have to declare "userBO" as transient so that it is ignored?
If your session is persisted in memory between requests, any other objects it references will be kept and not be eligible for garbage collection. There is no task that walks an object's internals setting references to null. Managed properties are only evaluated when the bean is created and before it is placed into scope.
Setting userBO to transient would only have an effect if the session was serialized (via passivation to disk, via session replication, etc.)

Struts2 - Session Troubles

I make (thanks with some users on this portal) my application that implements SessionAware.
This is my actual code :
public class UserManager extends ActionSupport implements SessionAware {
private Map<String, Object> session;
#Override
public String execute() throws Exception {
return SUCCESS;
}
public void setSession(Map<String, Object> map) {
this.session=map;
}
public String checkLogin() {
session.put("loggedOn", true);
return SUCCESS;
}
public String checkLogout() {
session.clear();
return SUCCESS;
}
}
And i check these variables on my .jsp :
<s:if test="#session['loggedOn']!=true">
DIV LOGIN
</s:if>
<s:else>
DIV LOGOUT
</s:else>
An easy piece of code.
What i'd like to know is this :
1 - the bean is (as default) request scoped. So when the request is finished it will be destroyed. But i see that, when i put a variable in the Map, it still alive on the server. How is possible? Is a variable of my Bean.
2 - Who call the setSession method? I think the servlet, due to the fact I implements that interface?
3 - I would like to detach about saving object/bean on a Session Object. I'd like to use the Bean session scoped (as for any kind of MVC framework). How can I do it on struts2?
Hope you can make clear these questions :) Cheers
1) Your bean is a struts2 action as such it is action scoped (which is a more restrictive scope than request). I say that action is a lesser scope because you can forward an action to another action in which case the previous action goes out of scope, request scoped objects however will stay in scope until the request is served. When you implement SessionAware you are provided with a reference to the SessionObject you are then putting your object into the Session object who's life span is much longer than your action. Clear your browser cache will remove the session value... you can also remove them by code be implementing SessionAware and removing the value from the map.
2 - The session already exists. You can get the session and add keys but even if you don't put anything in it, it will be there for use.
3 - You have a later question already for this topic see my answer there.

Resources