So, I am working on creating a simple chat app. I'm not using spring security.
So, in front end, the user enters their name which is handled by this controller.
#PostMapping("/addUser")
public User addUser(#RequestBody String name, HttpServletRequest request) {
String session = (String) request.getSession().getAttribute("sessionId");
System.out.println("Session id is " + session);
User newUser = new User(name, session);
userService.addUser(newUser);
System.out.println(newUser);
return newUser;
}
I'm using pre handler method handler interceptor to generate session id for the user. Below is the code:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Its working");
// TODO Auto-generated method stub
if(request instanceof HttpServletRequest) {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpSession session = servletRequest.getSession();
session.setAttribute("sessionId", session.getId());
System.out.println("Connected with session id : " + session.getAttribute("sessionId"));
}
return true;
}
So, I want to make sure that whenever users are inactive for cetain time, I want to end the session for that user and also remove that user from the arraylist of user where I have kept all the users who register by entering their name (in the front end).
Is it possible to achieve without sprin security or do I have to learn spring security to implement it.
I did try using task scheduler but then I found out in some article that its impossible to call HttpSession there.
You can set the session life (time it can be inactive before being killed) with server.servlet.session.timeout=30m
You can take the user out of your list by implementing a HttpSessionListener.sessionDestroyed - spring-boot-session-listener
if you use WebSocket, You can use heartbeat for your session, on the other hand, if you use rest then you should keep the session in memory(redis, hazelcast, or in-memory (singleton object) like map<key, session>,
(keep in mind, the client should send a disconnect request or you should control it in the backend)
So, I'm trying to send cookies to my frontend and I'm not using spring security. When the user enter their name and click submit button, I want that info to be send to my spring and then I want to return the info of the user and cookie. I implemented the logic like this
#PostMapping("/addUser")
public User addUser(#RequestBody String name, HttpServletRequest request, HttpServletResponse response) {
HttpSession getSession = (HttpSession) request.getAttribute("session");
Cookie cookie = new Cookie("sessionId", getSession.getId());
response.addCookie(cookie);
sessionService.addSession(getSession);
String session = (String) getSession.getId();
System.out.println("Session id is " + session);
User newUser = new User(name, session);
userService.addUser(newUser);
return newUser;
}
to check if cookie is working correctly, I'm using this method
#PostMapping("/noOfUsers")
public int userCount(#RequestBody String sessionId, HttpServletRequest request, HttpServletResponse response) {
System.out.println(request.getSession().getId());
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("sessionId")) {
System.out.println(cookie.getValue());
}
}
}
return this.userService.noOfUser();
}
I know you people might say "use get mapping" well I want to send my user account too when checking that's why I'm using postmapping where I will be sending my username too.
So, coming back to question. Well, I did try using postman and it worked I got the cookie value as I should have but when working with frontend, it just didn't worked which made me question am I doing it in right way??
I am doing a rest app in spring and i have a log out method like below. I dont have knowledge on spring so i just searched around and made this.
#RestController
public class LogoutController {
#Autowired
private DatabaseService databaseService;
#RequestMapping(value = "/myApp/user/logout", method = GET, produces = {"application/xml"})
public Users performLogout(#RequestHeader("AuthenticationID") String authID, HttpServletRequest request) throws DatatypeConfigurationException {
return handleLogout(request, authID);
}
private Users handleLogout(HttpServletRequest request, String authID) throws DatatypeConfigurationException {
LogService.info(this.getClass().getName(), "Received Logout Request");
final UsersXMLBuilder usersXMLBuilder = new UsersXMLBuilder();
Users usersXML = usersXMLBuilder.buildDefaultUsersTemplate();
HttpSession session = request.getSession();
AppUtilities utils = new AppUtilities();
try {
//Checking with RegEX
if (utils.isValidUUID(authToken)) {
//Get User Login Record from DB By the AuthID and Delete It
//Invalidate The Session
session.invalidate();
LogService.info(this.getClass().getName(), "Session Invaliated");
} else {
LogService.info(this.getClass().getName(), "Invalid AuthID Found. Not a Valid UUID");
usersXML.setResponseCode(-5);
usersXML.setResponseText("User Session is Not Valid");
}
} catch (Exception ex) {
LogService.error(this.getClass().getName(), ex);
usersXML.setResponseCode(-4);
usersXML.setResponseText("Error Occured!");
return usersXML;
} finally {
LogService.info(this.getClass().getName(), "LogOut Process Finished");
}
return usersXML;
}
}
Questions
1- Is it possible i can return a XML message when spring gives white label error page when i pass no authentication ID in request.
2- How can i get the Authentication Header and check it for null and give message that AuthID is missing.
3- How can i set a attribute explicitly and check for it in every controller that if it exists or not.
4- I plan to have a table where i can store user login time and give a session 10 mins time and Update it more 10 mins if i get any request from the user with the AuthID. So can i have a class or method which can check any incoming request? so i can detect the AuthID and Update My table.
Thank you for your time and help.
You can use an interceptor for that : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor
The interceptor will run for every request. It can stop the request and do a response itself.
I am working on a web application of my own.Iam using Spring-mvc3 architecture n my application.I want to add authentication to my application.I thought of doing it by sessions but am not able to do so.I have created a login page and after login am able to authenticate and go to next page and get data that i have saved during session creation.Then after that when am navigating to another page my session data that i have saved is getting lost and when iam trying to get the session id am getting a new session id which is different from the one the got created at the time of authentication please check this and provide me the appropriate answer.
#RequestMapping(value = "checkLogin.action")
public String validateLogin(
#ModelAttribute("loginDto") LoginDto loginDetails,
HttpServletRequest request) {
boolean validUser;
try {
validUser = userDao.validateLogin(loginDetails);
if (validUser) {
HttpSession session = request.getSession();
if (session.isNew()) {
logger.debug("New Session is Created");
System.out.println("Session id is" + session.getId());
} else {
logger.debug("Not a New Session");
System.out.println("Session Id" + session.getId());
}
//session.setMaxInactiveInterval(1000);
session.setAttribute("LoginData", loginDetails);
session.setAttribute("loggedUser",true);
return "home";
}
return "redirect:loginPage.action?message=Unable to Login invalid Id/Password";
} catch (DaoException e) {
logger.error("Problem in UserDao");
return "redirect:loginPage.action?message=Unable to Login invalid Id/Password";
} catch (Exception e) {
logger.error("problem validating User Login");
e.printStackTrace();
return "redirect:loginPage.action?message=Unable to Login invalid Id/Password";
}
}
this is how am setting data in my session and am able to retrieve that set attributes in view home to which on success it goes to, from home if i go to another view there am not able to get that data.
I wanted to know using anchor tag for navigating to another page clears the session data??????
I have a home.jsf that invoke a login servlet that look into database and query out the user object given the username and password. Then I save that user object into session under attribute name user, like this request.getSession().setAttribute("user", user);
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
boolean remember = "true".equals(request.getParameter("remember"));
//Hashing the password with SHA-256 algorithms
password = hash(password);
HttpSession s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id: {0}", s.getId());
}
User user = scholarEJB.findUserByUserNamePassword(username, password);
try {
if (user != null) {
request.login(username, password);
request.getSession().setAttribute("user", user);
if (remember) {
String uuid = UUID.randomUUID().toString();
UserCookie uc = new UserCookie(uuid, user.getId());
scholarEJB.persist(uc);
Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);
}else{
//If the user decide they dont want us to remember them
//anymore, delete any cookie associate with this user off
//the table
scholarEJB.deleteUserCookie(user.getId());
Helper.removeCookie(response, Helper.COOKIE_NAME);
}
response.sendRedirect("CentralFeed.jsf");
}else{
response.sendRedirect("LoginError.jsf");
}
} catch (Exception e) {
response.sendRedirect("LoginError.jsf");
}
Then I have a Filer that map to all my secured page, that will try to retrieve the user object from the session, otherwise, redirect me to home.jsf to login again
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id Before: {0}", s.getId());
}
User user = (User) request.getSession().getAttribute("user");
s = request.getSession(false);
if (s != null) {
logger.log(Level.INFO, "Id After: {0}", s.getId());
}
if (user == null) {
String uuid = Helper.getCookieValue(request, Helper.COOKIE_NAME);
if (uuid != null) {
user = scholarEJB.findUserByUUID(uuid);
if (user != null) {
request.getSession().setAttribute("user", user); //Login
Helper.addCookie(response, Helper.COOKIE_NAME, uuid, Helper.COOKIE_AGE);
} else {
Helper.removeCookie(response, Helper.COOKIE_NAME);
}
}
}
if (user == null) {
response.sendRedirect("home.jsf");
} else {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(req, res);
}
Now as you see here, I manipulate some Cookie as well, but that is only happen when I check remember me. So now I am in CentralFeed.jsf, but then any request that I send from here will bring back to home.jsf to login again. I walk through a debugger, so when I first login, the first time I get into the Filter, i successfully retrieve the user object from session by request.getSession().getAttribute("user");. But after that, when I get back in the filter, I no longer the session attribute user anymore. I set session timeout to be 30 min in my web.xml
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
EDIT
Now when I print out the session Id between request, it is fact different session id, but I have no idea why? please help.
EDIT2
#BalusC: I actually did invalidate the session. Back then, you show me how to force a logout when user log in somewhere else (http://stackoverflow.com/questions/2372311/jsf-how-to-invalidate-an-user-session-when-he-logs-twice-with-the-same-credentia). So inside User entity i have this
#Entity
public class User implements Serializable, HttpSessionBindingListener {
#Transient
private static Map<User, HttpSession> logins = new HashMap<User, HttpSession>();
#Override
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = logins.remove(this);
if (session != null) {
session.invalidate(); //This is where I invalidate the session
}
logins.put(this, event.getSession());
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
logins.remove(this);
}
}
In the valueBound method, I did invalidate the session, when I comment it out, everything work. I walk through the debugger, and here is what happen. When I first log in, the LoginServlet catch it. Then the line request.getSession().setAttribute("user", user); invoke the method valueBound. Then the Filter got called, and the line chain.doFilter(req, res); invoke the valueBound method again, this time, session is not null so it get in the if and session.invalidate. I comment the session.invalidate out and it work. But as u might have guess, I cant force a log out when user login somewhere else. Do you see a obvious solution for this BalusC?
The HTTP session is maintained by the JSESSIONID cookie. Ensure that your Helper.COOKIE_NAME doesn't use the same cookie name, it will then override the session cookie.
If that is not the case, then I don't know. I would use Firebug to debug the HTTP request/response headers. In a first HTTP response on a brand new session you should be seeing the Set-Cookie header with the JSESSIONID cookie with the session ID. In all subsequent requests within the same session, you should be seeing the Cookie header with the JSESSIONID cookie with the session ID.
A new session will be created when the Cookie header is absent or contains a JSESSIONID cookie with a (for the server side) non-existing session ID (because it's been invalidated somehow), or when the server has responded with a new Set-Cookie header with a different session ID. This should help you in nailing down the culprit. Is it the server who generated a new session cookie? Or is it the client who didn't send the session cookie back?
If it was the server, then somewhere in the server side the session has been expired/invalidated. Try putting a breakpoint on HttpSession#invalidate() to nail it further down.
If it was the client (which would be very weird however, since it seems to support cookies fine), then try to encode the redirect URL to include the JSESSIONID.
response.sendRedirect(response.encodeRedirectURL(url));
Try with different clients if necessary to exclude the one and other.
look at the JSessionID param in your request. If it changes that means you are losing your session (browser is telling your Server its another session). Dont know why its happening but propably is something you are doing (open another window, change servlet context and come back, change server in some request... etc.).
Please post more information if you confirm that