I want to create "pre" function. and in this function to check the session,
When some function in controller is called, I want that my "pre" function will called before it. and from the "pre" function I will pass the user to logIn page or to do the function.
something like this pseudo code:
if(!session)
return "redirect:login";
else
//calling to the selected function,
I saw some solutions to create this function, but the solution was to create it by: #ModelAttribute. and the problem is that with #ModelAttribute I didn't find any way to pass to another function in my controller.
More than, the selected function is always called after my #ModelAttribute finish,
How can I do that? there is a way to do something like this?
You can achieve that by using a servlet Filter. Here is a code snippet:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class RestrictionFilter implements Filter {
private static final String ACCES_PUBLIC = "/loginPage.jsp";
private static final String ATT_SESSION_USER = "user";
public void init( FilterConfig config ) throws ServletException {
}
public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain ) throws IOException,
ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
final HttpSession session = request.getSession();
/**
* check if user is not connected.
*/
if (session.getAttribute( ATT_SESSION_USER ) == null) {
/* Redirection to login page */
response.sendRedirect( request.getContextPath() + ACCES_PUBLIC );
} else {
/** access granted for the user*/
chain.doFilter( request, response );
}
}
public void destroy() {
}
}
Then add the filter to your web.xml like below:
<filter>
<filter-name>RestrictionFilter</filter-name>
<filter-class>yourPackage.RestrictionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestrictionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Related
I have integrated an application on tomcat to use Jasig Cas. Now i have made the entire application(SampleApp) to be authenticated by CAS. But there is a certain URL that i need to bypass this authentication i.e. (SampleApp/HomeListener).
I have written a new application Filter for this. But what parameter do i need to modify in the Servlet request object to achieve this.
Filter
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class PatternFilter implements Filter {
private FilterConfig config;
public void destroy() {
//nothing here
}
/**
* Filters the HTTP requests
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filter) throws IOException, ServletException {
filter.doFilter(request, response);
}
public void init(FilterConfig filterConfiguration) throws ServletException {
// TODO Auto-generated method stub
config = filterConfiguration;
}
}
You do not need to write your own filter. Try adding the "ignorePattern" parameter to your authentication filter configuration in your web.xml.
<init-param>
<param-name>ignorePattern</param-name>
<param-value>http://<your url pattern to bypass>/(.*)</param-value>
</init-param>
My aim: Inject any text into response.
My Tries: On various small projects I had successfully implemented a filter which alters the response.
My Approach: You may find all code at the bottom of my questions !
The problem I am facing is HttpServletResponseWrapper.toString() is returning "" when I put my code to huge web application( My project has many filter, security, spring and struts framework together, jsp and FTL views). When used on simple project the HttpServletResponseWrapper.getStatus() returns 304. But when used on my big application, the status returned is 200 (indicating the request succeeded normally). What happens at the end is un-altered response rendered to browser.
I would appreciate if I get any pointers to this issue from you. Thanks in advance. Below is the code I am using:
LogFilter.java
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class LogFilter implements Filter {
public void init(FilterConfig config)
throws ServletException{
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws java.io.IOException, ServletException {
System.out.println("BEFORE filter");
ServletOutputStream out = response.getOutputStream();
CharResponseWrapper responseWrapper = new CharResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, responseWrapper);
System.out.println("status : "+responseWrapper.getStatus());
String servletResponse = new String(responseWrapper.toString());
out.write((servletResponse + " filtered all data without any issues <B>Hahaha :)</B>").getBytes()); // Here you can change the response
System.out.println("AFTER filter, original response: "
+ servletResponse.toString());
}
public void destroy() {
}
}
CharResponseWrapper.java
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class CharResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter output;
public String toString() {
return output.toString();
}
public CharResponseWrapper(HttpServletResponse response) {
super(response);
output = new CharArrayWriter();
}
public PrintWriter getWriter() {
return new PrintWriter(output);
}
}
web.xml
.
.
.
.
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.<<hidden>>.web.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
.
.
.
Thank you very much #JBNizet. You are correct, I must override getOutputStream which I missed to implement. After searching more, I got an example at check answers. And it is working now. I am closing my question!
I have this code for filtering cache pages but facing some problems while compiling:
package bean.log.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
//import javax.servlet.annotation.WebFilter;
public class LoginFilter implements Filter
{
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
try
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("userHash") == null)
{
response.sendRedirect("/scape/applicationservices/fileshare/vm/login/login.jsp"); // No logged-in user found, so redirect to login page.
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);
}
else
{
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
After compiling the same I get following error:
D:\programs\MyPackage\bean\log\filter>javac LoginFilter.java
LoginFilter.java:14: bean.log.filter.LoginFilter is not abstract and does not ov
erride abstract method destroy() in javax.servlet.Filter
public class LoginFilter implements Filter
^
1 error
So I made changes in my code as below then it compiled but I am not getting desired result .The changes I made are:
I put #Override and implements Filter in comment and added public void init and public void destroy method
package bean.log.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
//import javax.servlet.annotation.WebFilter;
public class LoginFilter // implements Filter
{
//#Override
public void init( )
{
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
try
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("userHash") == null)
{
response.sendRedirect("/timescape/applicationservices/fileshare/vm/login/login.jsp"); // No logged-in user found, so redirect to login page.
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);
}
else
{
chain.doFilter(req, res); // Logged-in user found, so just continue request.
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void destroy( )
{
}
}
How to cofigure filter in web.xml
I configured it like below
<web-app>
<welcome-file-list>
<welcome-file>/WEB-INF/index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>noCacheFilter</filter-name>
<filter-class>bean.log.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noCacheFilter</filter-name>
<url-pattern>/scape/applicationservices/fileshare/vm/apps/*</url-pattern>
</filter-mapping>
</web-app>
I want this filter to restrict user to go back after LOGOUT to previous cache pages which are in my apps directory so I use that url-pattern.
how to achieve this filter to be worked.
A Java EE filter has to implement the interface you mentioned above: javax.servlet.Filter. Your problem doesn't lie in the Filter itself but in your Java usage. In this language when some non-abstract class implements the interface it or its parent has to implement all the declared methods. It means, that when the interface declares methods init(), doFilter() and destroy() then your class has to implement all of them even when the implementation should be empty. It means that you have to combine your both solutions:
uncomment implements Filter
let uncommented methods init() and destroy()
possibly uncomment #Override if you are using Java 6 or later
After that your filter should be fine, at least it should be executed when the web container processes some page matching URL specified in your web.xml mapping.
Anyway I guess that the logout URL is not usually so complicated so I would expect the mapping URL to be something like /logout. As I already mentioned the filter is executed only with pages matching the URL.
To provide proper browser caching I want to get rid of the conversationContext parameter, that Apache MyFaces Orchestra adds to every request, for requests to css files.
As Bozho suggested, I've implemented a filter that sets the attribute Orchestra is looking for.
public class ResourceFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException {
if(shouldNotAppendConversation(request)) {
request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE);
}
theChain.doFilter(request, theResponse);
}
private boolean shouldNotAppendConversation(ServletRequest theRequest) {
HttpServletRequest aRequest = (HttpServletRequest) theRequest;
String aPath = aRequest.getRequestURI();
if(aPath.endsWith(".css.jsf")) {
return true;
}
return false;
}
#Override
public void init(FilterConfig theFilterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
That doesn't work the parameter is still appended to every request. While debugging, I've found out that the filter gets first hit by a request to the jsf site. For sure I want to include the conversation context in that request, so the filter forwards the request directly to the next filter in the chain. The next request that hits the filter (usually the request for a css file) has already the conversation context included in the request.
The strange thing is, if I modify the filter to always set the attribute, all request will not have the conversation context attribute. But that means, the conversation context is also not included in the request for the jsf site (but should).
I've noticed that the links to css files in the generated html of the jsf site also contains the conversation context attribute or not depending on the filter implementation. I guess for this reason the second request has already included the conversation context parameter?
I don't understand why Orchestra is appending the conversation context parameter to every request and not just for the requests where the attribute is not set.
How can I implement the filter to work correctly?
The next request (e.g. for a CSS file) hitting your filter after the request to your page has already the conversationContext parameter included just because this is how the url for this resource has been rendered by the page in the previous request.
So the control over conversationContext should be taken at render time. The following solution is working for me with JSF 2 (I am using Mojarra 2.1.11, myfaces-orchestra-core20 1.5, RichFaces 4.1.0.Final). A special servlet filter is doing nothing but wraps HttpServletResponse with our own wrapper:
public class RfOrchestraParamControlFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
chain.doFilter(request, response);
}
...
}
The response wrapper tests the url to be encoded for being a richfaces resource and turns Orchestra's ConversationRequestParameterProvider's separation mode on in the current thread for the time of encoding:
package ...
import javax.faces.application.ResourceHandler;
import org.richfaces.resource.ResourceHandlerImpl;
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider;
public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper {
public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) {
super(httpServletResponse);
}
#Override
public String encodeURL(String url) {
if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) {
boolean current = ConversationRequestParameterProvider.isInSeparationMode();
/* Disable conversationContext parameter in current thread for the time of rendering link to a resource */
ConversationRequestParameterProvider.setInSeparationMode(true);
String result = super.encodeURL(url);
/* Restore */
ConversationRequestParameterProvider.setInSeparationMode(current);
return result;
}
else return super.encodeURL(url);
}
}
(I've had to use String.contains() instead of String.startsWith() when testing the url for being a resource as context path and servlet path happen to prepend the passed url.)
However that does not help either by this moment. The reason is that Orchestra uses its own response wrapping that takes place in its RequestParameterFacesContextFactory, and this wrapping happens after our filter is hit. In this way Orchestra's wrapper turns out to be external to our one which results in our wrapper receiving url too late, when the url has already been intercepted and conversationContext appended.
To avoid this we have a way to make our response wrapper external to Orchestra's one by replacing effect from RequestParameterFacesContextFactory interceptor with RequestParameterServletFilter which actually does the same work. Unfortunately using another filter is not quite exquisite where we might not, but I don't see another way so far.
So, in web.xml place your filter after Orchestra's one:
<filter>
<filter-name>requestParameterFilter</filter-name>
<filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class>
</filter>
<filter>
<filter-name>myOrchestraFilter</filter-name>
<filter-class>mypkg.RfOrchestraParamControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestParameterFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>myOrchestraFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Could not make previous solutions work. I did it this way:
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;
import javax.faces.application.ResourceHandler;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
/**
* #author Felipe Riccetto
*/
public class RemoveConversationParamFilter implements Filter {
public static String removeQueryParameter(final String url,
final String parameterName) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(url);
List<NameValuePair> queryParameters = uriBuilder.getQueryParams()
.stream().filter(p -> !p.getName().equals(parameterName))
.collect(Collectors.toList());
if (queryParameters.isEmpty()) {
uriBuilder.removeQuery();
} else {
uriBuilder.setParameters(queryParameters);
}
return uriBuilder.build().toString();
}
#Override
public void destroy() {
// nothing
}
#Override
public void doFilter(final ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp2 = new HttpServletResponseWrapper(
(HttpServletResponse) resp) {
#Override
public String encodeURL(String url) {
String s = super.encodeURL(url);
try {
String urlPath = new URL(
((url.toLowerCase().startsWith("http://")
|| url.toLowerCase().startsWith("https://"))
? ""
: "http://fake")
+ url).getPath().toString().toLowerCase();
if (urlPath.endsWith(".js") || urlPath.endsWith(".css")
|| urlPath.endsWith(".png")
|| urlPath.endsWith(".jpeg")
|| urlPath.endsWith(".jpg")
|| urlPath.endsWith(".gif") || urlPath.contains(
ResourceHandler.RESOURCE_IDENTIFIER)) {
s = removeQueryParameter(s, "conversationContext");
}
} catch (MalformedURLException | URISyntaxException e) {
// ignore
}
return s;
}
};
chain.doFilter(req, resp2);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// nothing
}
}
web.xml:
<filter>
<filter-name>RemoveConversationParamFilter</filter-name>
<filter-class>RemoveConversationParamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoveConversationParamFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
This last mapping must be the last in your web.xml
I want to fully internationalize my web page and have URLs translated to different languages. For example
http://example.tld/en/page
http://example.tld/de/pagina
all aforementioned pages should be handled by same controller and show same content (translated to desired language of course, this i know how to do - using message properties).
So my questions are:
How to achieve this functionality using #RequestMapping annotation?
Can I configure such aliases in properties or XML file and then "inject" them into controller? i.e.:
properties file:
alias.page=page:pagina
Controller
#RequestMapping("${alias.page}")
...
Or something like this.
Thanks for answers.
I've solved this issue by creating own implementation of servlet Filter
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class ExampleFilter implements Filter {
#Override
public void init(FilterConfig fc) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain fc) throws IOException, ServletException {
// Needed for getting URL from request
final HttpServletRequest hsRequest = (HttpServletRequest) request;
String url = hsRequest.getRequestURI().substring(
hsRequest.getContextPath().length()
);
/* This is just simple example. Here you can connect to database
or read properties or XML file with your configuration */
if ("/de/pagina".equals(url) || "/en/page".equals(url)) {
// change url and forward
RequestDispatcher dispatcher = request.getRequestDispatcher("/page");
dispatcher.forward(request, response);
} else {
// Do nothing, just send request and response to other filters
fc.doFilter(request, response);
}
}
#Override
public void destroy() {}
}
The controller method to handle request will then look like
#Controller
public class MultiLangController {
#RequestMapping(value="/page", method = RequestMethod.GET)
public String pageMethod() {
return ...;
}
}
Finally publish the new filter into web.xml
<filter>
<filter-name>MyExampleFilter</filter-name>
<filter-class>
com.path.to.filter.ExampleFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>MyExampleFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
And that should do the trick. If you don't need such flexibility, maybe UrlRewriteFilter (analogue of .htaccess for Java) will be sufficient.
Use a PathVariable in the #RequestMapping, with something before it so Spring can map the request:
#RequestMapping("myPage.do")
public String displayBasePage () {
return("pageName"); // a hard-coded JSP
}
becomes
#RequestMapping("/someidentifier/{pageName}.do"
public String displayBasePage (
PathVariable("pageName") String pageName) {
return(pageName); // the language-specific JSP, or whatever else you want to do
}
Spring will match the /someidentifier/ to this RequestMapping, and you can use whatever value you want for the pageName.