PrimeFaces redirect after Glassfish Login - jsf

I am trying to add PrimeFaces to my project. It is running on Glassfish 3 with form-based authentication. I downloaded the jar and put into WEB-INF/lib. After logging in, I was shown a css file with the URL:
localhost:8080/[webapp]/javax.faces.resource/theme.css.jsf?ln=primefaces-aristo
This does not happen if I disable security check. Here is the login part in my web.xml.
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/login.jsf?failed=true</form-error-page>
</form-login-config>
</login-config>
Can anyone tell me what is the problem? Thanks!

This is caused by the restricted pages being cached by the browser.
The container managed security will redirect to the last HTTP request which triggered the authentication check. In your case it's apparently the auto-included PrimeFaces theme CSS file. That can happen if the browser has loaded the to-be-authenticated page fully from the browser cache, while the browser has loaded the CSS file fully from the server side, or have tested the cache validity of the CSS file by a conditional GET request. The container managed security will then remember exactly this URL as redirect-after-successful-login URL.
You'd like to exclude the JSF resources (<h:outputScript>, <h:outputStylesheet> and <h:graphicImage> from authentication checks. You could do that by excluding the common URL pattern /javax.faces.resource/*.
<security-constraint>
<web-resource-collection>
<web-resource-name>Allowed resources</web-resource-name>
<url-pattern>/javax.faces.resource/*</url-pattern>
</web-resource-collection>
<!-- No Auth Contraint! -->
</security-constraint>
You also need to instruct the browser to not cache restricted pages to prevent the browser loading it from the cache (e.g. by pressing back button after logout). Map the following filter on the same URL pattern as the one of your <security-constraint>.
#WebFilter("/secured/*") // Use the same URL pattern as <security-constraint>
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
// ...
}
Note that this also fixes the "back button" problem. So the enduser would also not see the restricted pages anymore when back button is pressed after signout/logout as would happen in your current setup.

You should exclude web resources from validation. Add for example <url-pattern>*.css</url-pattern> in your <security-constraint> element. Do that for all web resources which don't need security checks (js, images, ...).

it seems like you have the wrong url-pattern in your security constraints.
Have a look at this example for a working version.
http://blog.eisele.net/2011/01/jdbc-security-realm-and-form-based.html

Related

JSF: Redirection [duplicate]

I have a JSF page which posts data to an external page.
The data is loaded from a JSF managed bean which generates a unique ID in the post data.
I have an issue where a user clicks on a checkout button then navigates back to the same page and presses the checkout button again. The post data has not updated. Moreover, the bean is not invoked at all. Is there anyway to force JSF to reload the page and the form data?
<form action="#{checkoutBean.externalUrl}" method="post"
id="payForm" name="payForm">
<input type="hidden" value="#{checkoutBean.uniqueID}" />
<input type="submit" value="Proceed to Checkout" />
</form>
That page is likely being loaded from browser cache. This is essentially harmless, but indeed confusing to the enduser, because s/he incorrectly thinks that it's really coming from the server. You can easily confirm this by looking at the HTTP traffic monitor in browser's web developer toolset (press F12 in Chrome/FireFox23+/IE9+ and check "Network" section).
You basically need to tell the browser to not cache (dynamic) JSF pages. This way the browser will actually request the server for the page (and hereby triggering proper creation/initialization of managed beans and so forth) instead of showing the previously requested one from its cache.
Generally, this is to be done with a simple servlet filter like follows:
#WebFilter("/app/*")
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
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);
}
// ...
}
Where /app/* is the example URL pattern on which you'd like to turn off the browser cache. You can if necessary map it on /*, *.xhtml or even on servletNames={"Faces Servlet"}.
If you happen to use JSF utility library OmniFaces, then you can use its builtin CacheControlFilter by just adding the following entry to web.xml (which demonstrates a direct mapping on FacesServlet, meaning that every dynamic JSF page won't be cached):
<filter>
<filter-name>noCache</filter-name>
<filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noCache</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
See also the showcase.
I found a solution that works for JSF without having to create a servlet-filter. Just put the line below to your .xhtml page.
<f:event type="preRenderView" listener="#{facesContext.externalContext.response.setHeader('Cache-Control', 'no-cache, no-store')}" />

Prevent remote access of a web page

Is it possible to prevent remote access of a web page?
Let's say I have my page1 (home page) which is obviously accessible anywhere via its url. Then I have page2 (admin page) which I would only like to be accessible from the machine where my web application is deployed.
This may sound like this kind of scenario. Only, instead of the admin console, page2 should not be accessible remotely.
Please be more precise what are you using?
I assume that you don't use any framework, so you have only serlvets and .jsp pages.
First,put you adminpage.jsp to WEB-INF folder. Content of this folder is not visible out of your application (without your permission).
Second, create filter that will intercept your requests to servlets (Try to use servlets for all requests, don't use direct links to .jsp pages, because this is only way to add some security. These servlets should be like controllers in MVC). To create Filter you need to add class that will implement interface Filter
public MyFilter implements Filter {
...
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain)
throws IOException, ServletException {
if (request.getRemoteAddr.equals("your server address") {
filterChain.doFilter(request,response);
}
}
...
}
You see, if IP address is equal as your server address is, this request will be proceed further. Filter interface has more two methods init() and destroy() and you can leave them blank. To connect your filter with your servlet add to your web.xml following.
<filter>
<filter-name>myFilter</filter-name>
<filter-class>fullPackagePath.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/url-to-the-admin-panel-servlet</url-pattern>
</filter-mapping>
Of course you need to have servlet with url that will forward to the admin.jsp page.

Force JSF to refresh page / view / form when opened via link or back button

I have a JSF page which posts data to an external page.
The data is loaded from a JSF managed bean which generates a unique ID in the post data.
I have an issue where a user clicks on a checkout button then navigates back to the same page and presses the checkout button again. The post data has not updated. Moreover, the bean is not invoked at all. Is there anyway to force JSF to reload the page and the form data?
<form action="#{checkoutBean.externalUrl}" method="post"
id="payForm" name="payForm">
<input type="hidden" value="#{checkoutBean.uniqueID}" />
<input type="submit" value="Proceed to Checkout" />
</form>
That page is likely being loaded from browser cache. This is essentially harmless, but indeed confusing to the enduser, because s/he incorrectly thinks that it's really coming from the server. You can easily confirm this by looking at the HTTP traffic monitor in browser's web developer toolset (press F12 in Chrome/FireFox23+/IE9+ and check "Network" section).
You basically need to tell the browser to not cache (dynamic) JSF pages. This way the browser will actually request the server for the page (and hereby triggering proper creation/initialization of managed beans and so forth) instead of showing the previously requested one from its cache.
Generally, this is to be done with a simple servlet filter like follows:
#WebFilter("/app/*")
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
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);
}
// ...
}
Where /app/* is the example URL pattern on which you'd like to turn off the browser cache. You can if necessary map it on /*, *.xhtml or even on servletNames={"Faces Servlet"}.
If you happen to use JSF utility library OmniFaces, then you can use its builtin CacheControlFilter by just adding the following entry to web.xml (which demonstrates a direct mapping on FacesServlet, meaning that every dynamic JSF page won't be cached):
<filter>
<filter-name>noCache</filter-name>
<filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noCache</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
See also the showcase.
I found a solution that works for JSF without having to create a servlet-filter. Just put the line below to your .xhtml page.
<f:event type="preRenderView" listener="#{facesContext.externalContext.response.setHeader('Cache-Control', 'no-cache, no-store')}" />

Request scope backing bean... not in request

I have a backing bean (say MyPageBean) with request scope, but it seems to be in session because, navigating my application, when I visit the page myPage, I always get the same instance.
I'm using JSF 1.2, IceFaces 1.8.2 and JBoss 5.1.0
Isn't it just your webbrowser or proxy which is aggressively caching the webpages?
Create a Filter which does the following in doFilter() method to instruct the client to not cache the HTTP response:
HttpServletResponse hsr = (HttpServletResponse) response;
hsr.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
hsr.setHeader("Pragma", "no-cache"); // HTTP 1.0.
hsr.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(request, response);
and map it in web.xml like follows:
<filter>
<filter-name>cacheFilter</filter-name>
<filter-class>com.example.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cacheFilter</filter-name>
<servlet-name>facesServlet</servlet-name>
</filter-mapping>
assuming that you've mapped the FacesServlet instance on <servlet-name> of facesServlet.
In ICEFaces request scope extends across partial submits. So if your application never refreshes the whole page, and uses only partial submits, you may encounter this.
Not using partial submit in the navigation should solve your problem.

JSF application giving 404 for a sub-context

I am working on a web application which uses JSF. I have a folder called 'admin' under 'web' and I have couple of jsp pages under folder 'admin'. I can access jsp pages under 'web' but when I try to access the pages under 'admin' I get '404-Requested resource cannot be found'
The 'context.xml' for my application is something like this:
<Context antiJARLocking="true" path="/MyApp"/>
This thing works on my local tomcat but when I deploy this to my web hosting providers tomcat I have above mentioned problem.
What exactly I need to do to fix this problem.
Here is server.xml for my application on the Hosting provides tomcat:
<Host name="myapp.com" appBase="/home/myapp/public_html">
<Alias>www.myapp.com</Alias>
<Context path="" reloadable="true" docBase="/home/myapp/public_html" debug="1"/>
<Context path="/manager" debug="0" privileged="true"
docBase="/usr/local/jakarta/tomcat/server/webapps/manager">
</Context>
</Host>
Or do I need to add URL-Mapping to my web.xml?
I have following servlet filter in the web.xml for '/admin/*' url-pattern
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>com.myapp.SecurityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
And the filter code is as follows:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
lgMgr.logDebug("doFilter() is called...");
String validuser = null;
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(true);
//If authorization key not in session, redirect to login page.
validuser = (String) session.getAttribute(Common.AUTH_USER);
if(validuser != null) {
lgMgr.logDebug("doFilter(): User is allowed to access the page...");
//If the user is allowed access to the URI, let the flow proceed as normal
chain.doFilter(request, response);
return;
} else {
lgMgr.logDebug("doFilter(): User is not allowed to access the page, redirecting user login...");
//User not allowed access - redirect to login page
res.sendRedirect(req.getContextPath() + "/AdmLogin.jsf");
return;
}
}
Files in /WEB-INF are not public accessible. I have no idea why it works locally, but this violates the servlet specification. Also, JSF cannot forward views to JSP pages in /WEB-INF folder, they should be placed in public webcontent (one folder level up above /WEB-INF folder).

Resources