PrettyFaces, Filter, and url-pattern issue - jsf-2

I'm working on a Java EE (which I'm fairly new to) web application (JSF, JPA, EJB), and am in the process of incorporating PrettyFaces for human readable/bookmarkable URLs. I've been using a Filter for 2 reasons.
to make sure a user is logged in.
to wrap the call to filterChain.doFilter(...) in a transaction so JPA lazy loading works when generating views (for example, I can just set a Department object in the backing bean, and use #{backingBean.department.employees} to get the associated list of employees in the .xhmtl file).
Before incorporating PrettyFaces, I was using a url-pattern (in web.xml) of *.xhmtl (although the filter doesn't really need to run for the login page) for the Filter. With PrettyFaces, trying to specify a url-pattern for Filters seems to be a bit of a problem, mainly due to the lack of flexibility of the url-pattern rules (lack of support for regular expressions). Is there another way of accomplishing what I need with-out using Filters (and without having to duplicate code)?
Also, I know I can add a static portion to the beginning of the URL (like, /dept/#{deptName}/... and then use a Filter with a url-pattern of /dept/*, but I was hoping to just start with something like /#{deptName}/... (and using a url-pattern of /* runs the filter on everything, including images, javascript, css, etc.)
Basically, the filter has a transaction injected...
#Resource UserTransaction tx;
And does something like this.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
HttpSession session = httpReq.getSession();
User currentUser = (User)session.getAttribute("userInSession");
if (currentUser == null) {
httpRes.sendRedirect("...") //redirect to LoginServlet
} else {
try {
tx.begin();
chain.doFilter(httpReq, httpRes);
}
catch (Exception e) { }
finally {
try {
tx.commit();
}
catch (Exception e) { }
}
}
I have a managed bean that is like this...
#ManagedBean
#RequestScoped
#URLMapping(
id="uutSerialNumber",
pattern="/#{uutSerialNumberController.programId}/uut/#{uutSerialNumberController.uutId}",
viewId="/uutSerialNumber.xhtml"
)
public class UutSerialNumberController {
#EJB private ProgramServiceBean programServiceBean;
#EJB private UutServiceBean uutServiceBean;
private Integer programId;
private Integer uutId;
private Program program;
private Uut uut;
#URLAction
public String loadData() {
program = programServiceBean.findByProgramId(programId);
uut = uutServiceBean.findUutByUutId(uutId);
return null;
}
//other stuff, setters/getters
}
In the view uutSerialNumber.xhmtl, I do something like this (which requires lazy-loading, unless I want to go to the trouble of manually pre-fetching collections in my uutServiceBean.findUutByUutId())...
<ul>
<c:forEach var="serialNumber item="#{uut.serialNumbers}>
<li>#{serialNumber.description}</li>
</c:forEach>
</ul>

Turns out I didn't have PrettyFaces configured correctly (doh!). It was a little confusing because in the PrettyFaces Reference Guide, it says that you don't need to edit web.xml if using Servlet 3.0 (which I am). But, doing the following solved my problem.
<!-- PrettyFaces Filter -->
<filter>
<filter-name>Pretty Filter</filter-name>
<filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
</filter>
<!-- My own view Filter -->
<filter>
<filter-name>View Filter</filter-name>
<filter-class>com.jasoni.ViewFilter</filter-class>
</filter>
<!-- mappings -->
<filter-mapping>
<filter-name>Pretty Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>View Filter</filter-name>
<url-pattern>*.xhtml</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
With this, I'm able to run a filter on my views and use a Transaction View Pattern (similar to the one mentioned in Pro JPA 2, except using a Filter instead of a Serlvet, so lazy loading works with JPA), and also check that the user has a session going.

I cant see how using PrettyFaces may affect your filter - you can always get PrettyContext from HttpServletRequest and get all you need for processing url's, including regular expressions. As for JPA and lazy loading - this is quite a different story, I'd suggest to be more specific in this area and provide more details, code snippets, etc for us to be able to help.

Related

Check if a servlet filter is registered

In JSF, is there anyway to check whether a filter is registered for an application? I have some functionality that requires a filter exists, and I'd like to produce better error messages to explain that the filter does not exist and the functionality will be disabled. Basically, given a theoretical filter:
<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>com.example.SomeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
I'd like some way of checking .isRegistered("com.example.SomeFilter").
I'd considered printing out the stack-trace and checking if the filter class exists there, but that seems like a hacky solution.
You can get access to the FilterRegistration from the ServletContext.
ServletContext ctx = (ServletContext)FacesContext.getCurrentInstance()
.getExternalContext().getContext();
if(ctx.getFilterRegistration("SomeFilter") != null){
...
}

OAuth2ClientContext (spring-security-oauth2) not persisted in Redis when using spring-session and spring-cloud-security

Thanks a lot in advance for reading this question.
Setup
I am using:
spring-security-oauth2:2.0.7.RELEASE
spring-cloud-security:1.0.1.RELEASE
spring-session:1.0.1.RELEASE
and would have a question regarding the persistence of spring-security-oauth2 OAuth2ClientContext in a Redis datastore when using spring-session (via #EnableRedisHttpSession) in a Single-Sign-On (#EnableOAuth2Sso), reverse proxy (#EnableZuulProxy) gateway.
Problem
It seems to me that the SessionScoped JdkDynamicAopProxied DefaultOAuth2ClientContext created in org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration is not correctly persisted in the Redis datastore.
#Configuration
#ConditionalOnBean(OAuth2SsoConfiguration.class)
#ConditionalOnWebApplication
protected abstract static class SessionScopedConfiguration extends BaseConfiguration {
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(accessTokenRequest);
}
}
Debugging the creation of the oauth2ClientContext without #EnableRedisHttpSession shows that (as expected) the bean will be instantiated once per client session and stored in the HttpSession. This instance will then be reused to store the fetched OAuth2 bearerToken details in addition to storing the OAuth2 accessToken in Spring SecurityContext's org.springframework.security.core.Authentication.
However, once using #EnableRedisHttpSession, the oauth2ClientContext bean will be first created on the session creation but also later on (while still using the same client session). Debugging the Redis client session content confirms that oauth2ClientContext is not correctly being persisted by session creation:
Before we retrieve the OAuth2 bearerToken (NO SpringContext, NO scopedTarget.oauth2ClientContext):
~$ redis-cli hkeys "spring:session:sessions:17c5e80b-390c-4fd6-b5f9-a6f225dbe8ea"
1) "maxInactiveInterval"
2) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
3) "lastAccessedTime"
4) "creationTime"
5) "sessionAttr:SPRING_SECURITY_SAVED_REQUEST"
After we retrieved the OAuth2 bearerToken (SpringContext persisted, but NO scopedTarget.oauth2ClientContext):
~$ redis-cli hkeys "spring:session:sessions:844ca2c4-ef2f-43eb-b867-ca6b88025c8b"
1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
2) "lastAccessedTime"
3) "creationTime"
4) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
5) "sessionAttr:SPRING_SECURITY_CONTEXT"
6) "maxInactiveInterval"
If we now try to access one of the configurer Zuul's routes (therefore requiring to call org.springframework.security.oauth2.client.DefaultOAuth2ClientContext#getAccessToken), another instance of oauth2ClientContext will be created (since not persisted in Redis, with a null AccessToken.
Funnily enough, this instance will later be persisted in Redis (but a null instance is persisted since the AccessToken is not re-asked for):
~$ redis-cli hkeys "spring:session:sessions:c7120835-6709-4c03-8d2c-98f830ed6104"
1) "sessionAttr:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"
2) "sessionAttr:SPRING_SECURITY_LAST_EXCEPTION"
3) "sessionAttr:scopedTarget.oauth2ClientContext"
4) "sessionAttr:SPRING_SECURITY_CONTEXT"
5) "maxInactiveInterval"
6) "creationTime"
7) "lastAccessedTime"
8) "sessionAttr:org.springframework.web.context.request.ServletRequestAttributes.DESTRUCTION_CALLBACK.scopedTarget.oauth2ClientContext"
Creating a Simple ScopedProxyMode.TARGET_CLASS Injected bean worked as expected however with the bean being persisted correctly in Redis.
public class HelloWorldService implements Serializable {
public HelloWorldService(){
System.out.println("HelloWorldService created");
}
private String name = "World";
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getHelloMessage() {
return "Hello " + this.name;
}
}
#Configuration
public class AppConfig {
private SecureRandom random = new SecureRandom();
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloWorldService myHelloService(){
HelloWorldService s = new HelloWorldService();
String name = new BigInteger(130, random).toString(32);
System.out.println("name = " + name);
s.setName(name);
System.out.println("Resource HelloWorldService created = " + s);
return s;
}
}
Example
The described problem can be reproduced in #dave-syer example for an OAuth2 reverse proxy gateway by adding the following dependencies:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
as well as the #EnableRedisHttpSession annotation in UiApplication.
Question
Should we ignore org.springframework.cloud.security.oauth2.client.OAuth2ClientAutoConfiguration from AutoConfiguration and manually create a oauth2ClientContext with a different setup to enable spring-session persistence in Redis? If so, can you please provide an example?
Otherwise: how to persist oauth2ClientContext in Redis?
Many in advance to anyone reading this question an trying to help.
There's a known issue there (https://github.com/spring-projects/spring-session/issues/129 and https://github.com/spring-projects/spring-boot/issues/2637). You can work around it by adding a RequestContextFilter.
#dave-syer hint was correct.
I post here the configuration which can be used to setup the RequestContextFilter and enable spring-session persistence of spring-security-oauth objects. In case this can help someone...
#Configuration
public class RequestContextFilterConfiguration {
#Bean
#ConditionalOnMissingBean(RequestContextFilter.class)
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
#Bean
public FilterRegistrationBean requestContextFilterChainRegistration(
#Qualifier("requestContextFilter") Filter securityFilter) {
FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
registration.setOrder(SessionRepositoryFilter.DEFAULT_ORDER + 1);
registration.setName("requestContextFilter");
return registration;
}
}
I came across this post and I have the exact same issue with some minor differences:
my application is not a Spring Boot application
I use JDBC persistence instead of Redis
However, and this might save some hours of future readers, the above solution also worked for me. Since I'm not using Spring Boot, I'll publish the solution here to be applied in a non Spring Boot application using web.xml configuration.
The "trick" is to define in the web.xml the RequestContextFilter. As far as my testing goes I have not seen any border effects of having both the request context filter living aside the request context listener.
What is important is the ordering of the filters. You need to define the filters in this order in your web.xml:
session repository filter
request context filter
security filter
So something like:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
If this helps you save a few hours of digging into Stackoverflow and other web sites, it makes my day.

Restrict access to java-melody monitoring url

Is there a way I can restrict access to /monitoring url generated by Java-Melody plugin in Grails using Shiro roles?
Update: a little bit more details. It's no problem so secure most Grails ressources with shiro. But in case of the java melody plugin, it seems that the melody filter is executed before the shiro filter gets executed. This renders shiro useless.
There are some solutions which say that this might be fixed through a change in the web.xml, but this is not a quick hit and I (rdmueller) didn't manage to make it work yet. The web.xml plugin also seems to promise some help, but I don't want to add another plugin just to secure one plugin.
Some older statements found on the web state that this problem should be already solved through the usage of the loadAfter list in this file: https://github.com/javamelody/grails-melody-plugin/blob/master/GrailsMelodyGrailsPlugin.groovy - but it seems that this only worked for older versions of Grails.
Update2: In order to make it easier to propose a solution, I've create a Grails 2.2.4 sample: https://github.com/rdmueller/SO30739581
just clone the project, do a grailsw run-app and navigate to
http://localhost:8080/SO30739581/dbdoc
and you'll get a login screen via shiro. Navigate to
http://localhost:8080/SO30739581/monitoring
and you'll get the melody screen without being logged in :-(
I ended up doing so by making changes to web.xml for HTTP authentication. Add this to you web.config file.
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Monitoring</realm-name>
</login-config>
<security-role>
<role-name>monitoring</role-name>
</security-role>
<security-constraint>
<web-resource-collection>
<web-resource-name>Monitoring</web-resource-name>
<url-pattern>/monitoring</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>monitoring</role-name>
</auth-constraint>
</security-constraint>
Then add a user and role to your tomcat-users.xml
<user username="yourusername" password="yourpassword" roles="monitoring"/>
I assume you're using Grails 2.x, you could hardcode it this way :
<!-- language: java-->
// grails-app/conf/MonitoringFilters.groovy
import org.apache.shiro.SecurityUtils
class MonitoringFilters {
def dependsOn = [ShiroSecurityFilters]
def filters = {
myMonitoringArea(uri: "/monitoring") {
before = {
SecurityUtils.subject.hasRole('ADMIN')
}
}
}
}
This is not a "quick hit", but the following approach should work with Shiro or whatever security framework your Grails app uses.
In web.xml, add the following elements above any existing <filter> elements:
<filter>
<filter-name>melodyFilter</filter-name>
<filter-class>com.your.package.MelodyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>melodyFilter</filter-name>
<url-pattern>/monitoring/*</url-pattern>
</filter-mapping>
This will call com.your.package.MelodyFilter any time the /monitoring/* url pattern is invoked.
Next, you'll need to create a MelodyFilter Java class in /src/java/com/your/package/MelodyFilter.java.
In the body of the doFilter method, you may call a Grails service method to perform any desired security checks, as follows:
package com.your.package;
import com.my.grails.app.MyService;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class MelodyFilter implements Filter {
#Override
public void destroy() { }
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String uri = ((HttpServletRequest)request).getRequestURI();
HttpSession session = ((HttpServletRequest)request).getSession(false);
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
// replace MyService with your actual service
MyService myService = (MyService)ctx.getBean("myService");
// replace isUserAuthorized with your actual service method;
// session and uri params included to demonstrate how to pass them
// your argument list can be whatever your service method requires
boolean authorized = myService.isUserAuthorized(session, uri);
if (authorized) { chain.doFilter(request,response); }
else {
request.setAttribute("error", "User is not authorized to access " + uri);
request.getRequestDispatcher("/someController/someAction").forward(request, response);
}
}
#Override
public void init(FilterConfig filterConfig) throws ServletException { }
}
Then simply implement myService.isUserAuthorized() to perform whatever security checks you desire.
I have verified this technique works in Grails-2.3.6 with grails-melody:1.59.0
Just to list all available options:
the shiro-protect-any - plugin seems to work, but IMHO, it seems to be to be a bit too complicated and the plugin is "not fully tested" (says the author)...

Create a listener for all pages

I have to use some listener class to listen all pages. According to the url, I must split it and get some informations.
For example :
x.domain.com/$member
I want to get the member name through url, get the following bean and retrieve some database informations.
So, I created a PhaseListener to do the job, but it is not called every times I needed it, for example in case of 404 error.
How can I proceed ?
Thanks a lot :)
PS : I am using Glassfish 4.1.
Use a servlet filter which is mapped on both normal and error page requests:
<filter-mapping>
<filter-name>yourFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Inside the filter, you can then check by the presence of a request attribute keyed with RequestDispatcher#ERROR_REQUEST_URI if it was being triggered on an error page or not.
String errorRequestURI = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
if (errorRequestURI != null) {
// Error page was triggered on the given URI.
}

Getting 'Cannot set header. Response already committed' with Primefaces fileupload

I am using jsf 2 (javax.faces-2.0.10.jar) and Primefaces 3.5 on Websphere 8.5.0.1 and I am also using the file upload jars:
commons-fileupload-1.3.1.jar
commons-io-2.4.jar
and I am trying to use Primefaces fileupload component as follows:
<h:form id="frm" enctype="multipart/form-data">
<p:fileUpload id="fileUpload" value="#{uploadDocument.file}"
fileUploadListener="#{uploadDocument.handleFileUpload}" mode="advanced" dragDropSupport="false"
sizeLimit="10000000" fileLimit="3" />
</h:form>
web.xml config:
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
<init-param>
<param-name>uploadDirectory</param-name>
<param-value>C:/uploadFolder</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
After choosing the file and clicking upload, the file is not uploaded and I am getting following warning in log file:
com.ibm.ws.webcontainer.srt.SRTServletResponse addHeader SRVE8094W: WARNING: Cannot set header. Response already committed.
Why is the file upload not working?
Obviously your response has been committed before the line throwing the exception. I've not seen the specific example you've got there, but the problem is quite common and there is a generic way to track these down. Something is being written to your response before you expected it to be, but the stacktrace you see is for a later event trying to add to that response. So, the solution is to record a stacktrace when the response is committed, and then at the later point when the exception is thrown, print this first stacktrace as well.
I don't have the code I used to use to do this to hand, as I wrote it for a previous company. I've put an outline solution below, that shows the gist of it-you need to wrap the response, and any servletoutputstream/printwriter objects it returns to detect the commit event. I've shown how this might be done by using introspection; but you can use ServletResponseWrapper and custom wrapper classes for the stream/writer if you prefer. In fact you don't need to wrap as many methods as I do here.
In our 'real' code, I recorded the stacktrace and printed it only when the problem occurred as described above, but the code below just logs when responses are committed, you can figure out which was which by looking at your logs.
public class BadCommitFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletRequest) res;
response=Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class[] { HttpServletResponse.class },
new ResponseInvocationHandler(response, response));
chain.doFilter(req, response);
}
private static class ResponseInvocationHandler<T> implements InvocationHandler {
final T proxied;
final HttpServletResponse response;
public ResponseInvocationHandler(T proxied, HttpServletResponse response) {
this.proxied = proxied;
this.response = response;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// in the 'real' code, I checked against a threadlocal
// at the end only, so there was no possibility that I'd
// miss out methods.
boolean isCommitted = res.isCommitted();
try {
Object ret = method.invoke(proxied, args);
if (ret instanceof PrintWriter) {
Proxy.newProxyInstance(ret.getClass().getClassLoader(),
new Class[] { PrintWriter.class },
new ResponseInvocationHandler(ret, response));
} else if (ret instanceof ServletOutputStream) {
Proxy.newProxyInstance(ret.getClass().getClassLoader(),
new Class[] { ServletOutputStream.class },
new ResponseInvocationHandler(ret, response));
}
} finally {
if(!isCommitted && res.isCommitted()) {
try { throw Exception("First Committed:"); }
// or however you want to log this
catch(Exception e){e.printStackTrace();}
}
}
return ret;
}
}
}
If you have trouble with the code, there are some usual suspects to look for. Remember commitment can be triggered explicitly, but more often it is because you have written enough data to the buffer that it has to flush:
using a jsp to dispatch to a servlet. Whitespace and content-type settings in jsps can push you over the buffer limit quite easily, you may not realise you'd written anything. Eg specifically jsps that do anything like <%# page contentType="text/html; charset=UTF-8"%> but then forward to another servlet are wrong.
setting large cookies. Cookies are headers, so count towards the buffer size
servlet filters. Some apps have huge stacks of these, that can be over-eager to write headers.
The issue was because i had a jar called appbase.jar on my classpath when i removed it everything worked fine.

Resources