Wicket + WAS: calling url causes a redirect to a wrong URL causing 404 - websphere

Using Websphere Application Server + Wicket 1.6
I am having some issues with my mounted URLs.
When I invoke an url akin to: localhost:9080/danesCooking/pies/meat I see the following in the Chrome network tab:
localhost:9080/danesCooking/pies/meat status code 302
localhost:9080/danesCooking/meat?2 status code 404
So it seems the /pies/ portion gets lost. This behaviour does not occur when I deploy my application to Tomcat\JBoss\... .
Possibly relevant, pies itself is not a mounted page.
I've already looked through some of the wicket issues\forums and it seems most issues seem to be either resolved\conflicting answers\have to do with relative urls (fixed in 1.5.x).
Has anyone experienced this issue and still recalls how to resolve this?
Used WAS *Versions: 7 and 8.5* liberty.

This issue is actually outlined here;
https://issues.apache.org/jira/browse/WICKET-3258
My resolution to the issue in Wicket 6.9.1 was;
public class MyApplication extends WebApplication {
#Override
public Class<? extends WebPage> getHomePage() {
return MyHomePage.class;
}
/* *********************************************** */
// Resolve Websphere Relative URL "sendRedirect" Bug
#Override
protected WebResponse newWebResponse(WebRequest webRequest, HttpServletResponse httpServletResponse) {
return new FixedServletWebResponse((ServletWebRequest) webRequest, httpServletResponse);
}
/**
* Websphere incorrectly handles relative redirect pages when "HttpServletResponse.sendRedirect(url)" is called.
*
* This small fix ensures that Websphere is only ever provided with absolute URLs so that this issue never occurs.
*/
private static class FixedServletWebResponse extends ServletWebResponse {
private final ServletWebRequest webRequest;
protected FixedServletWebResponse(ServletWebRequest webRequest, HttpServletResponse httpServletResponse) {
super(webRequest, httpServletResponse);
this.webRequest = webRequest;
}
#Override
public String encodeRedirectURL(CharSequence url) {
Url relativeUrl = Url.parse(url);
return new UrlRenderer(webRequest).renderFullUrl(relativeUrl);
}
}
/* *********************************************** */
}

You can also solve that using anonymous class as described in the Configuring and Deploying Open Source with WebSphere Application Server Liberty Profile chapter 5.2.4. (Tested with WLP 8.5.5.3 and Wicket 6.8.0)
Override the following method in your WebApplication class:
#Override
protected WebResponse newWebResponse(final WebRequest webRequest, final
HttpServletResponse httpServletResponse)
{
return new ServletWebResponse((ServletWebRequest) webRequest,
httpServletResponse)
{
#Override
public String encodeRedirectURL(final CharSequence relativeURL)
{
return new UrlRenderer(webRequest).renderFullUrl(Url.parse(relativeURL));
}
};
}
UPDATE
Other solution, instead of code change, is to set the following property in the webcontainer (works in 8.5.5.3):
<webContainer com.ibm.ws.webcontainer.redirectwithpathinfo="true" />

Related

Debug Jersey mapping/routing execution before reaching endpoints/resources

I have been working with Glassfish/Jackson for over a year and I always have this problem when introducing a new endpoint implementation: when the endpoint is not reached and I want to understand why, the only hints I have to go on are the returned request, since the execution doesn't reach the desired endpoint or resource (routing/mapping error).
I want to intercept the Jersey mapping/routing execution before reaching endpoints/resources, with the "raw" request, so that I can better understand resource/endpoint mapping and routing problems.
This answer to a different question, by #xeye, solved this problem for me:
Create a filter that implements ContainerRequestFilter, and override its filter method. This will be where we can intercept all requests for debugging.
// Executed whenever a request is sent to the API server.
// Useful for debugging errors that don't reach the desired endpoint implementation.
#Provider
#Priority(value = 0)
public class MyFilter implements ContainerRequestFilter {
#Context // request scoped proxy
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
try {
// put a breakpoint or log desired attributes of requestContext here.
} catch (Exception e) {
// ignore
}
}
}
Then register this new class in your ConfigResource implementation.
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig(){
register(MyFilter.class);
// ...
}
(It's OK to Ask and Answer Your Own Questions)

How can i ignore some path of vaadin ? /HEARTBEAT /UIDL /VAADIN

I am using a vaadin application with the dashboardemo example
My class does not use a VaadinSevlet but, a VaadinCDIServlet
My webServlet 3.0 I have it so
#WebServlet (asyncSupported = false, urlPatterns = {"/*"},
I will not serve any static content otherwise I would write another
urlpattern as well /VAADIN/*
The problem is that when I visit the path as
/HEARTBEAT/?v-uid=0
/HEARTBEAT
/UIDL/?v-uiId=2
/VAADIN/
/VAADIN/themes/valo/fonts
I get different errors, as I can show some errorView or redirect users to a main view,
The demo dashboard actually redirects some incorrect url or fragments !#blalbla, redirect to
https://domain/myapp/#!dashboard
but with these path does not it, I have reviewed many applications and it happens just the same, whether we are demos or not.please some help?
Update
The solution I recommend for this in case of handling errors 4xx 5xx etc, is to use spring framework, example:. redirect to an external url
#RestController
public class MyController implements ErrorController {
private static final String URL = "http://www.blablaba.com";
#RequestMapping(method = RequestMethod.GET)
#ExceptionHandler(RuntimeException.class)
public void handle(final RuntimeException rex, final HttpServletResponse
hsp) throws IOException {
hsp.sendRedirect(getErrorPath());
}
#Override
public String getErrorPath() {
return URL;
}
}
Im not sure the approach they took in the demo but this is what comes to my mind. In your ErrorView you can call UI.getCurrent().getNavigator() and then redirect to the desired URL by getting the URL from the Page.getCurrent() object then running Navigator.navigateTo().

Spring Session not working on Tomcat 8 when using Tiles - SESSION Cookie is not set as response is already included

I am using Spring Session 1.2.0.RELEASE on a Spring Boot Project. This is packaged as a war and deployed on Tomcat 8.
I have followed Spring Session documentation and configured it properly. The problem is that the entry point to the application is a controller that sets some value on session but the SESSION cookie is not sent to the browser.
Debugging I see that:
org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession() tries to write the cookie:
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue() sets the cookie in the response:
response.addCookie(sessionCookie);
The cookie isn't actually written. The underlying response object is org.apache.catalina.core.ApplicationHttpResponse. Its addCookie() method is:
/**
* Disallow <code>addCookie()</code> calls on an included response.
* #param cookie The new cookie
*/
#Override
public void addCookie(Cookie cookie) {
if (!included)
((HttpServletResponse) getResponse()).addCookie(cookie);
}
The problem is that included attribute, which at some point is set true, preventing the cookie from being added.
This happens when the jsp (using tiles) is being serviced:
UPDATE:
This is the moment when the response is being marked as included (when standard.jsp tiles layout is inserting an attribute:
<tiles:insertAttribute name="header" ignore="false"/>
To work around this problem I ended up creating a filter to enforce the creation of the session.
As seen, the first call to the controller didn't add the cookie because during the Tiles-JSP rendering the response was already marked as included. What I do is forcing the creation of the session in the filter and redirecting asking the very same requestURI. This way, since the call doesn't involve a tiles rendering the cookie is created and can be used right away in the next calls.
#Bean
#ConditionalOnExpression("${sessionEnforcerFilter.enabled:true}")
public FilterRegistrationBean sessionEnforcerFilter(){
logger.info("Registering sessionEnforcerFilter");
FilterRegistrationBean frb = new FilterRegistrationBean();
frb.setName("sessionEnforcerFilter");
frb.setFilter(new SessionEnforcerFilter());
frb.setUrlPatterns(Arrays.asList(new String[]{"/*"}));
return frb;
}
public class SessionEnforcerFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
if(httpServletRequest.getSession(false)==null){
logger.debug("sessionEnforcerFilter.doFilter () - Session is null - forcing its creation");
httpServletRequest.getSession();
String requestURI = httpServletRequest.getRequestURI();
logger.debug("sessionEnforcerFilter.doFilter () - Repeating request [{}]", requestURI);
httpServletResponse.sendRedirect(requestURI);
}else{
chain.doFilter(httpServletRequest, response);
}
}
#Override
public void destroy() {}
}
summary
Hold breakPoint in SessionRepositoryResponseWrapper.onResponseCommitted().
Check that the response object inside the SessionRepositoryRequestWrapper is a non-wrapped response. (included = false)
If it is a wrapped response object, make sure that the sessionRepositoryFilter comes first.
================
Spring-session is already handling the problem when 'DispatcherType.INCLUDE (included = true)'.
SessionRepositoryResponseWrapper.onResponseCommitted() is trying to addCookie to the original response object.
The sessionRepositoryFilter must be in the first position to wrap the original applicationHttpResponse passed by tomcat.
Problem Situation
The SessionRepositoryRequestWrapper receives the wrapped response and holds it.
When executing doInclude() in the servlet container, find the original reponse and wrap it with ApplicationHttpResponse (included = true).
Then, SetResponse (new wrapping response) to the innermost wrapper.
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.doInclude%28javax.servlet.ServletRequest%2Cjavax.servlet.ServletResponse%29
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat.embed/tomcat-embed-core/8.0.24/org/apache/catalina/core/ApplicationDispatcher.java#ApplicationDispatcher.wrapResponse%28org.apache.catalina.core.ApplicationDispatcher.State%29
Spring-session does an addCookie on the response (expecting the original response) stored in SessionRepositoryResponseWrapper.onResponseCommitted(), but it can not because it is set to 'included = true'.

Serving Static Content from same directory as service - Dropwizard

I am building a Dropwizard app to replace a legacy webserver, due to a lot of links pointing at this server, I have to be backwards compatible and support all kinds of resources that the legacy server used to serve.
The problem is that I have a bunch of static JS files being served from the same directory/path as the services themselves. Apparently you can't serve both types (service and static) from a single directory. so if I add the static bundle (now located in the resources directory), like so:
bootstrap.addBundle(new AssetsBundle("/javascript", "/media"));
The dynamic services (served from /media/) start returning 404
if I comment it, the dynamic services work fine.
As I said, I can't change any of the links, static or dynamic...
Any suggestions?
Update:
Resolved, here is a working example inspired by #airborn 's answer, this question which also pointed me to this module, which claims to solve this problem generically.
This example will apply a filter to ALL incoming requests, and allow you to redirect to wherever you want (similar to .htaccess functionality on apache).
Place the following line in the run function your main dropwizard class (the one that extends **Service<AppConfiguration> **
environment.addFilter(new UrlRewriteFilter(),"/*");
Place this class somewhere accessible to the above class
#WebFilter
public class UrlRewriteFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
//
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String requestURI = request.getRequestURI();
// Place Redirection logic here (else continues the filter chain).
if (redirectConditionTrue)
String newURI = ""//New URl to do to;
req.getRequestDispatcher(newURI).forward(req, res);
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {
//
}
}
Using Environment in your Service class, you should be able to add a filter to Jetty. In this proxy filter, you should be able to detect those js files and redirect them to the new location.

Encoded slash (%2F) with Spring RequestMapping path param gives HTTP 400

This is not a duplicate referenced question, because it is Spring specific. Whoever added that (3 years after the fact!) didn't bother to read the question or comment thread to see what the real answer was. The accepted answer isn't quite the answer, but the author of the answer never came back and edited it like I asked.
Given the restful method below, Spring 3.1 gives a 400 error with "The request sent by the client was syntactically incorrect ()." when the token parameter contains a URL encoded slash (%2F), for example "https://somewhere.com/ws/stuff/lookup/resourceId/287559/token/R4o6lI%2FbBx43/userName/jim" Without the %2F everything works fine. A 3rd party is already calling this service (of course!) so I can't change what they send, in the short term at least. Any ideas on how to work around this on the server side?
This problem is described very well here https://jira.springsource.org/browse/SPR-8662 though that issue is related to UriTemplate which I am not using that I can tell.
#RequestMapping("/ws/stuff/**")
#Controller
public class StuffController {
#RequestMapping(value = "/ws/stuff/lookup/resourceId/{resourceId}/token/{token}/userName/{userName}", method = RequestMethod.GET)
public #ResponseBody
String provisionResource(#PathVariable("resourceId") String resourceId, #PathVariable("token") String token, #PathVariable("userName") String userName, ModelMap modelMap,
HttpServletRequest request, HttpServletResponse response) {
return handle(resourceId, userName, request, token, modelMap);
}
}
Note: This is on Glassfish 3.1.2, and at first it was Grizzly/Glassfish not accepting the slash, but
-Dcom.sun.grizzly.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
fixed that.
asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-2.http.encoded-slash-enabled=true
didn't seem to help.
for spring-boot, the following did the trick
#SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
SpringApplication.run(Application.class, args);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setUrlDecode(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
This could be your answer: urlencoded Forward slash is breaking URL
I would suggest not putting that in the path, move it to a request param instead.
Work around:
You could change the RequestMapping to
#RequestMapping(value = "/ws/stuff/lookup/resourceId/**", method = RequestMethod.GET)
and then parse the path variables manually from the request object.
2019 Update for Spring Boot 2+ / Spring (Security) 5+ / Java 8+:
As my edit to iamiddy's answer was rejected I want to also provide the complete solution for Spring Boot 2 + as an separate answer.
The WebMvcConfigurerAdapter is deprecated with Spring5 / Java8 and can be replaced directly with the Interface WebMvcConfigurer ending up with:
#SpringBootApplication
public class Application extends WebMvcConfigurer {
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
SpringApplication.run(Application.class, args);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setUrlDecode(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
Plus you also need to configure Spring's (Strict)HttpFirewall to avoid the blocking of encoded slashes with the error message The request was rejected because the URL contained a potentially malicious String "%2F"
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
Spring Boot will use the above HttpFirewall Bean when available - otherwise it might be necessary to configure the WebSecurity as mentioned here:
For spring boot application this worked for me..
Version 1
Add
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
to your application.properties file
Version 2
run your spring boot application like this.
static void main(String[] args) {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
SpringApplication.run this, args
}
Version 3 or run your java application with
-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
This fixed %2F encoded slash path variable for me.
Here is a fix for Spring 3.2.4 (should work for other versions as well). One must overwrite the default UrlPathHelper
public class UrlPathHelperFixed extends UrlPathHelper {
public UrlPathHelperFixed() {
super.setUrlDecode(false);
}
#Override
public void setUrlDecode(boolean urlDecode) {
if (urlDecode) {
throw new IllegalArgumentException("Handler [" + UrlPathHelperFixed.class.getName() + "] does not support URL decoding.");
}
}
#Override
public String getServletPath(HttpServletRequest request) {
return getOriginatingServletPath(request);
}
#Override
public String getOriginatingServletPath(HttpServletRequest request) {
return request.getRequestURI().substring(request.getContextPath().length());
}
}
And inject it to the Mapping Handler:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="order" value="-1"></property>
<property name="urlPathHelper">
<bean class="com.yoochoose.frontend.spring.UrlPathHelperFixed"/>
</property>
</bean>
After a day of hard works it works now for me :-)
It was suggested to Spring team as https://jira.springsource.org/browse/SPR-11101
I have found this solution which is working for me;
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
just before
springApplication.run(args);
and add below code in Application class
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setUrlDecode(false);
configurer.setUrlPathHelper(urlPathHelper);
}
We just ran into this issue at my office, we did what was suggestion above from what Solubris said where you put it in a query param. The only additional requirement is that the data could have an '&' as well, which would mess up the query param. All we had to do is encode the text before it is sent in the URL and even '&' were filtered out.
Another answer would be to encode "/" twice, which would produce "%252F". In your mapped endpoint, Spring will decode it back to "%2F". All you need more is to decode it one more time using something like this:
URLDecoder.decode(encoded_URL, "UTF-8");
The following resolved the BACK_SLASH issue:
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
SpringApplication.run(Application.class, args);
}
But, same functionality could be done via application.yml.
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true
This setting doesn't work. I did not find a way for that, and still looking at it.
In order to avoid parsing the variables manually I did the following:
Add the following before executing any other code:
System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
And in the controller, add 2 variables instead one, for example:
#RequestMapping(value = "/api/devices-by-name/device={deviceId}/restconf/data/ietf-interfaces:interfaces-state/interface={dpuIdPrefix}/{dpuIdSuffix}",
method = RequestMethod.GET,
produces = "application/json")
public ResponseEntity<String> getInterfaceState(#PathVariable(value = "deviceId") String deviceId,
#PathVariable(value = "dpuIdPrefix") String dpuIdPrefix,
#PathVariable(value = "dpuIdSuffix") String dpuIdSuffix) {
String dpuId = dpuIdPrefix + "/" + dpuIdSuffix;
And with that I can retrieve the following:
curl -s -X GET http://localhost:9090/api/devices-by-name/device=ZNSDX16DPU03/restconf/data/ietf-interfaces:interfaces-state/interface=gfast%200%2F14
If the slash is optional, then you might need to configure two different request mappings.

Resources