Fetching session attributes from static methods - java

I have used below codes for fetching session attributes from session util class(contains static methods). Want to know that below code could be right approach in multithreaded environment or is there any better other ways for fetching sessions from util.
public static HttpSession getSession(){
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession();
return session;
}
public static String getEmailIDFromSession(){
return (String)getSession().getAttribute("USER_EMAIL");
}

No, it's OK. And it is really thread safe. But from other side you should understand that it will be available only within HTTP Request Thread and from Spring MVC environment.
From other side, if you want to get that attribute from your #Controller or #Service you always can inject session there:
#Controller
class MyController {
#Autowired
private HttpSession session;
}

Related

Autowiring HttpSession give different object than HttpServletRequest

I use Spring Security, and I found strange behavior of framework while login. Spring Security WebAuthenticationDetails has parameter sessionId which is getting from HTTP request, and it all should be good, but in fact REST request gives me another session id. If I will autowire HttpSession and then get session id from it, I will get Spring-like id. So it seems that I have two ids for one user. Is it correct? Or I missed something?
EDITED:
For example this class will gave some session id
public class AuthenticationEventListener implements ApplicationListener<AbstractAuthenticationEvent> {
#Autowired
HttpSession httpSession;
#Override
public void onApplicationEvent(AbstractAuthenticationEvent event) {
if (event instanceof AuthenticationSuccessEvent) {
LoggedUser loggedUser = (LoggedUser) event.getAuthentication().getPrincipal();
loggedUser.initSessionParams(event.getAuthentication());
String sessionId = httpSession.getId();
}
}
}
and this method will give another one:
#RequestMapping(value = "/chart")
public Map getTestStatusesChart(HttpServletRequest request) {
String sessionId= request.getSession(false).getId();
return null;
}
So the answer is next: with condition of security Spring change session id by default. To prevent such behavior you need to disable session-fixation-protection in Spring Security config. more info by link

Get current session in spring boot application that utilize spring-session backed by MongoDB

I have an instance of HandlerInterceptorAdapter that intercept request to check locale...
public class LocaleControllerInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final HttpSession session = SessionContextHolder.getSession();
// ...
}
}
and my SessionContextHolder is :
public abstract class SessionContextHolder {
public static HttpSession getSession() {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attr.getRequest().getSession(true);
}
}
when I want to call an endpoint, the preHandle() method of the interceptor will called 2 times (why?!), in the first call, the session that SessionContextHolder gives me (by getSession() method) is an instance of org.apache.catalina.session.StandardSessionFacade, and the second time is an instance of org.springframework.session.data.mongo.MongoExpiringSession.
I've already enabled MongoHttpSession by #EnableMongoHttpSession annotation.
The problem is that, I expect that the session should always be an instance of MongoExpiringSession but is not.
Can anyone explain the mechanism of Spring-Session and the reason of this behavior?

Close session of the user using primefaces and Hibernate [duplicate]

What is the best possible way to invalidate session within a JSF 2.0 application? I know JSF itself does not handle session. So far I could find
private void reset() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
session.invalidate();
}
Is this method correct? Is there a way without touching the
ServletAPI?
Consider a scenario wherein a #SessionScoped UserBean handles the
login-logout of a user. I have this method in the same bean. Now
when I call the reset() method after I'm done with necessary DB
updates, what will happen to my current session scoped bean? since
even the bean itself is stored in HttpSession?
Firstly, is this method correct? Is there a way without touching the ServletAPI?
You can use ExternalContext#invalidateSession() to invalidate the session without the need to grab the Servlet API.
#ManagedBean
#SessionScoped
public class UserManager {
private User current;
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/home.xhtml?faces-redirect=true";
}
// ...
}
what will happen to my current session scoped bean? since even the bean itself is stored in HttpSession?
It will still be accessible in the current response, but it will not be there anymore in the next request. Thus it's important that a redirect (a new request) is fired after invalidate, otherwise you're still displaying data from the old session. A redirect can be done by adding faces-redirect=true to the outcome, as I did in the above example. Another way of sending a redirect is using ExternalContext#redirect().
public void logout() throws IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.invalidateSession();
ec.redirect(ec.getRequestContextPath() + "/home.xhtml");
}
Its use is however questionable in this context as using a navigation outcome is simpler.
public void logout() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
Frontend code is:
<h:form>
<h:commandLink action="#{userManager.logout()}">
<span>Close your session</span>
</h:commandLink>
</h:form>
Backend code is:
public String logout() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
return "/login.xhtml?faces-redirect=true";
}

Send request after success login with spring security

Right now, I'm learning about implementing REST API with a Spring Security Framework.
My question is, after success login with spring security, how can i send the request to server and make sure the server know that i am have been authorized (already login with success)?
I have a some experiment code to do testing
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { WebAppConfig.class, SecurityConfig.class })
public class TheTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private FilterChainProxy filterChainProxy;
protected MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders//
.webAppContextSetup(wac)//
.addFilter(filterChainProxy)//
.build()//
;
}
#Test
public void testDoingArequest() throws Exception {
// login here
HttpSession session = mockMvc.perform(//
//
post("/login-process")//
.param("username", "theusername")//
.param("password", "thepassword")//
)//
.andDo(print())//
.andExpect(status().isFound())//
.andReturn().getRequest().getSession()//
;
// login is success and now trying to call request
this.mockMvc.perform(//
get("/doingRequest")//
.session((MockHttpSession) session)// <-- where this part must added to?
)//
.andExpect(status().isOk())//
.andDo(print())//
;
}
}
-
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//
.antMatchers("/doingRequest").authenticated()//
.anyRequest().permitAll()//
.and()//
.csrf().disable()//
.formLogin()//
.loginPage("/")//
.loginProcessingUrl("/login-process")//
.defaultSuccessUrl("/");
}
-
#Controller
public class TheController {
#RequestMapping(value = "doingRequest", method = RequestMethod.GET)
#ResponseBody
public String doingSomething() {
return "Only authorized user can read this";
}
}
-
Above code is running well but i dont know how to implementing the "session" part in HTTP. I'm expecting something like put a token or something in header or url in real life application/implementation not in the testing environment. How the client get the token? How do we call the request (with token embedd) in client code.?
Are you looking for mocking a session object.If yes then you need to import the mock session object, and in the test class you can create and use the object.
import org.springframework.mock.web.MockHttpSession;
MockHttpSession session = new MockHttpSession();
session.setAttribute("variable", object);
The configuration you have will use the server side session to maintain the security context, and the link with the client is the standard servlet JSESSIONID cookie, so this has nothing to do with Spring Security. Whether you actually want a session or not will depend on the nature of your client. If there is no state maintained between the client and server, then each request from the client must be separately authenticated/authorized. This might be done using Basic authentication for example, or something like an OAuth2 access token depending on your requirements.

Howto access HttpSession from a custom DataSource in Spring?

Is there a way to access HttpSession from WebApplicationContext in a custom DataSource? I implemented a custom authentication processing filter that stores some infromation in the HttpSession. This information is then used by a DataSource to obtain a database connection.
Another option is to use the SecurityContextHolder to obtain an authentication token which is customized to include additional attributes. I am not sure this is the right approach.
This is what I have so far:
public class CustomDataSource extends DriverManagerDataSource implements ApplicationContextAware {
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
// want to use the web context to get the http session
// Authentication has a getAttribute(String name) method
SecurityContext securityContext = SecurityContextHolder.getContext();
CustomAuthenticationToken authentication = (CustomAuthenticationToken) securityContext.getAuthentication();
Object attribute = authentication.getAttribute("db");
// create a connection object here
Object conn = getConnectionFromAttribute(attribute);
return (Connection)conn;
}
private WebApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = (WebApplicationContext)applicationContext;
}
}
Update:
I defined a new class called AuthInfo, which has username and password only. Then reated a ThreadLocal as a static final variable of a utility interface:
public interface WebUtils{
public static final ThreadLocal<AuthInfo> authInfo = new ThreadLocal<AuthInfo>();
}
The value of the ThreadLocal is then set in the attemptAuthentication method of the filter
AuthInfo info = new AuthInfo();
info.setName(username);
info.setPass(password);
WebAttributes.authInfo.set(info);
Now, in the custom DataSource
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
AuthInfo info = WebAttributes.authInfo.get();
Connection conn = getConnFromAuthInfo(info);
return conn;
}
Isn't this is the same as using the SecurityContextHolder and the CustomAuthenticationToken?
In a typical multilayer application, your data access layer shouldn't have any knowledge of higher layers such as the HTTP interface.
I suggest you investigate using Spring's session or request scoping. You can create a scoped proxy bean in one of these scopes, place the authentication information in that, and inject it into the datasource.
Don't place that logic in the datasource. The http session and the database should not be related.
You can make the check in a HandlerInterceptor or with aspectj, around your controllers or service layer

Categories