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.
Related
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
I have a booking page with URL /booking/Create.jsf. I have a filter for URL pattern /booking/* so the user is asked to login on the page /login/signin.jsf before being taken to Create.jsf. But I have a button "Continue as guest" so that user that is not registered can create a booking on Create.jsf page without log-in. How can I make that happen. Any help will be appreciated. My filter looks like
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
UserLoginController loginController = (UserLoginController) req.getSession().getAttribute("userLoginController");
if(loginController != null && loginController.isLoggedIn()){
chain.doFilter(request, response);
}
else{
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.sendRedirect(req.getContextPath() + "/login/signin.jsf");
}
}
The page create.jsf is considered in the end as public page. So, in order to enable the filter for other pages concerning "booking", just create a new subfolder named for example "user" inside which you should put others pages of "booking", the new url pattern of the filter will be as a result: /booking/user/*. This way, the other stuff of booking remains safe and the page /booking/create.jsf will be easily available for the users and guests because it's not covered by the filter.
So I've come accross quite a numbre of questions similar to mine, and I was starting to get it until I realised I don't, in short, here's the story :
In an authentification bean, success of authentification should result in accessing some web resources, failure should "filter" access and redirect to current login page.
Now, in that authentification bean, I added this line in case of success :
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, "true") ;
AUTH_STATE is defined in the bean as :
public static final String AUTH_STATE = "";
In case of failure, I do the following :
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(authentificationBean1.AUTH_STATE, null) ;
Now in the filter (one that is applied to every file except of authentification page), my doFilter method looks like this :
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) == null) {
((HttpServletResponse) response).sendRedirect("authentification.xhtml");
}
if(((HttpServletRequest) request).getSession().getAttribute(authentificationBean1.AUTH_STATE) != null) {
((HttpServletResponse) response).sendRedirect("accueil.xhtml");
}
}
My idea was that if authentification went well, the authentificationBean1.AUTH_STATE session attribut will be set to something not null, thus in the filter test I'll be able to redirect to a welcom page (accueil.xhtml) ; if that attribut is null, we'll stay in the authentification page.
Tasting the whole thing : the filter seems to work but too much, by that I mean even when authentification test must succeed it doesn't allow me to pass to the welcome page. It was actually working fine without the filter, it looks like I missed something about using filters with JSF or filters as it.
P.S : didn't apply chain.doFilter because I do not have another filter to call, but suspecting something there.
Thanks for your indications.
EDIT :
<filter>
<filter-name>RestrictionFilter</filter-name>
<filter-class>beans.RestrictionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestrictionFilter</filter-name>
<url-pattern>/faces/accueil.xhtml</url-pattern>
</filter-mapping>
Your filter is running in an infinite loop, redirecting to itself everytime. It is never continuing the request to the servlet. It seems that you're misunderstood how HTTP works. With response.sendRedirect() you're basically firing a brand new HTTP request. This brand new HTTP request will invoke the filter again. So, when your filter matches the condition in order to redirect to accueil.xhtml, it will keep redirecting to that page in an infinite loop and never continue to the servlet in order to process the request.
Further you also misunderstood the meaning of chain.doFilter(). It does not explicitly advance to the next filter. It just continues the request as if there was no filter. Whether there's another filter next in the chain or not is completely irrelevant. If there's no filter, then it will just end up in the target servlet (which is the FacesServlet in your case, who's responsible for processing the JSF page).
Basically, the flow should be as follows:
If the user is not logged in, then:
If the currently requested page is not authentification.xhtml, then redirect to it.
Or if the currently requested page is already authentification.xhtml, then continue request.
Or if the user is logged in, then continue the request regardless of the requested page.
In other words, this should do it:
#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);
String loginURL = request.getContextPath() + "/authentification.xhtml";
boolean loggedIn = session != null && session.getAttribute(authentificationBean1.AUTH_STATE) != null;
boolean loginRequest = request.getRequestURI().startsWith(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest)) {
chain.doFilter(request, response);
} else {
response.sendRedirect(loginURL);
}
}
Note that I also added a check on JSF resources (the CSS/JS/image files included via <h:outputStylesheet|outputScript|graphicImage>), otherwise they would also be blocked when the login page is presented. Also note that this filter can be mapped on /* and not on only a single page.
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?
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);
}
}