my servlet mapping spoil my filter - java

In my program any url in the form of /Controller/* is redirected by my servlet mapping to Controller class.
I tried to add a filter for authantication, if user is not logged in and path is not /Controller/RegForm it's redirecting to /Controller/RegForm.
Problem is because my servlet mapping redirects to /Controller, filter always gets the /Controller as path.
How can I use both filter and the servlet mapping ?
This is my web.xml:
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/Controller/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>/Controller/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
my filter:
#WebFilter("/Controller/*")
public class AuthFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
#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);
String path = ((HttpServletRequest) request).getServletPath();
if ((session != null && session.getAttribute("student") != null )||(excludeFromFilter(path))) {
chain.doFilter(req, res); // Log
}
else {
response.sendRedirect("/registration-war/Controller/RegForm"); // No logged-in user found, so redirect to login page.
}
}
private boolean excludeFromFilter(String path) {
if (path.equals("/Controller/RegForm")) {
return true; // add more page to exclude here
} else {
return false;
}
}

You use HttpServletRequest.getServletPath() which returns the servlet URL which is (according to your servlet mapping) "/Controller".
You want the path info not the servlet path:
Returns any extra path information associated with the URL the client sent when it made this request. The extra path information follows the servlet path but precedes the query string and will start with a "/" character.
So for example this will return "/RegForm" if your user requests the /Controller/RegForm page.
String pathInfo = HttpServletRequest.getPathInfo();

Related

Java web.xml - How do I do a catchall servlet for any unmatched requests to forward to index.html?

I am serving an angular page in a Java WAR in Glassfish.
I need to serve everything under public as a static file and all other requests should serve index.html.
Because it's Angular, it needs to serve index.html but still keep the end. So if you go to example.com/stuff it should load the index page and keep /stuff on the end.
I have this glassfish-web.xml right now, but I'm still getting a 404 for everything outside public.
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD
GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>DefaultServlet</servlet-name>
<servlet-class>
org.apache.catalina.servlets.DefaultServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DefaultServlet</servlet-name>
<url-pattern>*</url-pattern>
</servlet-mapping>
</glassfish-web-app>
Use a Serlvet Filter:
#WebFilter("/*")
public class MainFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String requestUrl = request.getRequestURL().toString();
if (validUrl(requestUrl)) {
//allowed, continue navigation
chain.doFilter(req, res);
} else {
//invalid URL, send back to index.html
String invaludUrl = retrieveInvalidPart(requestUrl);
response.sendRedirect(request.getContextPath() + "/index.html" + invaludUrl);
}
}
private boolean validUrl(String url) {
//implement how to validate the URL
}
private String retrieveInvalidPart(String url) {
//implement how to recognize the invalid part of the URL
}
}
Note that this problem is completely unrelated to GlassFish or any other application server.
If you also want/need to add the query string associated to the url in case of invalid request, you may retrieve it by using HttpServletRequest#getQueryString:
//invalid URL, send back to index.html
String invaludUrl = retrieveInvalidPart(requestUrl);
String queryString = request.getQueryString();
queryString = (queryString == null) ? "" : queryString;
response.sendRedirect(request.getContextPath() + "/index.html" + "?invalidUrl=" + invaludUrl + queryString);
More info:
StackOVerflow Servlet Filter Wiki
How can I get the request URL from a Java Filter?

POST to GET Redirection

On jsp page After session expiration if a user performs some DB operations the Post url HTTP status shows as 302 which should redirect to my logout Page but as it's a GET call to logout it is not being redirected.
How to redirect from POST Http status 302 to GET or what can be the other way to achieve this?
Some comments/suggestion:
When the server responds with HTTP 302 additionally it also sends a Location header which browser reads and makes another GET request.
This is how it typically works. So please make sure that when you send HTTP 302 you also send a Location header in response and then rest of the things will be handled by the browser.
Please note that here I have take liberty to assume that you can change server side code which sends HTTP 302. Let me know if its otherwise.
You can use Session Filter like :
public class SessionFilter implements Filter {
private ArrayList<String> urlList;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
boolean allowedRequest = false;
if(urlList.contains(url)) {
allowedRequest = true;
}
if (!allowedRequest) {
HttpSession session = request.getSession(false);
if (null == session) {
response.sendRedirect("index.jsp");
}
}
}
chain.doFilter(req, res);
}
}
and by making an entry in webl.xml
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>
net.viralpatel.servlet.filter.SessionFilter
</filter-class>
<init-param>
<param-name>avoid-urls</param-name>
<param-value>index.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Or hide the details via placing following entry in web.xml:
<error-page>
<error-code>302</error-code>
<location>/302ErrorPage.jsp</location>
</error-page>

getting IllegalStateException within the doFilter method

When i create a servlet filter in Spring MVC, I am getting the following exception.
[javax.servlet.ServletException: java.lang.IllegalStateException: Cannot create a session after the response has been committed] with root cause
when i put the sysout i could understand that the exception occurs at the redirect line, but didn't understand why
can anyone please tell me some solution for this
SessionFilter.java
public class SessionFilter implements Filter {
private ArrayList<String> urlList;
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
boolean allowedRequest = false;
if(urlList.contains(url)) {
allowedRequest = true;
}
if (!allowedRequest) {
HttpSession session = request.getSession(false);
if (null == session) {
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
}
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig config) throws ServletException {
System.out.println("entered init");
String urls = config.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVCHibernate</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.common.dao.SessionFilter</filter-class>
<init-param>
<param-name>avoid-urls</param-name>
<param-value>index.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
:
:
:
To simple and short Answer for your Question:
To avoid this , you should have a return statement , or avoid redirecting or forwarding request , or these kind of things should be done by the last filter in the filter chain.
For More Details Explanation you can read below :
This Exception occurs when you try to send response again when the response is already committed and flushed to user.
For Example :
Here in below example code ,first the request will be forwarded to index_test.jsp and response will be flushed to user , then the control will again come back to filter and try to send another response (redirect)to user , and it will fail.
Usually we check multiple conditions in filter and accordingly forward and redirect , if two conditions are met , then it will create a problem .
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.getRequestDispatcher("index_test.jsp").forward(request, response);
((HttpServletResponse)response).sendRedirect("new.jsp");
chain.doFilter(request, response);
}
Solution for your case :
To avoid this , you should have a return statement , or avoid redirecting or forwarding request , or these kind of things should be done by the last filter in the filter chain.
So you could change your code as :
public class SessionFilter implements Filter {
private ArrayList<String> urlList;
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
boolean allowedRequest = false;
if(urlList.contains(url)) {
allowedRequest = true;
}
if (!allowedRequest) {
HttpSession session = request.getSession(false);
if (null == session) {
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
return;
}
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig config) throws ServletException {
System.out.println("entered init");
String urls = config.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}
Its Obvious right :
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
return;
We are have return after that statement.
So further execution wont happen so u are not getting exception.
See we cant involve both filtering and Redirect or Forward in same block it will give IllegalStateException because :
This Exception occurs when you try to send response again when the response is already committed and flushed to user

How JSP page should check authentication

I am new to web programming. I am asking a common pattern to do things like checking authentication. Here is the scenario:
The website has a login page for visitors. It will take username and encrypted password and sent them to server, then get either a error code (username/password doesn't match)or an auth key from the server. When the user logged in successfully, I want the website automatically jump to the main.jsp page that presents the main functionality of the website.
In this case, I want main.jsp check the user authentication. That is, I don't want such thing happens like user can directly open www.example.com/main.jsp, and if they did thing like this, I want to redirect them to login page.
So how could I pass authentication information across page, and how could I prevent user from directly accessing the main.jsp without login? Do I need to use session or anything?
you could try using filters:
Filter can pre-process a request before it reaches a servlet,
post-process a response leaving a servlet, or do both.
Filters can intercept, examine, and modify requests and responses.
NOTE: be sure to add a session attribute once your user is logged in, you can use that session attribute on the filter
on your login.jsp add:
session.setAttribute("LOGIN_USER", user);
//user entity if you have or user type of your user account...
//if not set then LOGIN_USER will be null
web.xml
<filter>
<filter-name>SessionCheckFilter</filter-name>
<filter-class>yourjavapackage.SessionCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionCheckFilter</filter-name>
<!--url-pattern>/app/*</url-pattern-->
<url-pattern>/main.jsp</url-pattern> <!-- url from where you implement the filtering -->
</filter-mapping>
SessionCheckFilter.java
public class SessionCheckFilter implements Filter {
private String contextPath;
#Override
public void init(FilterConfig fc) throws ServletException {
contextPath = fc.getServletContext().getContextPath();
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getSession().getAttribute("LOGIN_USER") == null) { //checks if there's a LOGIN_USER set in session...
res.sendRedirect(contextPath + "/login.jsp"); //or page where you want to redirect
} else {
String userType = (String) req.getSession().getAttribute("LOGIN_USER");
if (!userType.equals("ADMIN")){ //check if user type is not admin
res.sendRedirect(contextPath + "/login.jsp"); //or page where you want to
}
fc.doFilter(request, response);
}
}
#Override
public void destroy() {
}
}
How JSP page should check authentication
It shouldn't. You should use Container Managed Authentication, and define the login/security in web.xml via URL patterns.
Added by Glen Best:
E.g. Add something like this to web.xml:
<security-constraint>
<display-name>GET: Employees Only</display-name>
<web-resource-collection>
<web-resource-name>Restricted Get</web-resource-name>
<url-pattern>/restricted/employee/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Employee</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
This also works for me
<filter>
<filter-name>SessionCheckFilter</filter-name>
<filter-class>yourjavapackage.SessionCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionCheckFilter</filter-name>
<!--url-pattern>/app/*</url-pattern-->
<url-pattern>/main.jsp</url-pattern> <!-- url from where you implement the filtering -->
</filter-mapping>
public class SessionCheckFilter implements Filter {
private String contextPath;
#Override
public void init(FilterConfig fc) throws ServletException {
contextPath = fc.getServletContext().getContextPath();
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getSession().getAttribute("LOGIN_USER") == null) { //checks if there's a LOGIN_USER set in session...
req.getRequestDispatcher("login.jsp").forward(req, resp); //or page where you want to redirect
} else {
String userType = (String) req.getSession().getAttribute("LOGIN_USER");
if (userType.equals("ADMIN")){ //check if user type is admin
fc.doFilter(request, response); it redirected towards main.jsp
}
}
}
#Override
public void destroy() {
}
}
How about using:
String username = request.getRemoteUser();

Filter called only for servlets

How can i use a Filter just for servlets and not for jsp?
url-patterns :
/* - this makes the container to call the filter for servlets as well as jsp.
*.jsp - this makes the container to call the filter only for jsp.
Is there any way it calls the filter only for servlets..
Since filter is mapped to URL and the mapping is always "positive", i.e. you cannot say "call this filter unless url is *.jsp) the only solution is create special URLs for either servlets or JSPs.
For example you can map all your servlets to URLs that end with *.do, e.g. create.do, delete.do etc.
<servlet-mapping>
<servlet-name>Create Servlet</servlet-name>
<url-pattern>/create.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Delete Servlet</servlet-name>
<url-pattern>/delete.do</url-pattern>
</servlet-mapping>
Then you can create filter and map it to *.do:
<filter-mapping>
<filter-name>actionsFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
It will work for all servlets (because they are mapped to *.do) and will not work for JSPs (because they are not mapped to *.do).
You can do this by adding a Dummy Filter that doesn't propagate to the FilterChain, i.e. not calling FilterChain.doFilter() in the Dummy Filter, but including the requestdispatcher for jsp files.
public class NOPDummyFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
req.getRequestDispatcher(req.getServletContext().getContextPath()
.substring(req.getServletContext().getC‌​ontextPath().lastIndexOf('/') + 1)).include(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
and in the web.xml:
<filter>
<filter-name>NOPDummyFilter</filter-name>
<filter-class>NOPDummyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NOPDummyFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>MyRealServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
see this discussion: http://www.coderanch.com/t/169859/java-Web-Component-SCWCD/certification/Filter-has-Exclude-url-pattern
hope this helped.
And code:
// Check if request goto a Servlet
private boolean needFilter(HttpServletRequest request) {
//
// Servlet Url-pattern: /path/*
//
// => /path
String servletPath = request.getServletPath();
// => /abc/mnp
String pathInfo = request.getPathInfo();
String urlPattern = servletPath;
if (pathInfo != null) {
// => /path/*
urlPattern = servletPath + "/*";
}
// Key: servletName.
// Value: ServletRegistration
Map<String, ? extends ServletRegistration> servletRegistrations = request.getServletContext()
.getServletRegistrations();
// collection of all servlets in your webapp.
// containing *.jsp & *.jspx
Collection<? extends ServletRegistration> values = servletRegistrations.values();
for (ServletRegistration sr : values) {
Collection<String> mappings = sr.getMappings();
if (mappings.contains(urlPattern)) {
return true;
}
}
return false;
}

Categories

Resources