how to enable PUT method in Jetty? - spring-mvc

I'm working on a Spring REST / Backbone application.
While GET works great, I'm having trouble with PUT (and probably the same with DELETE).
My Spring controller has the following method:
#RequestMapping(value="/{id}", method = RequestMethod.PUT)
public void putItem( #PathVariable("id") String id, #RequestBody Item item) {...}
But when I try to save a Backbone model, I get the following error:
405 (HTTP method PUT is not supported by this URL)
The GET mapping is in the same controller class and uses the same url annotation (class-level).
Are my annotations correct? I'm using Jetty for server, do I need to configure it somehow to allow PUT requests?
EDIT:
assuming that this is a Jetty configuration issue, I added the following to webdefault.xml
<web-resource-collection>
<url-pattern>*.do</url-pattern>
<http-method>GET</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>POST</http-method>
</web-resource-collection>
inside the <security-constraint> definition. It has the effect that now GET method returns 403 (Forbidden) -- so it's as if this definition would be indeed only constrain the security and is not the means of making it more liberal. I also tried removing the GET and PUT lines but it had no effect on my orginal 405 error (of course it did make GET work again)

You need to make sure that GET POST PUT and DELETE verbs are enabled on the server. Your problem is not client side, so if you have access to server settings just make sure the above verbs are enabled. I am not familiar with jetty, but it looks as though it is not supported out of the box and would require some sort of your own handler. Here is the resource that I found after doing a quick search -> JETTY - PUT DELETE

I finally figured out that the problem was the *.do pattern.
Backbone was adding the .do before the pathvariable, hence it didn't work. I got rid of the postfix entirely and now it works!

Related

Disable access to a Servlet

I'm developing a WebApp using JavaEE and I use a servlet to test some stuff.
Currently, my WebApp is set as when I go to my local url localhost:8080/myApp/test , I can run my test Servlet.
My plan is to deploy my project to a Web and I want to disable the Servlet, but not delete it. I mean, if in the future I visit my remote server via URL www.myNewWeb.com/test , I would like it throws an error od do nothing.
How could I do that?
There are many possible options here:
Option 1
Remove the mapping (annotation #WebServlet or url mapping entry in web.xml). In this case, any attempt to call this servlet will end with an error generated by the JEE container of your choice. It will try to map the servlet to URL, will obviously fail and throw an exception
The obvious drawback of this method is that you need to change the deployment configuration and if you'll want to run the same artifact in another envrironment where this servlet should work you won't be able to do so.
Option 2
Create some kind of configuration, load this configuration along with your application.
In the doGet (just for the sake of example) method do something like this:
public void doGet(request, response) {
if(config.isTestServletEnabled()) { // this is where the data gets read from configuration that I've talked about before
// do your regular processing here
}
else {
// this will happen when the servlet should not be activated
// throw an exception, return HTTP error code of your choice, etc
}
}
This way doesn't have a drawback of the first method that I've explained above, however involves some code to be written.

Spring Security OAuth2 Behind a Proxy Server

There seem to be many examples of Spring Security OAuth2, but most of them run on localhost at some specific set of ports. I was able to get my application working with ports specified for my AuthorizationServer and my ResourceServer. The next step I needed to take was move this application behind a proxy server, but the application stopped functioning. The main issues seem to be path related, but I'm struggling with lack of examples on how to accomplish the task of moving OAuth2 Spring behind a proxy server. I've focused on overriding the WhitelabelApprovalEndpoint, but I'm not sure if this is what is required.
I was able to create a controller that is nearly identical to the WhiteLabelApprovalEndpoint, but do not know how to adapt it to accommodate being behind a proxy.
#Controller
#SessionAttributes("authorizationRequest")
public class ApprovalEndpoint {
#RequestMapping("/oauth/confirm_access")
...
private static String TEMPLATE = "<html><body><h1>OAuth Approval</h1>"
+ "<p>Do you authorize '${authorizationRequest.clientId}' to access your protected resources?</p>"
+ "<form id='confirmationForm' name='confirmationForm' action='authorize' method='post'><input name='user_oauth_approval' value='true' type='hidden'/>%csrf%%scopes%<label><input name='authorize' value='Authorize' type='submit'/></label></form>"
+ "%denial%</body></html>";
...
The only change I made to the class was to update the form action string, making the path relative by replacing
action='${path}/oauth/authorize'
with
action='authorize'
This allows the POST to go to the correct URL
http://localhost/proxy/stuff/javaPath/oauth/authorize
instead of
http://javaPath/oauth/authorize
The latter doesn't map when submitted through Apache (the frontend proxy). But it would seem that this creates other problems in the Java application, because this results in the error
error="invalid_request", error_description="Cannot approve uninitialized authorization request."
I see that this exception is thrown in the AuthorizationEndpoint when the authorizationRequest is null. This looks like it should be handled by my custom class having SessionAttributes set properly, but updating the just the path that I'm POSTing to seems to break this.
May be you already solved it but posting the answer as it may help someone.
It is because authorize end point URL (domain + path(including proxy)) should be consistent. I mean either it should be 'localhost' or your proxy path but it should be consistent.
As OAuth uses session internally and later fetches it from the same path (when the POST happens) . So if the URL changes (POST) it wont get the session then it throws Cannot approve uninitialized authorization request.
For my case ,I was using the authorize end point as:
https://mydomain/myapp/oauth/authorize?grant_type=authorization_code&client_id=clientid&redirect_uri=http://localhost:8181&response_type=code
but in the properties I was having :
server:
session:
cookie:
path: /appProxy
context-path: /myapp
port: 8081
After successful authorization when POST is done on it tries to fetch the session from /appProxy/myapp instead of /myapp and resulting in Cannot approve uninitialized authorization request.
So to solve this, I can either remove Session.cookie.path property or run Oauth server on https://mydomain/appProxy/myapp/oauth/authorize to make it consistent.

ASP.NET MVC, CustomErrors & ResponseRewrite

I have an MVC website (v5, though I don't think it's related) where I have intentionally introduced an error upon when attempting to establish a database connection (wrong server IP in the connection string). When the user hits the HomeController one dependencies for the constructor is a UserRepository (to get the current user profile data) which depends on a database connection/session to be available. When it's not, the Dependency Resolver can't inject the UserRepository and when that happens it causes an error (as it does with any dependency of any controller), and I get a generic "No parameterless constructor defined for this object". Which is pretty useless.
So I'm trying to use a custom error page to retrieve the inner exception and display it in a friendly manner. (Because this error is happening when trying to acquire the HomeController, it never actually reaches the HandleErrorAttribute, hence the relying on CustomErrors).
So I have an ErrorsController with a series of actions...
Snippet from ErrorsComtroller.cs
public ActionResult Error()
{
return View("Error_500");
}
public ActionResult NotFound()
{
return View("Error_404");
}
Snippet from web.config
<customErrors mode="On">
<error statusCode="404" redirect="~/errors/notfound" />
<error statusCode="500" redirect="~/errors/error" />
</customErrors>
The Error_500 page is pretty basic, it has a model type of HandleErrorInfo, but if it's not present it checks for Exception details using Server.GetLastError(). Problem is, GetLastError() is always null, and I get my custom error page but no additional details beyond my generic feedback of "An unexpected error has occured". After doing some digging I found that the method doesn't work after a redirect, which is the default way the CustomErrors functions. So I changed the web.config to use this line instead...
Snippet from web.config
This way it won't cause a redirect and the GetLastError() should have my exception details about the database connection problem. Thing is, now I get the default ASP.NET error page with this message.
An exception occurred while processing your request. Additionally,
another exception occurred while executing the custom error page for
the first exception. The request has been terminated.
So I did some more digging using intellitrace, and I see the exception about the database connection. A little farther down I see the error about not having a parameterless constructor on HomeController and then one about encountering an error trying to create the controller of type 'HomeController'. But then I see one that says
Error executing child request for /errors/error
So I navigated directly to that path and the page works fine. But when it's used in customerrors WITH the ResponseRewrite for the redirectmode, it errors out. I put a break line on the first (and only) line of the ErrorsController.Error() action, but it never gets hit. If I substitute the redirect path in the custom errors to a static file it works, but if I change it back to the ~/errors/error it fails again.
Is there a issue when using MVC actions as url's for the CustomErrors when ResponseRewrite is specified?
"This happens because "ResponseRewrite" mode uses Server.Transfer under the covers, which looks for a file on the file system. As a result you need to change the redirect path to a static file, for example to an .aspx or .html file:"
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx"/>
See: https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
"Apparently, Server.Transfer is not compatible with MVC routes, therefore, if your error page is served by a controller action, Server.Transfer is going to look for /Error/Whatever, not find it on the file system, and return a generic 404 error page!"
See: CustomErrors does not work when setting redirectMode="ResponseRewrite"
In other words, you cannot use ResponseRewrite with views.
This is a well known issue that has been problematic for developers because it does not afford itself to either an easy or elegant solution. Bottom line, MVC does not play nice when using custom views for exception handling and customer user-friendly pages for HTTP errors. The stock error.cshtml file (i.e., a View) in the Views\Shared folder is a great thing to have because it maintains the layout of the web page and provides exception errors. But, when you get HTTP errors then you need to create a view to handle the status code errors (e.g., 404, 500, etc.). Note: if you go the route of sending HTTP errors to a view then the URL line will contain non-ideal info (see weblinks below for further explanation).
You could route HTTP errors to the Error view, but I don't recommend it because the Error view should be for application errors (i..e, exceptions) whereas a separate custom user-friendly page should be created for generic HTTP errors. The difference is that the former is an application problem that the site developer needs to look at whereas the latter is a user error (or at least should be) that does not require the developer to look at it (just my 2 cents).
An alternative is to bypass the views and use custom user-friendly pages for both application exceptions and HTTP errors. But, beware of two problems:
1.) The wrong status code is returned (usually 200), which can be a problem because it will be picked up and indexed by search engines (you do not want this!)
2.) The URL specifies a non-sensical URL in the web browser
These can be handled easy enough. See the following link (go down to the section customErrors in web.config): https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
Below are other weblinks that I also found useful:
http://benfoster.io/blog/aspnet-mvc-custom-error-pages
https://msdn.microsoft.com/en-us/library/bb397417.aspx
https://www.youtube.com/watch?v=nNEjXCSnw6w
How do I display custom error pages in Asp.Net Mvc 3?
The last one appears to be yet another alternative: a custom hack to get around the problem of not being able to couple views with ResponseRewrite. This works by completely bypassing CustomErrors (i.e., CustomErrors mode="Off"). I have not yet tried this yet, but I am looking into it.
Final thought, keep an eye on all site status codes when either error or exception codes are thrown - make sure there are no 200 (i.e., OK) codes.

Difference between / and /* in servlet mapping url pattern

The familiar code:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
My understanding is that /* maps to http://host:port/context/*.
How about /? It sure doesn't map to http://host:port/context root only. In fact, it will accept http://host:port/context/hello, but reject http://host:port/context/hello.jsp.
Can anyone explain how is http://host:port/context/hello mapped?
<url-pattern>/*</url-pattern>
The /* on a servlet overrides all other servlets, including all servlets provided by the servletcontainer such as the default servlet and the JSP servlet. Whatever request you fire, it will end up in that servlet. This is thus a bad URL pattern for servlets. Usually, you'd like to use /* on a Filter only. It is able to let the request continue to any of the servlets listening on a more specific URL pattern by calling FilterChain#doFilter().
<url-pattern>/</url-pattern>
The / doesn't override any other servlet. It only replaces the servletcontainer's built in default servlet for all requests which doesn't match any other registered servlet. This is normally only invoked on static resources (CSS/JS/image/etc) and directory listings. The servletcontainer's built in default servlet is also capable of dealing with HTTP cache requests, media (audio/video) streaming and file download resumes. Usually, you don't want to override the default servlet as you would otherwise have to take care of all its tasks, which is not exactly trivial (JSF utility library OmniFaces has an open source example). This is thus also a bad URL pattern for servlets. As to why JSP pages doesn't hit this servlet, it's because the servletcontainer's built in JSP servlet will be invoked, which is already by default mapped on the more specific URL pattern *.jsp.
<url-pattern></url-pattern>
Then there's also the empty string URL pattern . This will be invoked when the context root is requested. This is different from the <welcome-file> approach that it isn't invoked when any subfolder is requested. This is most likely the URL pattern you're actually looking for in case you want a "home page servlet". I only have to admit that I'd intuitively expect the empty string URL pattern and the slash URL pattern / be defined exactly the other way round, so I can understand that a lot of starters got confused on this. But it is what it is.
Front Controller
In case you actually intend to have a front controller servlet, then you'd best map it on a more specific URL pattern like *.html, *.do, /pages/*, /app/*, etc. You can hide away the front controller URL pattern and cover static resources on a common URL pattern like /resources/*, /static/*, etc with help of a servlet filter. See also How to prevent static resources from being handled by front controller servlet which is mapped on /*. Noted should be that Spring MVC has a built in static resource servlet, so that's why you could map its front controller on / if you configure a common URL pattern for static resources in Spring. See also How to handle static content in Spring MVC?
I'd like to supplement BalusC's answer with the mapping rules and an example.
Mapping rules from Servlet 2.5 specification:
Map exact URL
Map wildcard paths
Map extensions
Map to the default servlet
In our example, there're three servlets. / is the default servlet installed by us. Tomcat installs two servlets to serve jsp and jspx. So to map http://host:port/context/hello
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Doesn't match any extensions, next.
Map to the default servlet, return.
To map http://host:port/context/hello.jsp
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Found extension servlet, return.
Perhaps you need to know how urls are mapped too, since I suffered 404 for hours. There are two kinds of handlers handling requests. BeanNameUrlHandlerMapping and SimpleUrlHandlerMapping. When we defined a servlet-mapping, we are using SimpleUrlHandlerMapping. One thing we need to know is these two handlers share a common property called alwaysUseFullPath which defaults to false.
false here means Spring will not use the full path to mapp a url to a controller. What does it mean? It means when you define a servlet-mapping:
<servlet-mapping>
<servlet-name>viewServlet</servlet-name>
<url-pattern>/perfix/*</url-pattern>
</servlet-mapping>
the handler will actually use the * part to find the controller. For example, the following controller will face a 404 error when you request it using /perfix/api/feature/doSomething
#Controller()
#RequestMapping("/perfix/api/feature")
public class MyController {
#RequestMapping(value = "/doSomething", method = RequestMethod.GET)
#ResponseBody
public String doSomething(HttpServletRequest request) {
....
}
}
It is a perfect match, right? But why 404. As mentioned before, default value of alwaysUseFullPath is false, which means in your request, only /api/feature/doSomething is used to find a corresponding Controller, but there is no Controller cares about that path. You need to either change your url to /perfix/perfix/api/feature/doSomething or remove perfix from MyController base #RequestingMapping.
I think Candy's answer is mostly correct. There is one small part I think otherwise.
To map host:port/context/hello.jsp
No exact URL servlets installed, next.
Found wildcard paths servlets, return.
I believe that why "/*" does not match host:port/context/hello because it treats "/hello" as a path instead of a file (since it does not have an extension).
The essential difference between /* and / is that a servlet with mapping /* will be selected before any servlet with an extension mapping (like *.html), while a servlet with mapping / will be selected only after extension mappings are considered (and will be used for any request which doesn't match anything else---it is the "default servlet").
In particular, a /* mapping will always be selected before a / mapping. Having either prevents any requests from reaching the container's own default servlet.
Either will be selected only after servlet mappings which are exact matches (like /foo/bar) and those which are path mappings longer than /* (like /foo/*). Note that the empty string mapping is an exact match for the context root (http://host:port/context/).
See Chapter 12 of the Java Servlet Specification, available in version 3.1 at http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html.

Accessibility of a servlet class from within an external web.xml file

I have two web applications.But only one among them includes Java servlet class.I want to access that servlet class from within the web.xml file of other application.Is it possible?.If yes,How will be it possible?.
You can't do that in the web.xml. You can however create a new servlet which in turn redirects/forwards the request to the servlet of the other webapplication. Redirecting is easy, just let the URL point to the particular servlet.
response.sendRedirect("/otherwebapp/theservlet");
Forwarding requires a bit more work. This is by default not possible due to security restrictions. First you need to configure the servletcontainer to enable cross context access between the webapplications in question. It's unclear which one you're using, so here's just a Tomcat targeted example so that you understand in what direction you should look for your own servletcontainer: for the both webapps, you need to set the crossContext attribute of the <Context> element to true:
<Context crossContext="true">
This way you can obtain the other context by ServletContext#getContext() inside a servlet:
ServletContext othercontext = getServletContext().getContext("/otherwebapp");
Finally you can forward the request through it as follows:
othercontext.getRequestDispatcher("/theservlet").forward(request, response);

Resources