I am working on a simple program redirection by making some calls to a servlet. However, for some reason, I am continuously getting a 404 error every time I try to construct the code in this particular project build.
It may be of note that I am building this project in Eclipse and am using Apache Tomcat.
here is my coding....
HTML first:
To save some aggrivation, this is the particular snippet on where the problems arise. My connection to the MySQL database along with the database reads are operating perfectly fine.
<form action="objectServer" method="get">
<select name="choice">
<% while (rs.next()){ %>
<option value="<%=rs.getString(2) %>"><%=rs.getString(2) %></option>
<% }
MysqlConnection.close(connect);
%>
</select>
<br />
<input type="submit" value="View the Descrition!" />
</form>
Java code:
The first is a simple java class that validates whether an item has been selected and acts to help redirect.
package com.program.service;
public class Service {
public boolean redirect(String selected){
if( (selected == null) || (selected == "") ){
return false;
} else {
return true;
}
}
}
And finally, the servlet itself.
package com.program.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wines.service.Service;
#WebServlet("/objectServer")
public class InfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String selected = request.getParameter("choice");
Service service = new Service();
boolean redirector = service.redirect(selected);
if(redirector){
response.sendRedirect("next_page.jsp");
} else {
response.sendRedirect("this_page.jsp");
}
}
}
As one can see, this is a REALLY simple program that should be redirecting to the next page, but for some reason I am missing something that I just cannot see at this moment. I don't don't know whether it's an issue with my coding, my server, or something else I could have missed. As a note, the web.xml has not been programmed in this particular application as of yet.
Depending on your setup, your jsp's are most likely can be only accessed through Servlets. In this case, you will need to use "forward" instead of "redirect". Please understand the differences between "forward" and "redirect". Here is a good read: Forward versus redirect
Example Forward:
RequestDispatcher dispatcher = aRequest.getRequestDispatcher("this_page.jsp");
dispatcher.forward(aRequest, aResponse);
Example redirect:
response.sendRedirect(absoluteOrRelativeURL); // e.g absoluteOrRelativeURL= "objectServer"
if your JSP pages are resides under the WEB-INF, you cannot redirect to the JSP page. this is because the content under the WEB-INFare restricted from the direct access. therefore you have to forward the request for that resource. that can be done by modifying you method as follows. ( i have assumed that your jsp pages are resides directly under the WEB-INF directory)
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String selected = request.getParameter("choice");
Service service = new Service();
boolean redirector = service.redirect(selected);
if(redirector){
request.getRequestDispatcher("WEB-INF/next_page.jsp").forward(request,response);
} else {
request.getRequestDispatcher("WEB-INF/this_page.jsp").forward(request,response);
}
}
further more, if you wish to make a ridirect for particular resource, make sure to do the redirect for a servlet mapping. you cannot make a redirect for a particular resource resides under the WEB-INF directory.
Related
I have built a single page webapplication using Angular on the frontend and Spring on the backend. Its a community website and i want to be able to ban misbehaving users the spring way. I have searched stackoverflow to see if there is a thread about this but i could find none.
My attempt to build this functionality is by creating a custom webfilter that filters all incoming requests and checks whether the ip address of the requester is in the blocked ip list. If not then the request gets forwarded, but if it is on the list then an error response is sent back instead.
Here is the code of the filter and an implementing interface:
package RequestPreprocessors;
import DAOs.BanDao;
import Interfaces.IpAddressExtractor;
import Services.ModeratorService;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
import java.util.logging.Logger;
#WebFilter("/*")
public class IpAddressFilter implements Filter, IpAddressExtractor {
private static final Logger log = Logger.getLogger("IpAddressFilter.class");
private Set<String> blockedIpAddresses;
#Autowired
private ModeratorService moderatorService;
#PostConstruct
private void loadBlockedIpAddresses(){
blockedIpAddresses = moderatorService.getBlockedIpAddresses();
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
String clientIpAddress = getClientIP((HttpServletRequest) servletRequest);
log.info("ip " + clientIpAddress + " is requesting " + httpServletRequest.getRequestURI());
if(blockedIpAddresses.contains(clientIpAddress)) {
log.info(clientIpAddress + " is currently on the banlist, aborting request...");
httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
}
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
Here is the code of the implementing interface
public interface IpAddressExtractor {
public default String getClientIP(HttpServletRequest request) {
String xfHeader = request.getHeader("X-Forwarded-For");
if (xfHeader == null){
return request.getRemoteAddr();
}
return xfHeader.split(",")[0]; // voor als ie achter een proxy zit
}
}
This should work but i don't think sending a simple http status code is very elegant, i would like to be able to send back a message explaining to the user that he/she is in fact banned.
So my question is; How do i ban a user from a spring web application effectively. And with effectively i mean being able to send an error message back to the single page app that can then be displayed to the user. I would also like to know if this is the best way to deny banned users access from the REST api. I would like to know if there are different more effective ways to accomplish this.
Thank you
EDIT: This is the tutorial i used to create the majority of the code https://www.baeldung.com/java-web-app-without-web-xml
Effective banning is a co-operative effort between your application doing the detection and the operating system implementing the block. If you are deploying on to Linux then an effective strategy is this:
Log an easily parseable message to an audit log file that says the user is to be banned and include the IP address. The HTTP response to the offender can include a suitable 'goodbye' message.
Install and configure fail2ban to parse your log files and implement the ban. It works by making local modifications to the firewall rules to prevent the offender even making a network connection to your server.
I am using servlet to get request from frontend.
Am i able to make single servlet which could do multiple operation based on url pattern?
Here will be my url mapping
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
<url-pattern>/HelloServletOne</url-pattern>
<url-pattern>/HelloServletTwo</url-pattern>
</servlet-mapping>
That means if i hit to the url as framed below it should invoke its own functionalities.
URL:/HelloServlet: it should do function 1
URL:/HelloServletOne: it should do function 2
URL:/HelloServletTwo: it should do function 3 etc.
How can i achive this by extending servlet.?
Code/link examples are much appreciated.
Regarding your url-pattern you need to know what URL was called. Because a request can be made due to different http-methods (GET, POST etc.) you can use parts of the FrontController Pattern
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet {
private static final String SERLVET = "HelloServlet";
private static final String SERLVET_ONE = "HelloServletOne";
private static final String SERLVET_TWO = "HelloServletTwo";
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
private void processRequest(HttpServletRequest req, HttpServletResponse resp) {
String path = req.getServletPath();
switch (path) {
case SERLVET:
// ... call your function1
break;
case SERLVET_ONE:
// ... call your function2
break;
case SERLVET_TWO:
// ... call your function3
break;
default:
break;
}
// do something else
}
}
The getServletPath method may only work for explicit url-patterns like you have given. For other information on the URL check this link
You can handle multiple requests by the same servlet by making a contract to have a request parameter like 'ACTION'. Then in your forms add this as hidden field with values like 'ACTION_1' and 'ACTION_2' and 'ACTION_3'. So, in doPost() you can check this parameter value and can invoke respective handling methods in same servlet.
class YourServlet extends HttpServlet{
public void doPost(HttpReq req, HttpResp resp){
String action = reg.getParameter('ACTION');
if('ACTION_1'.equals(action)){
doAction_1();
}
if('ACTION_2'.equals(action)){
doAction_2()
}
if('ACTION_3'.equals(action)){
doAction_3()
}
else {
defaultAction();
}
}
}
I made into.
HttpServletRequest.getRequestURI() returns the URL pattern including /* with query parameter if exist, and HttpServletRequest.getPathInfo() returns the part matched by /* (or null for exact match).
Here in my case i need getPathInfo() where it will returns
HelloServlet,HelloServletOne or HelloServletTwo based on request.
Thanks.
You should not use three different Servlet for this purpose. You should use different methods of Servlet to achieve this.
Use doGet method for get data.
Use doPost method for insert data.
Use doPut method for update data.
Use doDelete method for delete data.
Please refer servlet api documentation for more details.
EDIT:
Read more about this here.
It says the url mapping you have provided must work if you are working with servlet api version 2.5 or greater.
Also, please make sure that you have provided fully qualified name of servlet class in <servlet-name>.
I am currently trying to complete a login system using jsp and servlets.I have my register and login validation working.
I wish to link to a welcome page following login to display the user profile information.
I had, just for testing purposes, a response.sendRedirect(welcome.jsp) which redirected following a successful login by the login servlet.
Now, to display the profile info on this welcome page I was going to use a servlet to gather the info from the database and render it to the the browser using a printwriter.
How do I call this servlet successfully from the loginservlet to run the doPost() method?
Or is there a better way of doing it?
Thank you for your time.
(For simplicity, I was just trying to get a basic webpage to appear first to make sure this was working I will have no problem with the database side of things once I get this going)
LOGIN SERVLET:
package logon;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
#WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try
{
System.out.println("In the Login Servlet");
User user = new User();
user.setEmail(request.getParameter("email"));
user.setPassword(request.getParameter("password"));
LoginDAO.login(user);
if(user.isValid())
{
HttpSession session = request.getSession(true);
session.setAttribute("currentSessionUser",user);
session.setAttribute("currentSessionUserEmail", user.getEmail());
response.sendRedirect("WelcomeServlet");
}else
response.sendRedirect("LoginFailure.html");
} catch (Throwable exc)
{
System.out.println(exc);
}
}
}
WELCOME SERVLET:
package logon;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet("/WelcomeServlet")
public class WelcomeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public WelcomeServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out=response.getWriter();
out.print("<html>"+"<head>"+"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">");
out.print("<title>Welcome</title>");
out.print("</head>"+"<body>");
out.print("Welcome to the welcome page!!!");
out.print("</body>"+"</html>");
}
}
You can't redirect using POST, only using GET. Since you're just displaying HTML in WelcomeServlet move the code from doPost to doGet, or make the one call the other, which simply makes them both do the same thing.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
Also, it would be better to use a JSP than to out.print a bunch of HTML inside a servlet. See the info page for servlets.
Plus, obviously your welcome page needs to read the attribute currentSessionUser from the session and make sure its not null to see if the user is really logged in or not. Otherwise if a user knows the address of the welcome page they can just bypass your login check as you have it now.
Your problem is that you have currently implemented your Servlet to respond to the wrong HTTP verb.
You'll notice that the servlet has as doPost and a doGet method. As you might expect these map onto HTTP GET and HTTP POST requests. Your current problem stems from the fact that you have implemented the doPost method in your WelcomeServlet therefore expecting a POST request, when it will actually be serving a GET request.
Speaking very crudely, you can think of GET requests as read operations and POST requests as write operations. So when you submit a form to save some data, this is typically handled a POST request. You are basically asking to write data to a database or session. When you load a web page, this is typically handled as a GET request. You are simply asking to read the data.
Again simplifying, but re-directs are typically GET requests. Therefore your Servlet will need to implement the doGet() method to respond to the browsers GET request after it is re-directed.
A request to an Action can be validated using the Interceptors. Also, Direct request to a JSP page can be avoided using an empty action declaration. It is something like this;
<action name="home" >
<result>home.jsp</result>
</action>
I want to validate this calling to the JSP page. As I feel that a simple approach can be adding an Action (ActionSupport) with an Interceptor which checks the action name( and do some validation using session etc). But I've a doubt that whether it reduces the performance,because that action class doesn't do anything and just execute its execute() only(useless task...), and where there should be an empty Action .(BUT: as I ve read some docs on Struts2, it is said that even though we don't add an Action calss,the framework itself adds and action class which returns "success" therefore,adding an action class or not ourselves, doesn't affect newly )
Any way, I d like to know what your best approaches are to validate or authorized access to some JSP pages.( number of pages can be many.. not only to one jsp page)
Added:
Example:
Lets say that, there are some restricted pages where all users can't have access,for example user's account page can be visited only to logged in users.There can be more such type of pages. If a request comes to a such page,the user has to be validated.Then, if the request comes through a empty/anonymous action (as explained in above code snip -only action name-no real class) how to validate such requests to JSP pages? Should an action class be used for this?
If your attention is to secure some part of your application so as only Authenticated as well authorize use can access that part, than you have two option
Use an interceptor based authentication
User a security API like Spring -security
Interceptor based authentication is quite easy. here is an example how to do this, but such authentication is not recommended for a production based and real life application since its really a very simple case.
if you are looking for a complete authentication system, i suggest you to look at Spring security.Its quite easy and configurable, all you need to tell the underlying spring mechanism which all areas and under secure tag and Spring security will intercept them before your action get called and only successful and authorize action will get called by spring security.
//This is for authorization
package com.kogent.action;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
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 org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.ng.ExecuteOperations;
import org.apache.struts2.dispatcher.ng.InitOperations;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.dispatcher.ng.filter.FilterHostConfig;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
public class SessionController extends StrutsPrepareAndExecuteFilter {
protected PrepareOperations prepare;
protected ExecuteOperations execute;
protected List<Pattern> excludedPatterns = null;
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
prepare = new PrepareOperations(filterConfig.getServletContext(),
dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(),
dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
postInit(dispatcher, filterConfig);
} finally {
init.cleanup();
}
}
/**
* Callback for post initialization
*/
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null
&& prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request,
response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(
request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
//here you have to identify the whether the user have access to requested resource or not
//allow him if he was access.
//if(someCondition)
execute.executeAction(request, response, mapping);
//else{
//redirect the user how do you want it to be.
ActionMapping modfiedActionMapping = new ActionMapping();
modfiedActionMapping.setName("someActionName");
modfiedActionMapping.setNamespace("someNameSpace");
execute.executeAction(request, response, modfiedActionMapping);
//}
}
}
} finally {
prepare.cleanupRequest(request);
}
}
public void destroy() {
prepare.cleanupDispatcher();
}
}
<filter>
<filter-name>struts2</filter-name>
<filter-class>Point to your customized filter</filter-class>
</filter>
This might be a very odd question, but some hints or guidelines will be very helpful. We want to "session proof" our web site, basically make sure that two different sessions generate the same link structure (e.g. Both user-a and user-b will get the same links in the same web page).
The reason behind this test, is that our web site is generated by a content management solution that will generate different links(URLs) for each different session. That CMS (which is internally built) was fixed to return the same links across sessions.
The other situation with session proofing, is that our caching mechanism (SQUID) is giving TCP_MISSes all the time to our website, which makes us think that the complete site is marked dynamic and the caching server is having to reget all objects all the time.
Are you trying to verify that two different users do in fact see the same structure? One way would be to use something like wget to crawl the whole web site from two different IP addresses, and then compare the resulting trees.
This is what we do at amplafi.com
(h/t See http://randomcoder.com/articles/jsessionid-considered-harmful )
in the web.xml:
<filter>
<filter-name>DisableSessionIdsInUrlFilter</filter-name>
<filter-class>
com.amplafi.web.servlet.DisableSessionIdsInUrlFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>DisableSessionIdsInUrlFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
And this java code:
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.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
/**
* remove any session id from the Url.
*
*
* Ideally we would like to only remove this container-provided functionality
* only for public portions of the web site (that can be crawled by google)
* or for links that are to be bookmarked.
*
* #author Patrick Moore
*/
public class DisableSessionIdsInUrlFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) {
chain.doFilter(request, response);
return;
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
/*
* Next, let's invalidate any sessions that are backed by a URL-encoded
* session id. This prevents an attacker from generating a valid link.
* Just because we won't be generating session-encoded links doesn't
* mean someone else won't try
*/
if (httpRequest.isRequestedSessionIdFromURL()) {
HttpSession session = httpRequest.getSession();
if (session != null) {
session.invalidate();
}
}
HttpServletResponseWrapper wrappedResponse = new ResponseWrapper(httpResponse);
chain.doFilter(request, wrappedResponse);
}
#Override
#SuppressWarnings("unused")
public void init(FilterConfig arg0) throws ServletException {
}
/**
* wraps response and prevense jsessionid from being encoded on the output.
*/
private static class ResponseWrapper extends HttpServletResponseWrapper {
ResponseWrapper(HttpServletResponse httpResponse) {
super(httpResponse);
}
#Override
public String encodeRedirectUrl(String uri) {
return uri;
}
#Override
public String encodeRedirectURL(String uri) {
return uri;
}
#Override
public String encodeUrl(String uri) {
return uri;
}
#Override
public String encodeURL(String uri) {
return uri;
}
}
}
If every page in your site has a different link then caching would definitely be broken for the site.
Are you asking how to verify that the links are the same per session?
Or are you asking how to ensure that links are the same per session?
For the former simply browsing from two different browsers and user logins should be sufficient.
As for ensuring the links are the same per session well... That would depend on your implementation which you indicated was inhouse.
Why are your URLs different? Are you storing session IDs in them?
If you are, you should probably move that to a cookie!
You could try using a Load test suite like Pureload to simulate multiple users hitting your site. Pureload can have multiple concurrent simulated users each make the same request and confirm that the results are as expected. Depending on how dynamic your results are this may help you test your bug.
You could write a test in Java using selenium. Add the assertions for the data you expect. Then you could loop over a list of multiple logins to see the test passes for each.
Selenium is pretty easy to get started in and tests can be written in many languages.
See here for details:
http://seleniumhq.org/projects/remote-control/
An example test would be something like this (pseudocode):
public void setUp() throws Exception {
setUp("http://mywebsite.com", "*chrome"); // to run the test in opera replace chrome with opera
}
public void testLoginWithMultipleUsers() {
for(loop over users) {
runLogin(user)
}
}
public void runLogin(User user) throws Exception {
selenium.open("/login.htm");
assertTrue(selenium.isTextPresent("Link1"));
assertTrue(selenium.isTextPresent("2003-2008"));
selenium.open("/account");
assertTrue(selenium.isTextPresent("2003-2008"));
selenium.waitForPageToLoad("30000");
etc...
Selenium provides lots of methods to check if links and other page elements are present and the test can even be recorded in the browser - give it a try!