Inheriting Servlet instead of using filters - java

By reading this answer, I noted that the given exemple :
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
// User is not logged in. Redirect to login page.
((HttpServletResponse) response).sendRedirect("login");
} else {
// User is logged in. Just continue with request.
chain.doFilter(request, response);
}
}
make us having to write in web.xml something like :
<filter>
<filter-name>RestrictionFilter</filter-name>
<filter-class>com.myproject.filters.RestrictionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestrictionFilter</filter-name>
<url-pattern>/restrained/*</url-pattern>
</filter-mapping>
But I want to be totally free to choose which url have to be restrained to loged members (it's a bit annoying to specify, for each url-pattern, the filter which have to be activated).
I used to create a Servlet who inherits HttpServlet and surcharges service() in order to check if the session contains a member instance, and then, calls the "true" service() method :
public abstract class MembreHttpServletProjet1 extends HttpServlet{
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
if(req.getSession().getAttribute("membre") == null){
resp.sendRedirect(req.getContextPath() + "/accueil");
return;
}
super.service(req, resp);
}
}
By this way, if a servlet needs to be used only if the user is loged as a member, I make inherit this servlet by MembreHttpServletProjet1.
Is this way wrong ? I understood the utility of filters in some case but I still confused for this exemple.
Thank you.

Related

Short Ciruit a Servlet Filter chain when the web.xml catches the top-level url-pattern

I have tried to piece together what I have read here and nothing seems to work for me. I am trying to redirect the user to an error .jsp page when they don't have access to my server. So I have the standard Java Filter.
Note, I'll be terse where it doesn't matter too much.
public class SecurityFilter implement Filter
#Override
public void doFilter(final ServletRequest req, final ServletResponse resp, final FilterChain chain) {
HttpServletRequest request = (HttpServletRequest)req;
if (user has access) {
write to DAO
}
else {
HttpServletResponse response = (HttpServletResponse)resp;
response.reset();
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_FOUND);
response.setHeader("Location", request.getRequestURL.toString());
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
response.addCookie(cookie);
}
request.getRequestDispatcher("error.jsp").forward(request, response);
return;
}
chain.doFilter(request, response);
}
Now my web.xml file looks like the following:
<filter>
<filter-name>securityCheckFilter</filter-name>
<filter-class>ui.filter.SecurityCheckFilter</filter-class>
</filter>
...
<filter-mapping>
<filter-name>securityCheckFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
My problem is, I have an index.jsp file which loads up many others at different urls. When it gets hit the security filter gets hit a number of times. I thought the return statement would stop the chain but it doesn't. I can't name the filter because I have only one filter class. How can I stop processing once access has been denied?

How to set the default page of a folder to open when the user enters the folder URL?

If i have a page in the path, let's say, http://localhost:8080/MyApp/admin/login.xhtml, how to set this login.xhtml as the default page to this folder, when the user types http://localhost:8080/MyApp/admin/ ?
And i dont want this page to be in welcome file list, i want it to be the default page ONLY for this folder.
----- EDIT -----
As #joe776 suggested, i tried to put an index.jsp inside my admin folder, with a <jsp:forward page="login.xhtml" /> on it, and it works, but only on the first time! If the user types again http://localhost:8080/MyApp/admin/, it shows an error /admin/paginas/index.xhtml Not Found in ExternalContext as a Resource, where paginas is a folder inside the admin folder. If the user quits the browser, open it again and types the same URL it works, but again, only for the first time. Is tomcat getting crazy or something like that?
An easy way would be to put an index.jsp in that folder and let it redirect to your login.xhtml. Another way is to add login.xhtml as welcome page.
The Tomcat docs give an example for both possibilities: http://wiki.apache.org/tomcat/HowTo#How_do_I_override_the_default_home_page_loaded_by_Tomcat.3F
You can add a security constraint to your web.xml. A sample as follows
<security-constraint>
<display-name>Admin</display-name>
<web-resource-collection>
<web-resource-name>Protected</web-resource-name>
<description>Protected Page</description>
<url-pattern>/admin/ *</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name/>
</auth-constraint>
</security-constraint>
So every time you try to access anything in admin folder, it will direct you to login page.
Edit
to just redirect to /admin/login.xhtml you can use a filter. Here is a sample code of a jsf filter's doFilter method you can modify for your purpose.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
RequestDispatcher rd;
HttpServletRequest req = (HttpServletRequest) request;
String requestURI = req.getRequestURI();
if (requestURI.equalsIgnoreCase("/index.xhtml")) {
rd = req.getRequestDispatcher("/admin/login.xhtml?faces-redirect=true");
rd.forward(request, response);
}else{
chain.doFilter(request, response);
}
}
As #jpr said, i used a Filter to redirect to the login page, only strange thing is that i needed to get the url and do the forward again when the user enters the "/admin" folder, because it was redirecting to the wrong page, don't know why.
But my code now looks like this:
#WebFilter({"/admin/paginas/*"})
public class LoginFilter implements Serializable, Filter{
private static final long serialVersionUID = 1L;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// HttpServletResponse res = (HttpServletResponse) response;
HttpSession httpSession=req.getSession(true);
Object administradorLogado=httpSession.getAttribute("administrador");
System.out.println("Entrando no loginFileter!");
if (administradorLogado == null) {
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/admin/login.xhtml?faces-redirect=true");
requestDispatcher.forward(request, response);
}else{
String url = ((HttpServletRequest)request).getRequestURL().toString();
System.out.println("URL que peguei no filter admin: "+url);
if(url.endsWith("admin/")){
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/admin/login.xhtml?faces-redirect=true");
requestDispatcher.forward(request, response);
}else{
chain.doFilter(request, response);
}
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}

how to prevent servlet from being invoked directly through browser

I was working on a web project using java servlet and jsp pages. In one of the servlet we have RequestDispatcher method and which is calling another servlet.
#WebServlet("/Demo")
public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.sendRedirect("testing"); //calling other servlet
}
}
#WebServlet("/testing")
public class TestingServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("Hello World");
}
}
So, now I wanted to prevent contextRoot/testing from being invoked directly from the browser but instead only let it invoked from the other servlet(Demo)
Please suggest me if there is any way to do that.
Couple of techniques exist:
Look at writing a HTTP Request Filter. You can then inspect the incoming request and the url and reject it if the pattern matches the servlet paths that you do not want to be invoked directly.
Another mechanism is to use the security constraints in your web.xml to allow access to various paths in your application only to authorized users/roles. Look at <security-constraint> tag in web.xml
Answer given by "Romin" is correct. You have to use Filters for this. what you can do is, you can set a new session variable whenever "/Demo" url is accessed and in the filter check for the condition that session exists, if it exists allow the url or else throw error. You could do something similar like this. In "Demo" servlet
#WebServlet("/Demo")
public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
HttpSession session = request.getSession() //get new session
res.sendRedirect("testing"); //calling other servlet
}
}
In Filter class add the below code
#WebFilter("/login")
public class MyFilter implements Filter{
public void init(FilterConfig arg0) throws ServletException {}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpRequest request = (HttpRequest) req;
HttpResponse respone = (HttpResponse) res;
HttpSession session = request.getSession(false) //get the existing session object
if(null != session) {
chain.doFilter(req, resp);
} else {
"redirect to some error page or home page"
}
}
public void destroy() {}
}
One approach is to check the caller's ip using ServletRequest.getRemoteAddr() and rejects it if it's not called locally
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
if(!req.getRemoteAddr().equals("127.0.0.1")) { // reject }
}
However this method wouldn't work legitimate caller (eg: proxy) is also using the same ip.

Example Servlet Filter that catches and blocks IP's that request suspicious URL's

To avoid re-developing the wheel. Are there any example Java EE servlet filters that take care of some basic security checks/ i.e.
Block web requests for a time period if a rootkit hits the server, ie with a url that ends in .exe or contains "../../.."
Throttle or block IP's that are making unexpectedly high number of requests.
I also wonder if something equivalent to a Thread.sleep(1000); in the servlet filter for those particular types of requests wouldn't be such a bad thing.
Maybe this will help.
public class SuspiciousURLFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
if (requestURI.endsWith(".exe")) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
//send error or maybe redirect to some error page
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
filterChain.doFilter(request, response);
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
In your web.xml:
<filter>
<filter-name>suspiciousURLFilter </filter-name>
<filter-class>your.package.SuspiciousURLFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SuspiciousURLFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

how to Open HTML page of subdirectory when URL is hit- using java web.xml

I have a scenario that when user opens http://MYWEBSITE.com/abc/ , the user is directed to xyz.html page which is in abc subdirectory. I am using Java for web development. How can I do this in web.xml?
P.S. URL is http://MYWEBSITE.com/abc/ not http://MYWEBSITE.com/abc
you could define a servlet-filter in web.xml like this
<filter>
<filter-name>incompleteUrlFilter</filter-name>
<filter-class>com.mywebsite.IncompleteUrlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>incompleteUrlFilter</filter-name>
<url-pattern>/abc/*</url-pattern>
</filter-mapping>
and the filter class would look like this
package com.mywebsite;
public class IncompleteUrlFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
if( ((HttpServletRequest)req).getPathInfo() == null ){ // nothing after /abc/ !
req.getRequestDispatcher("/abc/xyz.html").forward(req, resp); // forward to xyz.html
} else {
chain.doFilter(req, resp); // else continue as usual
}
}
}

Categories