Multiple forward slashes in request mapping in spring - spring

#RestController
#RequestMapping("/api")
public class AbcController {
#RequestMapping(value = "/abc", method = RequestMethod.GET)
public String abc(){
return "Hello";
}
}
Valid URL: http://localhost:8080/api/abc
Invalid URls:
http://localhost:8080////api/abc
http://localhost:8080/////api////abc
http://localhost:8080/////////api/////abc
Problem: My controller is accepting all above urls. I want to restrict it and accept only valid url and throw error on invalid urls.
Note: I'm not using any custom routing. It's default spring has.

The simplest way is to add custom handler interceptor to validate the url.
public class ValidateURLInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (isValidUrl(request.getRequestURI())) {
return true;
}
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid URL");
return false;
}
private static boolean isValidUrl(String url) {
return !url.contains("//");
}
}
And then update the MVC configuration
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ValidateURLInterceptor());
}
}

Add maven dependency for spring security and use below code to allow access to all the paths without logging in.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/**");
}
}

Related

Swagger UI does not show Params

I've got a Spring-Application (2.1.0.RELEASE) and added Swagger and Swagger-UI (2.9.2).
I have a SwaggerConfig class, that I copied from the Baeldung tutorial
Then, there is the App class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
#EnableAutoConfiguration
public class App
{
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
And there is the actual REST controller:
#RestController
public class TweetRating {
#GetMapping("/{userid}/tweet")
public static void getTweet(#PathVariable String userid){
System.out.println("UserID: "+ userid);
}
#GetMapping("/")
public static void isWorking(#RequestParam String id){
System.out.println("ID: "+ id);
}
}
The Swagger-UI just won't show the params of the methods. Neither the PathVariable not the RequestParam. Therefore, the "Try it out" function does not make any sense, of course. It looks like this:
Screenshot1
Screenshot2
Why is that and how can I solve it?
Try to apply enableUrlTemplating(true) in you SwaggerConfig :
#Configuration
#EnableSwagger2
public class SwaggerConfig {                                   
    #Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2) 
          .select()                                 
          .apis(RequestHandlerSelectors.any())             
          .paths(PathSelectors.any())  
.enableUrlTemplating(true)                       
          .build();                                          
    }
Also try this one :
#ApiOperation(value = "Dexcription of endpoint")
#RequestMapping
public String doSomething(#ApiParam(value = "Description of path vaiable")#PathVariable("/{code}")

Custom web filter for specific controllers

Help me please, or show other ways to resolve this problem.
#RestController
#RequestMapping("/users")
public class UserController {
#RequestMapping("/login")
public String logIn() {
return "";
}
#RequestMapping("/getUserData")
#FilterThisRequest
public String getUserData(#PathVariable Long userId) {
return user;
}
}
And I have AuthFilter extends GenericFilterBean which makes a certain logic. How can I make that the filter execute only before methods which have #FilterThisRequest? Or there are better practices to resolve this problem?
Check FilterRegistrationBean reference guide at https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners-beans.
Make FilterRegistrationBean available to Spring via a #Configuration class, the below example will ensure that authFilter runs only for /getUserData. Note that it is URL (and not method) based filtering.
#Autowired AuthFilter authfilter;
....
....
#Bean
public FilterRegistrationBean authFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean(authfilter);
registration.addUrlPatterns("/web-app-name/getUserData/");
return registration;
}
I would suggest you for the Interceptor.
#Configuration
public class Config extends WebMvcConfigurerAdapter {
#Autowired
RequestInterceptor requestInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor).addPathPatterns("/getUserData","/user");
}
}
Interceptor -
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object object) throws Exception {
}
You can override Interceptor's prehandle and postHandle according to your need.

Custom AbstractEndpoint listening to "/" (root)

I've implemented a starter that configures Swagger the way I like. In addition, I'd like to redirect every call to the app's root URL (e.g. localhost:8080) to /swagger-ui.html.
Therefore, I added an own AbstractEndpoint which is instantiated in the #Configuration class as follows:
#Configuration
#Profile("swagger")
#EnableSwagger2
public class SwaggerConfig {
...
#Bean
public RootEndpoint rootEndpoint() {
return new RootEndpoint();
}
#Bean
#ConditionalOnBean(RootEndpoint.class)
#ConditionalOnEnabledEndpoint("root")
public RootMvcEndpoint rootMvcEndpoint(RootEndpoint rootEndpoint) {
return new RootMvcEndpoint(rootEndpoint);
}
}
The respective classes look like this:
public class RootEndpoint extends AbstractEndpoint<String> {
public RootEndpoint() {
super("root");
}
#Override
public String invoke() {
return ""; // real calls shall be handled by RootMvcEndpoint
}
}
and
public class RootMvcEndpoint extends EndpointMvcAdapter {
public RootMvcEndpoint(RootEndpoint delegate) {
super(delegate);
}
#RequestMapping(method = {RequestMethod.GET}, produces = { "*/*" })
public void redirect(HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.sendRedirect("/swagger-ui.html");
}
}
As stated in public RootEndpoint(), the custom Endpoint is bound to /root. Unfortunately, I can't specify super(""); or super("/"); as those values throw an exception (Id must only contains letters, numbers and '_').
How can I achieve having a custom Endpoint listening to the root URL in a starter using #Configuration files to instantiate beans?
I solved it with an easier approach by adding a WebMvcConfigurerAdapter bean in the #Configuration:
#Bean
public WebMvcConfigurerAdapter redirectToSwagger() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("").setViewName("redirect:/swagger-ui.html");
}
};
}

Adding patterns to addResourceHandler always returned error when want to serve static content

I went through all question here, all docs according to Spring and couldn't find solution which make my case work.
The case is that I would like to secure my application (Spring Boot with Angular 4) by Spring Security. So the first things which I did was to add two Configuration classes, ex:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.anyRequest().permitAll().and().httpBasic();
}
#Configuration
#EnableWebMvc
#ComponentScan("com.inventory")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/", "/#/", "/resources/static/**")
.addResourceLocations("/resources/static/index.html", "/resources/static/index.html", "/resources/static/index.html");
}
}
#Controller
public class ViewController {
#RequestMapping(value = "/#/")
public String index() {
return "forward:/resources/static/index.html";
}
#RequestMapping(value = "/")
public String home() {
return "index.html";
}
}
As you see in Controller I tried to use to diffrent attempts to serve static content. Unfortunately all this returns:
There was an unexpected error (type=Internal Server Error, status=500).
Could not resolve view with name 'index.html' in servlet with name 'dispatcherServlet'
What am I doing wrong? Why I can't get this static content? Of course my static content is under resources/static and there are .js files and ex. index.html.

vaadin + spring boot: Cannot forward to error page for request

By single view application vaadin 7.7.7, spring-boot 1.5 i check uri fragment https:/tld/#!category-name-1 from user and if the category exist show items and if not
VaadinService.getCurrentResponse().sendError(404, "page not found!");
but i got error after update spring-boot 1.5 and vaadin 7.7.7 (with embeded tomcat):
Cannot forward to error page for request [/vaadinServlet/UIDL/] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
How can i send http error pages from vaadin to user?
ErrorPageCutomizer.java
#Component
public class ErrorPageCutomizer implements EmbeddedServletContainerCustomizer {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
}
}
RestController.java
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ErrorHandlingController implements ErrorController {
private static final String PATH = "/error";
#RequestMapping(value = PATH + "/404")
public String error404() {
return "<div style='font-weight:bold; margin-top:200px; text-align:center; font-size:160%;'>Page not found...<br>to home</div>";
}
#RequestMapping(value = PATH + "/500")
public String error500() {
return "<div style='font-weight:bold; margin-top:200px; text-align:center; font-size:160%;'>500 Internal server error...</div>";
}
#Override
public String getErrorPath() {
return PATH;
}
}
Soliution was:
#Configuration
public class AppInitializer implements WebApplicationInitializer {
#Bean
public ErrorPageFilter errorPageFilter() {
return new ErrorPageFilter();
}
#Bean
public FilterRegistrationBean disableSpringBootErrorFilter(ErrorPageFilter filter) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
}
Have you tried the SystemMessagesProvider. In that provider you could define an errorUrl for a variety of errors:
public class YourServlet extends VaadinServlet
{
#Override
protected void servletInitialized() throws ServletException
{
super.servletInitialized();
getService().setSystemMessagesProvider(new SystemMessagesProvider()
{
#Override
public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo)
{
final CustomizedSystemMessages c = new CustomizedSystemMessages();
final String errorUrl = "<url to errorpage>";
c.setSessionExpiredURL(errorUrl);
c.setSessionExpiredNotificationEnabled(false);
c.setAuthenticationErrorURL(errorUrl);
c.setAuthenticationErrorNotificationEnabled(false);
c.setCommunicationErrorURL(errorUrl);
c.setCommunicationErrorNotificationEnabled(false);
c.setCookiesDisabledURL(errorUrl);
c.setCookiesDisabledNotificationEnabled(false);
c.setInternalErrorURL(errorUrl);
c.setInternalErrorNotificationEnabled(false);
c.setSessionExpiredURL(errorUrl);
c.setSessionExpiredNotificationEnabled(false);
return c;
}
});
}

Resources