How to restrict access if user is not logged in - jsf

My project has a template main.xhtml and three views login.xhtml, dashboard.xhtml, new.xhtml. Once I login in login.xhtml, the LoginBean will validate and if successful, then it will take to dashboard.xhtml. If user need to create an new record he click the new button which takes to new.xhtml.
But the problem is, if dashboard.xhtml is requested directly from browser, then it is working without login. Do I need to check every view that the user is logged in? How can I achieve this?

It sounds like as if you're homegrowing authentication. In that case, you need to also homegrow access restriction. That is normally to be done using a servlet filter.
Assuming that you're logging in as follows in a #RequestScoped bean,
public String login() {
User user = userService.find(username, password);
FacesContext context = FacesContext.getCurrentInstance();
if (user != null) {
context.getExternalContext().getSessionMap().put("user", user);
return "dashboard.xhtml?faces-redirect=true";
} else {
context.addMessage(null, new FacesMessage("Unknown login, try again."));
return null;
}
}
Then you can check for the logged-in user in a #WebFilter("/*") filter as follows:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
User user = (session != null) ? session.getAttribute("user") : null;
String loginURL = request.getContextPath() + "/login.xhtml";
boolean loginRequest = request.getRequestURI().startsWith(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);
if (user != null || loginRequest || resourceRequest)) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURL);
}
}
Note thus that this would continue the request when the user is logged in, or when the login page itself is requested directly, or when a JSF resource (CSS/JS/image) is been requested.
If you were using container managed authentication, then the filter would have been unnecessary. See also How to handle authentication/authorization with users in a database?

Related

Prevent page access via URL

Good morning everyone!
I have an application that has access control, it is working ok
But the user can write the URL in the browser and access pages that he does not have access to
Could someone help me solve this?
Below is the implementation of Filter
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filter) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
if (session.getAttribute("sessionUser") != null
|| req.getRequestURI().endsWith("Login.xhtml")) {
System.out.println("if");
filter.doFilter(request, response);
} else {
System.out.println("else");
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath()+"/Login.xhtml");
}
}
Before answer i suggest you to use one security framework to control access of pages. something powerfull like spring security.
But in this case you checked only that user session is validated or not but nothing related to page or page name added to session.
You should add all user accessed page (name for example), to session as attributes after successful login and then in this filter, check what page user requested to access?
If session attributes contains that page dofilter called else redirect to access denied page.

Homegrown authentication, how do I remember and get the logged in user

I made a filter and a authentication in an application JSF it works very well but I'd like get the current user and I have no idea how to do that.
anybody could help me?
This method authenticates
public String Authenticates() {
FacesContext fc = FacesContext.getCurrentInstance();
EntityManager manager = getManager();
PersonDAO dao = new PersonDAOJPA(manager);
if (dao.login(getPerson().getEmail(), getPerson().getPassword())) {
ExternalContext ec = fc.getExternalContext();
HttpSession session = (HttpSession) ec.getSession(false);
session.setAttribute("userLogged", true);
getCurrentUser();
return "/index.xhtml" + "?faces-redirect=true";
} else {
FacesMessage ms = new FacesMessage("Email or Password Incorrect");
ms.setSeverity(FacesMessage.SEVERITY_ERROR);
fc.addMessage(null, ms);
return "/account.xhtml";
}
}
You're basically setting a boolean in session to indicate if an user is logged in or not.
if (userService.login(email, password)) {
session.setAttribute("userLogged", true);
}
This is rather simplistic. This can be improved by simply putting the user itself in the session.
User user = userService.find(email, password);
if (user != null) {
session.setAttribute("user", user);
}
Now, wherever you'd like to check if an user is logged in, instead of checking if userLogged equals true, you just check if user does not equal null.
User user = (User) session.getAttribute("user");
if (user != null) {
// User is logged in.
} else {
// User is not logged in.
}
This immediately solves your problem of getting the "current" user. It's this way already available by #{user}.
<p>Your email is #{user.email}.</p>
Unrelated to the concrete problem, you'd better not grab the raw HttpSession from under JSF's covers in a JSF artifact. That false argument in getSession(false) is also another thinking mistake and prone to NullPointerException later on. Instead, use ExternalContext#getSessionMap().
context.getExternalContext().getSessionMap().put("user", user);

JSF SessionScoped only allow to connect from one account to a web page

I am developing a JSF application where 3 kind of users(1, 2,3) can login using an id and when they login the access to different 3 menus(Menuuser1, Menuuser2, Menuuser2) depending on what kind of users they are. Each time an user logins I store its id in an attibute in a sessionscope attribute.
I want that if an user of type 1 logins and he open another tab in the browser he is redirected to the menuuser1 and cannot login from the same computer as an user of type 2.
How could I do that?
You can perform authentication in filter , you can check the role of the user in filter class, if given role is user1, it will forward the request to the Menuuser1 else if it's the user2 then forward to Menuuser2 and so on ...
Example
public class ControlRole implements Filter{
public void init(FilterConfig arg0) throws ServletException {}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpSession session = request.getSession(false);
User user = (session != null) ? session.getAttribute("user") : null;
if(user.getRole().getName().equals("user1")){
chain.doFilter(req, resp);//sends request to next resource
}
else if(user.getRole().getName().equals("user2")){
// ......
}
else{
oresponse.sendRedirect(request.getContextPath() + "/login");
}
And for "If an user with rol1 logins from its computer, he will not be able to login from the same computer as an user with rol2 while he is loged as user with rol1" this is automatically done by the sessionScope

How to use HttpServletRequest#login() programmatic login with SHA-256 configured security realm

i have read there, i am using glassfish 3.1.1 security realm configured with sha-256 digest algorithm. is there any tutorial about this ? maybe i am blethering, i am trying to login with this code:
public void login() throws NoSuchAlgorithmException {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
EntityManager em = emf.createEntityManager();
boolean committed = false;
try {
FacesMessage msg = null;
EntityTransaction entr = em.getTransaction();
entr.begin();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte byteData[] = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
password = sb.toString();
Query query = em.createQuery("SELECT COUNT(u) FROM EntityUser u WHERE u.userName = :userName AND u.password = :password")
.setParameter("userName", userName).setParameter("password", password);
long result = (long)query.getSingleResult();
if (result == 1) {
request.login(userName, password);
msg = new FacesMessage();
msg.setSeverity(FacesMessage.SEVERITY_INFO);
msg.setSummary("You are logged in");
}
entr.commit();
committed = true;
} catch (ServletException e) {
context.addMessage(null, new FacesMessage("wrong username or password"));
}
finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
}
result variable returns 1, but request.login(userName, password); method in if condition always throws servletexception.
Can you post the exception stacktrace? That way it would be easier to understand the source of the exception. But judging from your currently supplied code, you should supply in
request.login(userName, password);
the password as the plain-text password and not the hashed password.
Interface HttpServletRequest
ServletException - if the configured login mechanism does not support username password
authentication, or if a non-null caller identity had already been established (prior to
the call to login), or if validation of the provided username and password fails.
There can be a lot of reasons that login fails. You've just checked if appropriate user and password are in table. Glassfish makes two queries - in authenticate process - to two tables. One to table specified as userTable, and second to groupTable which are determined in security realm definition. Check if web.xml and glassfish-web.xml are correct too.
the questioned problem is whole about method
request.login(userName, password);
Author made everything right, even his own authentication way of working with users database, but request.login needs for authentication realm be set up, to be used by this method. And you have your own, you dont need separate request.login authentication. For the case you need it - thats how you do it jdbc-realm-setup-with-glassfish-v3
So, after you get the result=1, you set up your context.getExternalContext().getSessionMap().put("user", u);
and send redirection context.getExternalContext().redirect(context.getExternalContext().getRequestContextPath() + "какой-то модуль.xhtml");
and use webfilter to block access to /Pages/*.xhtml without logging in.
#WebFilter("/Pages/*")
public class LoggingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
User user = (User) req.getSession().getAttribute("user");
if(user != null){
chain.doFilter(request,response);
}
else res.sendRedirect(req.getContextPath()+"/запрос_учетных_данных.xhtml");
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}

how to differentiate a new log in (new Session) and a session time out

Could someone let me know how to differentiate a new log in (new Session) and a session time out .
Only on login : user must be authenticated and redirected to a servlet to load user details (on other screnarios user must not be redirected to the servlet)
and on timeout user must be redirected to the timeout page.
To identify a new session (user not logged in):
-- Session attributes cannot be used since the session becomes null on timeout.
-- Setting cookies for session management didnt work.
The cookies are getting removed for the current session
Cookie cookie = new Cookie("activeSession", null);
cookie.setMaxAge(0);
cookie.setPath("/");
cookie.setValue("");
httpServletResponse.addCookie(cookie);
getCookieValue(httpServletRequest , "activeSession"); returns null
public static String getCookieValue(HttpServletRequest request, String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && name.equals(cookie.getName())) {
return cookie.getValue();
}
}
}
return null;
}
After logout or Timeout (session is invalidated) when user logs in and a new session is created.
The cookies that were removed in the previous sessions reappears with the preset values.
getCookieValue(httpServletRequest , "activeSession") returns a value;
If I use the below approach it works for the 1 st login attempt.
After the first login session has timedout ,the filter redirects to timeout page.
The actual problem arises when user accesses the application in the same window after timeout.
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain) throws IOException,
{ if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//Check for a new login
if (httpServletRequest.getSession(false) == null && httpServletRequest.getRequestedSessionId()==null)
{
// Create a new session
httpServletRequest.getSession();
//Redirect to servlet on 1 st login to fetch details from DB
httpRequest.getRequestDispatcher("/loginServlet").forward(request,response);
}else{
//validate active or timedout sessions.
boolean isSessionValid = (httpServletRequest.getRequestedSessionId() != null) && !httpServletRequest.isRequestedSessionIdValid();
if(isSessionValid)
{
httpServletResponse.sendRedirect(getTimeoutPage());
}
}
}
filterChain.doFilter(request, response);
}
Therefore the details are not fetched from DB and the page is not loaded correctly.
Browser:IE 8
Server : Weblogic server
Your cookie approach is unnecessary and technically invalid. A max age of 0 makes it to expire immediately when the response is processed. But anyway, you don't need an additional cookie. The HttpSession is by itself already backed by a cookie and the Servlet API already offers methods to check the one and other. Just store the logged-in user as an attribute of the HttpSession (which can in turn be a session scoped JSF managed bean).
The following example should do, assuming that you've stored the logged-in user as a property of a session scoped JSF managed bean with the managed bean name "auth".
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
Authenticator auth = (Authenticator) req.getSession().getAttribute("auth");
if (req.getRequestedSessionId() != null && !req.isRequestedSessionIdValid()) {
res.sendRedirect(req.getContextPath() + "/timeout.xhtml");
} else if (auth == null || !auth.isLoggedIn()) {
res.sendRedirect(req.getContextPath() + "/login.xhtml");
} else {
chain.doFilter(request, response);
}
}

Resources