Session attributes not working in Spring #RestControllers - spring

I have added location as a session attribute as given below
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
com.blife.werp.model.User userSession = userRepository.findByUsername(user.getUsername());
HttpSession session = request.getSession();
session.setAttribute("user", userSession);
session.setAttribute("username", user.getUsername());
session.setAttribute("location",userSession.getLocation());
try {
userService.isloggedIn(true, userSession,request);
} catch (Exception e) {
e.printStackTrace();
}
redirectStrategy.sendRedirect(request, response, "/dashboard");
}
but when I used it in Spring Rest service as given bellow gave me and exception
"org.hibernate.LazyInitializationException: could not initialize proxy - no Session"
#RequestMapping("/get_product_by_location")
public List<ProductStock> getProductByLocation(HttpServletRequest request, #RequestParam String code){
HttpSession session = request.getSession();
Location location = session != null ? (Location) session.getAttribute("location") : null;
System.out.println(code+" "+location);
List<ProductStock> products = productService.getProductByLocation(code,location);
System.out.println(products);
return products;
}
Can any one let me now the issue in my code example to cause this error, If the "location" attribute is already in the session why it gave me an Lazy Initialization I am not going fetch this via any Repositories.

Related

SecurityContextHolder authentication object not available to subsequent requests from the client

Inside getUserObject() method we are not able to get Authentication object. It's available for 1st request only. But its setting to null for subsequent requests from client. So please help me to configure it properly so that its available for all the requests calls.
I am not sure how to configure inside configure method in AuthConfig.java so that authentication object would be available for all the requests chain
AuthConfig.java:
#Configuration
#EnableWebSecurity
public class AuthConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/callback", "/", "/auth0/authorize", "/resources/**", "/public/**", "/static/**",
"/login.do", "/logout.do", "/thankYou.do", "/customerEngagement.do",
"/oldCustomerEngagement.do", "/registerNew.do", "/forgotPassword.do", "/checkMongoService.do",
"/reset.do", "/rlaLogin.do", "/fnfrefer.do", "/thankYouLeadAggregator.do", "/referral")
.permitAll()
.anyRequest().authenticated().and().
logout()
.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler());
}
------------------------------------------------------------------------------
AuthController.java:
#RequestMapping(value = "/callback", method = RequestMethod.GET)
public void callback(HttpServletRequest request, HttpServletResponse response)
throws IOException, IdentityVerificationException {
try {
Tokens tokens = authenticationController.handle(request, response);
DecodedJWT jwt = JWT.decode(tokens.getIdToken());
List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication auth = new UsernamePasswordAuthenticationToken(jwt.getSubject(), jwt.getToken(), grantedAuths);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
response.sendRedirect(config.getContextPath(request) + "/loancenter/home.do");
} catch (Exception e) {
LOG.info("callback page error");
response.sendRedirect(config.getContextPath(request) + "/loancenter");
}
}
--------------------------------------------------------------------------------
HomeController.java:
#Controller
public class DefaultController implements InitializingBean {
#RequestMapping(value = "home.do")
public ModelAndView showCustomerPage(HttpServletRequest req, HttpServletResponse res, Model model) {
ModelAndView mav = new ModelAndView();
try {
User user = getUserObject(req);
if(user==null) {
LOG.info("User not found in session");
mav.setViewName(JspLookup.LOGIN);
return mav;
}
} catch (Exception e) {
LOG.error("Exception in Home page ", e);
}
return mav;
}
protected User getUserObject(HttpServletRequest request) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
LOG.info("authentication::{}", authentication);
User user = null;
if (authentication == null) {
return user;
}
if (authentication.getPrincipal() instanceof User) {
user = (User) authentication.getPrincipal();
LOG.info("User already authenticated and logging :{}", user.getEmailId());
sendUserLoginEmailToLO(user);
} else {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
user = userProfileDao.findByUserEmail(jwt.getClaims().get("email").asString());
if (user != null) {
LOG.info("First time authentication:{}", user.getEmailId());
boolean auth0EmailVerified = jwt.getClaims().get("email_verified").asBoolean();
LOG.info("First time authentication email verified flag from auth0:{}", auth0EmailVerified);
LOG.info("First time authentication email verified flag from nlc:{}", user.getEmailVerified());
if (BooleanUtils.isFalse(user.getEmailVerified()) && auth0EmailVerified) {
LOG.info("Email is verified in Auth0, updating email_verified flag to true in DB for userId: {}",
user.getId());
userProfileDao.verifyEmail(user.getId());
LOG.info("First time authentication updated email verified flag in nlc db:{}", user.getEmailId());
}
if (user.getNewEmailVerified() != null && BooleanUtils.isFalse(user.getNewEmailVerified())) {
LOG.info("The user is verifying his email: set his verified to true");
userProfileDao.verifyNewEmail(user.getId());
}
Authentication auth = new UsernamePasswordAuthenticationToken(user, jwt.getToken(),
token.getAuthorities());
messageServiceHelper.checkIfUserFirstLogin(user);
LOG.info("Authentication provided for user : {}", user.getEmailId());
LOG.debug("Auth object constructed : {}", auth);
SecurityContextHolder.getContext().setAuthentication(auth);
HttpSession session = request.getSession(true);
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
sendUserLoginEmailToLO(user);
}
}
return user;
}
}

Spring Security: Unable to re-login

I am fixing an existing application, where first login works fine and the logout works fine taking me back to login page.
However after logout, when I try to re-login without browser refresh (just enter credentials on login page), I am getting redirected to Host based URL(which is blocked over the intranet).
Reason
SavedRequest savedRequest = requestCache.getRequest(request, response);
is null during re-login.
I think that may be because I loggedOut, session is cleared by LogoutHandler.
Code for reference.
`public class BroadleafAdminAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
RequestCache requestCache = new HttpSessionRequestCache();
private static final String successUrlParameter = "successUrl=";
private static final String APPLICATIONURL = "APPLICATIONURL";
#Resource(name = "blAdminSecurityRemoteService")
protected SecurityVerifier adminRemoteSecurityService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
AdminUser user = adminRemoteSecurityService.getPersistentAdminUser();
if (user != null && user.getLastUsedSandBoxId() != null) {
request.getSession(false).setAttribute(BroadleafSandBoxResolver.SANDBOX_ID_VAR, user.getLastUsedSandBoxId());
}
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
return;
}
.
String targetUrl = savedRequest.getRedirectUrl();
.
*Logic where I update my targetUrl*
.
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}`
I want to avoid going into this condition
if (savedRequest == null) Since I am then unable to execute
*Logic where I update my targetUrl*

401 Unauthorized on authenticationManager.authenticate() (Spring Security)

401 Unauthorized produced when trying to login while registration works perfectly fine.
During debug i've spotted that response is given on the line where method authenticationManager.authenticate() at UserController is called. Another thing i noticed is that for some reason i haven't had this issue while working with JPA Repositories rather than DAO.
I'm using PostgreSQL
Here is code for corresponding method if UserController:
#RequestMapping(path = "/auth", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.OK)
public AuthResponse authenticate(#RequestBody AuthRequest req){
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(req.getUsername(), req.getPassword()));
String token = jwtService.generateToken(req.getUsername());
return new AuthResponse(token);
}
JwtFilter.doFilterInternal():
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = httpServletRequest.getHeader("Authorization");
String jwtToken = null;
String username = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer")) {
jwtToken = authorizationHeader.substring(7);
username = jwtService.extractUsername(jwtToken);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.validateToken(jwtToken, userDetails.getUsername())) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()
);
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
SecurityConfig.configure():
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable()
.authorizeRequests()
.anyRequest().permitAll()
.and().addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic();
}
UserService.loadUserByUsername():
#Service
public class UserService implements IUserService, UserDetailsService {
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User userByName = userDao.getUserByUsername(s);
return new org.springframework.security.core.userdetails.User(userByName.getUsername(), userByName.getPassword(), userByName.getAuthorities());
}
}
DAO query:
#Override
public User getUserByUsername(String username) {
return jdbcTemplate.queryForObject("SELECT * FROM user_table WHERE username = ?", new Object[]{username}, User.class);
}
This is probably a JWT issue.
In the row: .and().addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
Use the Debug to see, what do you have in there as parameters.
If you look at the documentation :
An AuthenticationManager must honour the following contract concerning exceptions:
A DisabledException must be thrown if an account is disabled and the AuthenticationManager can test for this state.
A LockedException must be thrown if an account is locked and the AuthenticationManager can test for account locking.
A BadCredentialsException must be thrown if incorrect credentials are presented. Whilst the above exceptions are optional, an AuthenticationManager must always test credentials.
Exceptions should be tested for and if applicable thrown in the order expressed above (i.e. if an account is disabled or locked, the authentication request is immediately rejected and the credentials testing process is not performed). This prevents credentials being tested against disabled or locked accounts.
I'm guessing your authenticate is throwing one of these three exceptions (or possibly some other exception). You need to look at your logs to determine which one, or catch the exception and debug it.
The issue was that query did not return excpected value. I changed:
#Override
public User getUserByUsername(String username) {
List<User> userList = jdbcTemplate.query("SELECT * FROM user_table WHERE username = ?", new Object[]{username}, (resultSet,i) -> {
System.out.println(1);
return new User(resultSet.getInt("id"),
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("role"));
});
return userList.get(0);
}

using servlet filter with session variable

I have created a Java web application using JSF 2.
When a user login to my application, I store his identifier in the session, so:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("userid", myBean.getUserId());
Then I created my filter:
public class PageFilter implements Filter {
private FilterConfig filterconfig;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterconfig = filterconfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httprequest =(HttpServletRequest) request;
HttpServletResponse httpresponse =(HttpServletResponse) response;
HttpSession session = ((HttpServletRequest) request).getSession();
String userid = (String) session.getAttribute("userid");
String pageRequested = httprequest.getRequestURI();
try {
if( userid != null && pageRequested.contains("index.xhtml") ) {
System.out.printf("User authenticated with " + httprequest.getRemoteUser() + " username conected.");
httprequest.getRequestDispatcher("/service/home.xhtml").forward(request, response);
} else {
chain.doFilter(request, response);
}
}catch(IOException | ServletException e){
//do something
}
}
#Override
public void destroy() {
System.out.print("Existing from loginFilter");
}
}
My scope is to manage the refresh button of the browser so if user is already logged then user is redirected to /service/home.xhtml. Also, the url in my web application is always:
localhost:8080/myapplication
So if user browses the site among all the pages, the url is always that (the action is hidden).
The problem is that if user clicks on the url in the browser, the request is for index.xhtml and my session is null (I cannot get user identifier by session.getAttribute("userid");).
Where is my fault?
The index.xhtml is defined as welcome-file-list in my web.xml:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
Thanks.

How to know that a session is expired?

I set values to the session object in the method of a controller after success of login :
#RequestMapping(value = "/", method = RequestMethod.POST)
public ModelAndView processLogin(Model model, HttpServletRequest request, HttpSession session, #RequestParam String login, #RequestParam String pwd) {
if ( utilisateurDao.verifierLoginUser(login) ) {
if ( utilisateurDao.verifierUser(login, pwd) ) {
HashMap<String, String> criteres = new HashMap<String, String>();
criteres.put("user_login", login);
criteres.put("user_passwd", pwd);
List<Utilisateur> users = utilisateurDao.lireParCritere(criteres);
session.setAttribute("user_code", ((Utilisateur)users.get(0)).getUser_code());
session.setAttribute("menu", menuDao.afficherMenuParUtilisateur((Integer)session.getAttribute("user_code"), env, request, session));
criteres.clear();
users.clear();
criteres.put("user_code", String.valueOf(session.getAttribute("user_code")));
users = utilisateurDao.lireParCritere(criteres);
session.setAttribute("user_names", ((Utilisateur)users.get(0)).getNoms());
session.setAttribute("logout_menu", env.getProperty("menu.logout"));
return new ModelAndView("redirect:/accueil");
} else {
ModelAndView modelViewLogin = new ModelAndView("redirect:/");
modelViewLogin.addObject("e", "p").addObject("l", login);
return modelViewLogin;
}
} else {
ModelAndView modelViewLogin = new ModelAndView("redirect:/");
modelViewLogin.addObject("e", "l");
return modelViewLogin;
}
}
Then I opened the app inactive for some minutes. After that I went to the "accueil" path. Then the menu was not shown anymore ! The menu was got from session. So how to know that the session is expired and where is the convenient place to test it ?
By default in spring security session is stored in SessionRegistry.
By using SecurityContext you can get this info in your controller code.
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
If you want to be notified when session has expired or person logged out you can always register listener on SessionDestroyedEvent- documentation.
example:
#Component
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
//do your stuff here
}
}
Its also worth to refer to spring docs for that subject.
You can make a Interceptor,
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter
In this interceptor you can control the HttpServletRequest
and check if obj exists into them and then you can throw to a new SessionExpiredException and catch with #ExceptionMapper (https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc)
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if (request.getSession().getAttribute("user")==null) {
throw new SessionExpiredException();
}
return true;
}
I check like below. I think it might be help.
public boolean isUserLoggedIn(HttpServletRequest request) throws IOException {
SecurityContext securityContext = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if(securityContext != null) {
Authentication authentication = securityContext.getAuthentication();
if(null != authentication && authentication.isAuthenticated() != true)
return false;
else
return true;
} else {
return false;
}
}

Resources