I'm setting up authentication for a portion of a webapp using standard servlet container authentication (web.xml security entries) plus Tomcat Realm capabilities (to read users and roles from a database).
Everything seems to fit my requirements except one aspect: since the authentication will guard our REST APIs, I'd like every response to be in JSON format.
But with the tools I'm going to use, when there's a failed authentication Tomcat sends back a response with an HTML body.
I found this question on Spring that addresses the same issue, but it relies on Spring components.
Is there any customization possible using only servlet and Tomcat components?
From first glance, simple solution may look like custom error page for error code 401 (or any other).
Look for answer there:
how to specify the default error page in web.xml
P.S. Probably you can also use custom Servlet filter to handle content for error.
Because you're using a standard JAX-RS provider you can take advantage of the standards that exist. Normally you'd want something like:
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class MyExceptionMapper implements ExceptionMapper<RuntimeException> {
#Override
#Produces(MediaType.APPLICATION_JSON)
public Response toResponse(RuntimeException exception) {
return Response.status(Response.Status.FORBIDDEN)
.entity("{\"error\": \"your error message\"}")
.type(MediaType.APPLICATION_JSON)
.build();
}
}
The hard part here is that the exceptions vary between JAX-RS providers. So, while I may get a RuntimeException with RestEasy (and I know that I do) the exception may be different with Jersey. If you implement an exception mapper that just takes Exception you can quickly figure out what type of Exception is thrown with your JAX-RS provider.
The advantage of this is that it is mostly standard in that you could move to another app server and it would not be Tomcat specific.
Related
The Restlet framework documentation touts it's ability to run stand-alone via it's Server class and using the jse library build or to run in a Servlet container like Tomcat using the jee library build.
The library helpfully produces two types of log records, code related log records for debugging and errors and access related log records that look like this:
20-Dec-2018 12:33:01.723 INFO [http-nio-8088-exec-52] org.restlet.engine.log.LogFilter.afterHandle 2018-12-20 12:33:01 0:0:0:0:0:0:0:1 - 0:0:0:0:0:0:0:1 8088 POST /WebApp/route - 204 0 647 11619 http://localhost:8088 PostmanRuntime/7.4.0 -
This is helpful in stand-alone mode with the -jse build where Engine#setLogLevel(...) exists. I find this Apache httpd like logging to be extra noise when using the -jse build inside of a Tomcat container where I already have a separate access log. Unfortunately Engine#setLogLevel doesn't exist in the JEE build.
Using the simple Apache Tomcat Restlet JEE example code, where is the ideal place to disable the Restlet access log?
After testing different things, using Logger.getLogger("org.restlet").setLevel(Level.WARNING) was the only thing that reliably suppressed the Restlet access log messages. I tried org.restlet.engine, org.restlet.engine.og, and org.resetlet.engine.log.LogFilter and various component access methods, none suppressed the message. I'm not sure if I'm not suppressing more than I really wanted. It seems that if Engine#setLevel isn't available in JEE, then access logging should be default suppressed in JEE.
package my.package.space;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.restlet.Application;
import org.restlet.Restlet; // from org.restlet.jee artifact version 2.3.12
import org.restlet.routing.Router;
public class MyJeeApplication extends Application {
/**
* Creates a root Restlet that will receive all incoming calls.
*/
#Override
public synchronized Restlet createInboundRoot() {
// Create a router Restlet that routes each call to a new instance of HelloWorldResource.
Router router = new Router(getContext());
// Set restlet log level to warning to suppress
// INFO org.restlet.engine.log.LogFilter.afterHandle access log messages
Logger.getLogger("org.restlet").setLevel(Level.WARNING);
// Defines only one route
//router.attach("/hello", HelloWorldResource.class);
router.attachDefault(HelloWorldResource.class);
return router;
}
}
I have a pretty big project with a lot of different controllers. I do have a main controller that has all of the mappings for the start of the program like (/login, /resetPassword, /logout, etc). I also do not have a web.xml file in the project. I need to add a custom error page for all unmapped requests. I have tried creating my own exception class and didn't work. Most of the solutions I find are to add error location to the web.xml. I would prefer not to have to create one but if anybody has any tips or can push me in the right direction that would help out so much. I've been stuck on this problem for a couple of days now. Thanks.
You should use 404 mapped to an error page in web.xml. Because it will handle even url requests that are not mapped to your DispatcherServlet. For example, imagine your Spring DispatcherServlet is mapped to any url ending in .htm, now some mistypes and tried to access something/somethingelse.do your application server will now present its own default error page to the user, which might not be pleasant.
The only time you should think about serving custom error pages from your MVC controllers, is when you have something specific to show the user. Specific as in, if an exception is encountered in this particular controller, I want to show a specific message, or redirect the user to a specific page. In these cases, you can use #ExceptionHandler methods in Spring controllers.
For more, look at this blog post, or refer the MVC documentation: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
See this answer: How to make a filter to detect if the user requested a page that is not found?
Make a Filter
Use HttpServletResponseWrapper and override the sendError() and setStatus()
Pass the wrapped response through chain.doFilter(req, wrapper)
If you get a sendError() in your wrapper, see if it's a 404.
Take appropriate response.
I am writing a restlet client that will invoke some Resteasy coded rest services (cannot change the server code, hence cannot use the Restlet way of annotating resources).
Resource Interface is using JAX-RS annotations and have more than one #POST method (one of the biggest problems of Restlet when dealing with this).
I was trying to do my implementaion this way:
IAppLoginResource resource = JaxRsClientResource.createJaxRsClient("http://localhost:9090/rest", IAppLoginResource.class);
final GetLoginAppInfoResponse response = resource.getLoginAppInfo( getLoginAppInfoRequest );
The problem is that the request by default is GET, I didn't find a way to specify the request method like when using ClientResource (which I can't use because I need to deal with JaxbRepresentation and Jaxb problems).
Any sample/snippet of code that implement a Restlet client using JAX-RS annotated resources?
Any ideas?
Thanks,
I've entered an issue for this topic:
https://github.com/restlet/restlet-framework-java/issues/1081
I've tested a sample application based on your code, and it works properly using the current 2.3 branch (future 2.3.3). I wonder if the fix for this issue https://github.com/restlet/restlet-framework-java/issues/1072 helps.
Regarding the documentation, I 'll complete the current page (http://restlet.com/technical-resources/restlet-framework/guide/2.3/extensions/jaxrs), cf this issue: https://github.com/restlet/restlet-framework-java/issues/1084.
You can also have a look at the org.restlet.test project, especially in this package https://github.com/restlet/restlet-framework-java/tree/2.3/modules/org.restlet.test/src/org/restlet/test/ext/jaxrs.
I am working on a web application using the Spring framework and Hibernate. My problem is that I often receive 404 errors caused by a mistake I have made somewhere in the codebase but there are no exception messages in the console. Because of this I am struggling to find where the mistake is because the project has become very large and manually trying to find the problem is impractical. I'm assuming that Spring is causing the problem so my question is: is there some way of enabling more detailed error messages? Thanks
404 is an http error and only your web server might be knowing of it. Very likely with these failed requests, your application server or Spring container was never hit. Look for web server logs to identify the problem.
Troubleshooting 404 on IIS server
http://blogs.iis.net/tomkmvp/archive/2009/04/27/troubleshooting-a-404.aspx
Troubleshooting 404 on RAD web server
http://www-304.ibm.com/support/docview.wss?uid=swg27035752&aid=1
As a couple of people have already alluded to it, the issue here is that certain errors (like the 404 exception) get intercepted by the Servlet container, therefore never reaching Spring and whatever logging mechanisms you have may have set up. So the trick here is to change the order of importance of your Exceptions so that Spring gets a crack at it.
The best approach I have ever come across to catch, handle and adequately log all exceptions in Spring is described in this article: http://steveliles.github.io/configuring_global_exception_handling_in_spring_mvc.html
I have been implementing this setup since I came across that blog post, and it has been a lifesaver to say the least. It will give you the detailed error messages you need. The key is to basically create a custom Exception Handler by implementing Spring's HandlerExceptionResolver and Ordered interfaces, then returning the lowest possible order number, thus moving your exception handling up the totem pole:
import org.springframework.core.*;
import org.springframework.web.servlet.*
public class LoggingHandlerExceptionResolver
implements HandlerExceptionResolver, Ordered {
public int getOrder() {
return Integer.MIN_VALUE; // we're first in line, yay!
}
public ModelAndView resolveException(
HttpServletRequest aReq, HttpServletResponse aRes,
Object aHandler, Exception anExc
) {
anExc.printStackTrace(); // again, you can do better than this ;)
return null; // trigger other HandlerExceptionResolver's
}
}
The problem ended up being that there were a couple of missing annotations from one of my Hibernate entities. Following the procedure from the link below helped track it down by providing more detailed error messages:
http://www.captaindebug.com/2011/07/using-hibernate-validation-annotation.html
I also hit the problem of no console output while 404 error.
As in The Saint's answer, one of the causes of no console log:
the issue here is that certain errors (like the 404 exception) get intercepted by the Servlet container
"spring-framework-reference-3.2.3.pdf" --> 1.3 --> Logging --> Using Log4J, solved the problem in my environment.
I have been researching on the better framework I could use to validate the data at client and server side. I know it is important to do validations at both the side.
I had thus come across something called GWT Validation Framework which can do validations at both the side. I have few JSP's. I have o validate the data filled in by user, at client side. But I haven't found a single example on how to do it? Can anyone please enlighten on the same.
Thank you
P.S: It would be grateful if someone could assist on some better client side validation methods(other than java script).
GWT has support for compiling javax.validation into a compile module, but it isn't going to be easy to use without actually using GWT. The validation mechanism is powered by JSR-303 bean validations, and so needs to see the bean on both the client and on the server - a html client page created by a jsp isn't enough, you need to create and load a GWT module onto the page.
In GWT, you write what looks like Java, and it compiles to JavaScript. JSR303 support also gets compiled to javascript, so any amount of client side validation isn't enough - see Why is client-side validation not enough? for more explanation on that - your server also needs to run the validation.
If you are not already using GWT, then GWT's validation isn't going to make a lot of sense for your project. If you decide this all makes sense for you, then start using it - check out http://www.gwtproject.org/doc/latest/DevGuideValidation.html for more information and the sample project at https://github.com/gwtproject/gwt/tree/master/samples/validation for some source.
For client side data validation
I am using Putnami Web Toolkit (PWT).
This framework is compliant with commons JSR-303 bean validation annotations.
You can find documentation and live example at this location :
http://pwt.putnami.org/#!Validation
For server side data validation
I am using Hibernate's Bean Validation JSR-303 reference implementation ( version 4.3.2-Final ).
An example below :
imports :
import java.util.HashSet;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.Validator;
code :
final Set<ConstraintViolation<BeanToValidate>> violations = validator.validate(form);
if (!violations.isEmpty()) {
final Set<ConstraintViolation<?>> constraintViolations = new HashSet<ConstraintViolation<?>>(
violations);
throw new ConstraintViolationException(constraintViolations);
}