Jmeter + JSF can't pass login filter - jsf

I got a problem when use Jmeter to test a JSF application.
I'm a newbie in Jmeter, follow some post on net i did
And code filter
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession httpSession = httpRequest.getSession(false);
if (!httpRequest.getRequestURI().startsWith(httpRequest.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpResponse.setDateHeader("Expires", 0); // Proxies.
}
String strRequestURI = httpRequest.getRequestURI();
// httpRequest.getServletPath()
// httpRequest.getServerName()
if (strRequestURI.indexOf("/public/") >= 0)
chain.doFilter(request, response);
else if ( (strRequestURI.indexOf("/login.xhtml") >= 0)
|| strRequestURI.contains("javax.faces.resource")
|| (strRequestURI.indexOf("/admin-access-denied.xhtml") >= 0)) {
chain.doFilter(request, response);
} else if ((httpSession != null) && (httpSession.getAttribute(SessionBean.SESSION_KEY) != null)) {
if (strRequestURI.indexOf("/lazy-load.xhtml") >= 0) {
chain.doFilter(request, response);
} else {
chain.doFilter(request, response);
}
} else {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.xhtml");
}
} catch (Exception e) {
e.printStackTrace();
}
I did all things that i read : add Coockie Manager, add Regular Expression Extrator, add parameter to Http request but after run test, my response data is blank ( only access to login.xhtml page )
But response is blank , only login page is showed .
Pls help me to solve this problem.
PS: I run debug mode and httpSession.getAttribute(SessionBean.SESSION_KEY) is always null , its set on login controller ( when login successed ).
HttpSession session = SessionBean.getSession();
session.setAttribute(SessionBean.SESSION_KEY, sessionData);
Thanks a lot,

Most likely your javax.faces.Viewstate value is not propertly correlated, you're sending ${viewstate} instead of the extracted value, most likely your Regular Expression fails somewhere
It's better to put PostProcessors as children of the specific Samplers, otherwise they are being triggered on each sampler causing execution overhead and in some cases JMeter Variables data loss
So your test should have the following structure:
lazy-load.xhtml
Extract Viewstate
login.xhtml
You may want to consider using CSS/JQuery Extractor or XPath Extractor instead of Regular Expressions Extractor as Regular Expressions are fragile, sensitive to markup change and complex ones can hardly be understood and maintained.
Example expressions:
XPath: //input[#id='javax.faces.ViewState]/#value
CSS:
- Expression: input[id=javax.faces.ViewState]
- Attribute: value

Related

JSF, session timeout handling [duplicate]

This question already has answers here:
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
(2 answers)
Closed 4 years ago.
I have configured my session timeout in the server and have added a filter to handle session timeout. But when I am trying to redirect it back to the login page its not working. I searched the net but not getting anything solid. I am using jsf.. my code
public class SessionTimeoutFilter implements Filter {
private String timeoutPage = "login.seam";
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain filterChain) throws IOException,ServletException {
if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse))
{
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if (isSessionControlRequiredForThisResource(httpServletRequest)) {
if (isSessionInvalid(httpServletRequest))
{
String timeoutUrl = httpServletRequest.getContextPath()
+ "/" + getTimeoutPage();
System.out.println("Session is invalid! redirecting to timeoutpage : " + timeoutUrl);
httpServletResponse.sendRedirect(timeoutUrl);
return;
}
}
}
filterChain.doFilter(request, response);
}
Can anyone tell me what am i doing wrong... why is sendredirect not responding
Maybe this solution will be proper for your needs:
How to redirect to index page if session time out happened in jsf application
if you need perform some action on session timeout you can also create #Destory annotated method on session statefull bean.

Homegrown authentication filter does not show the welcome page

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.

JSF page style missing when using login filter

I am using following filter to control access to all pages in JSF 2.0 using GlassFish as application server. The problem is that with this code although filter works fine and user are redirected to log.xhtml if they try to acess anyother page directly but the login.xhtml does not look good (no colored image displayed and while page shape changed) as it should be. However if i remove the sendRedirect statement and replace it with chain.doFilter statement, then the page displays in the same way as it should be looking nice and good however filtering does not work obviously. How can I fix this problem?
LoggingFilter.java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
LoginBean auth = (LoginBean) req.getSession().getAttribute("loginBean");
if ((auth != null && auth.isLoggedIn()) || req.getRequestURI().endsWith("/login.xhtml")) {
// User is logged in, so just continue request.
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpResponse.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
} else {
// User is not logged in, so redirect to index.
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath() + "/faces/login.xhtml");
//FacesContext.getCurrentInstance().getExternalContext().dispatch("/login.xhtml");
//chain.doFilter(request, response);
}
}
This filter also redirects all requests on CSS/JS/image files to the login page. The browser end up getting a response containing some HTML code representing the login page instead of the concrete CSS/JS/image content it requested for and hence the browser fails applying the necessary look'n'feel.
Provided that you're 100% utilizing JSF resource management (<h:outputStylesheet>, etc) and thus they are all covered by /javax.faces.resource/* URIs, rewrite your 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);
LoginBean auth = (session != null) ? session.getAttribute("loginBean") : null;
String loginURL = request.getContextPath() + "/faces/login.xhtml";
boolean loggedIn = auth != null && auth.isLoggedIn();
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + "/faces" + ResourceHandler.RESOURCE_IDENTIFIER);
if (loggedIn || loginRequest || resourceRequest)) {
if (!resourceRequest) {
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(request, response);
} else {
response.sendRedirect(loginURL);
}
}
Note that no-cache headers should not be set on resource requests, otherwise you defeat the benefit of the browser cache on CSS/JS/image files.

After logout, all restricted pages are still available in browser history, how to prevent that?

Here is my logout method:
public String logout() throws IOException, ServletException
{
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext ec = context.getExternalContext();
HttpSession session = (HttpSession) ec.getSession(false);
HttpServletResponse response = (HttpServletResponse) ec.getResponse();
final HttpServletRequest request = (HttpServletRequest)ec.getRequest();
session.invalidate();
Cookie[] cookies = request.getCookies();
Cookie opentoken = null;
for(Cookie c : cookies){
if (c.getName().equals("opentoken")){
if (session != null){
opentoken = c;
opentoken.setMaxAge(0);
opentoken.setValue("");
response.addCookie(opentoken);
response.sendRedirect(request.getContextPath());
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setHeader("Cache-Control", "must-revalidate");
response.setHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT");//past date
}
break;
}
}
context.getExternalContext().getSessionMap().remove("#{LogoutBean}");
return "login.xhtml?faces-redirect=false";
}
After calling this method, the navigation in browser history is still working. How can I solve this?
When you set response headers, it applies on the current response only, not on all previous responses (the restricted pages) or future responses (the redirect(!) and thereafter). You actually want to turn off the browser cache on all responses of the restricted requests. And indeed, as you guessed in your comment, you should be using a servlet filter for this.
Another problem is that when you call response.setHeader(), you're basically overridding any previously set header. You don't want to do that, the must-revalidate has totally no effect if no-cache and no-store are absent. You need to set the values commaseparated as a single header, or to use response.addHeader().
All with all, you should have a class like this in your webapp:
#WebFilter("/app/*")
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
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);
}
// ... (just implement init() and destroy() with empty bodies).
}
This example assumes that all restricted pages are available behind the /app/* URL pattern. If yours is different, e.g. /secured/*, /user/*, /admin/*, etc, then you need to alter the URL pattern in the #WebFilter accordingly.
Once done that, your logout() can then be simplified as follows:
public String logout() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.invalidateSession();
if (ec.getRequestCookieMap().get("opentoken") != null) {
ec.addResponseCookie("opentoken", null, Collections.<String, Object>singletonMap("maxAge", 0));
}
return "login.xhtml?faces-redirect=true";
}

JSF Filter skip some files

I have a project with this structure (I can't change it):
Web Pages
META-INF
WEB-INF
assets (javascript, css and images)
includes (top.xhtml, bottom.xhtml, etc)
templates (master.xhtml)
views
fornecedor
-home.xhtml
-user.xhtml
-login.xhtml
franqueador
-home.xhtml
-user.xhtml
-login.xhtml
O have a login.xhtml for each folder for a reason, I can't change it, it was passed by the project manager.
This is my SessionFilter:
#WebFilter("/views/*")
public class SessionFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
LoginController loginController = (LoginController) ((boolean) (session != null) ? session.getAttribute("loginController") : null);
if (!request.getRequestURI().endsWith("/fornecedor/index.xhtml")) {
if (loginController == null || !loginController.getIsLoggedIn()) {
response.sendRedirect(request.getContextPath()
+ "/views/index.xhtml");
} else {
chain.doFilter(req, res);
}
}
}
}
And it doesn't work, returns a blank page with no html code and when I change the .xhtml to .html, it gives me a redirect loop.
I need to avoid all my login.xhtml pages and the index.xhtml on views folder. I have debugged the if on my filter but it always returns false.
EDIT
Following BalusC answer I came to this:
if (!request.getRequestURI().endsWith("/views/index.html")
&& !request.getRequestURI().endsWith("/views/fornecedor/login.html")
&& !request.getRequestURI().endsWith("/views/franqueado/login.html")
&& (loginController == null || !loginController.getIsLoggedIn())) {
response.sendRedirect(request.getContextPath() + "/views/index.html");
} else {
chain.doFilter(req, res);
}
It is working but there is another problem, if I have 10 folder, I'll need to add them on this if statement...I need to make it automatic.
Your first if condition has no else. That explains the blank page.
You need to evaluate the URL and logged-in conditions in a single if instead.
if (!request.getRequestURI().endsWith("/fornecedor/index.xhtml") && (loginController == null || !loginController.getIsLoggedIn()) {
response.sendRedirect(request.getContextPath() + "/views/index.xhtml");
} else {
chain.doFilter(req, res);
}
As to the redirect loop, that's because your FacesServlet is mapped on an URL pattern of *.html instead of *.xhtml for some unclear reason. So the request URL does never match. Fix the URLs in the filter accordingly. To generalize it for all login.html and index.html requests, just do as follows:
if (!request.getRequestURI().endsWith("/index.html")
&& !request.getRequestURI().endsWith("/login.html")
&& (loginController == null || !loginController.getIsLoggedIn())
{
response.sendRedirect(request.getContextPath() + "/views/index.html");
} else {
chain.doFilter(req, res);
}

Resources