I'm wondering if there is any pattern or implementation that allows me to enable/disable all the controllers at once of a given spring boot application by using a simple boolean variable that was provided by another feature flags service.
I'm thinking of putting a conditional check in each of the controller paths but it's a really bad way of doing it.
Thanks in advance
You can define custom Filter and register that. Sample Filter code at.
public class RequestAllowDenyFilter implements Filter {
private boolean isAllowed = true;
public RequestAllowDenyFilter(boolean isAllowed) {
this.isAllowed = isAllowed;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (isAllowed) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
}
}
}
Then when you register filter you need to pass do you want to allow/deny request.
#Value("${request.enabled:true}")
private boolean isEnabled;
#Bean
public FilterRegistrationBean<RequestAllowDenyFilter> loggingFilter() {
FilterRegistrationBean<RequestAllowDenyFilter> registrationBean
= new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestAllowDenyFilter(isEnabled));
registrationBean.addUrlPatterns("/**");
registrationBean.setOrder(0);
return registrationBean;
}
You need to define request.enabled in application.properties file. Either true/false based on what you want to do.
Related
I have a series of Rest API Controllers in my Spring boot application with Request Mappings that match certain URLs.
I need to change my implementation to always make sure that a specific custom header is in place for all requests. If header is not there I want to fail the request. If it is I want to forward to the appropriate controller which would be the same as my current implementation.
Is there a way to do this in Spring Boot without modifying my existing controllers at all? Could I try to use something like Spring Security, even though my header is not related to security at all?
Thank you.
Web MVC defines an abstraction called "HandlerInterceptor" and its no-op implementation HandlerInterceptorAdapter
So you can register the bean that looks like this:
#Component
public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// check the headers, extract them from request, whatever
return true; // if you want to proceed to controller
return false;// otherwise :)
}
}
This will instruct spring mvc to call the method before the flow gets to the controller.
You can configure a Filter as a #Service.
#Service
#NoArgsConstructor #Log4j2
public class FilterImpl implements Filter {
#Override
public void init(FilterConfig config) throws ServletException { }
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request.getHeader("required-header-name") != null) {
chain.doFilter(request, response);
} else {
log.info("Rejected {}", request);
}
}
#Override
public void destroy() {
}
}
in our application we are creating request filters which should not be hit for some urls. We want be able to exclude urls like spring do witch url patterns, e.g.:
// register filter in bean
FilterRegistrationBean filterBeanRegistration = new FilterRegistrationBean();
filterBeanRegistration.setFilter(myFilter());
filterBeanRegistration.addInitParameter("excluded", "*/foo/**, */bar/**");
...
and new filter doesn't hit urls like domain:8080/aaa/foo/xxxx, domain:8080/bbb/bar/xxxx .
Can you tell me how to do that with spring classes or another simple way? Thank you in advice.
EDIT:
There is FilterBeanRegistration#addUrlPatterns(String... urls) method where I can specify urls, but there is no any format which tells which url should hit. For our purposes is better exclude some urls.
You can use org.springframework.web.filter.OncePerRequestFilter. It gets executed once every incoming request. You can override shouldNotFilter method to exclude the URLs you don't want the filter to run for. Example code:
public class MyFilter extends OncePerRequestFilter {
private static final String[] excludedEndpoints = new String[] {"*/foo/**, */bar/**"};
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return Arrays.stream(excludedEndpoints)
.anyMatch(e -> new AntPathMatcher().match(e, request.getServletPath()));
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Filtering logic goes here. call below line on successful authentication.
filterChain.doFilter(request, response);
}
}
Is it possible in the Spring Security to (well it is Java, of course possible, so quesiton is - is it possible in some relatively painless way) automatically authorize all requests from local host (OK, some given IP) as a request that belongs to a given test user.
For instance in some filter - take all requests, check IP and if it comes from local host say something like spring.authorizeAs("user")
This answer for the similar question may help you. Based on your requirements you build principal and set it manually to Security Context.
In my case answer is following
#Component
public class LocalAuthFilter implements Filter {
#Autowired
private UserDetailsService mng;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
if (("127.0.0.1".equals(req.getRemoteAddr())) &&
("anonymousUser".equals(SecurityContextHolder.getContext().getAuthentication().getPrincipal()))) {
UserDetails userDetails = mng.loadUserByUsername("user"); //my test user
Authentication auth = new UsernamePasswordAuthenticationToken(
userDetails.getUsername(),
userDetails.getPassword(),
userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(req, resp);
}
#Override
public void destroy() {
}
}
Need help on the basics -
I have integrated Angular and Spring Boot.
I made production build of the Angular app and copied the 6 files in the Spring boot static resource folder.
By default when I hit localhost:8080 index.html is rendered as Spring boot Automatically registers it as welcome page.
Now when i am inside angular i can navigate to different component via ANGULAR ROUTER and the url is also changing.
But when i copy the same URL for example - localhost:8080/myTask and enter it in url address bar it throws 404 resource not found.
Because it hits the Spring controller first and since there is no mapping for that it fails.
In the class where you have extended WebMvcConfigurerAdapter in Spring Boot, inside addViewControllers method, you should do something like this
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/myTask").setViewName("forward:/");
}
for forwarding, all request, you can do registry.addViewController("/**").setViewName("forward:/");
Update Thanks Jonas for the Suggestion. Since WebMvcConfigurerAdapter is deprecated in Spring 5.0, you can implement the above logic by extending WebMvcConfigurer
// the perfect solution(from jhipster)
#Controller
public class ClientForwardController {
#GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
If you don't use Spring MVC (for example, you are using Jersey), you can also solve this by using a javax.servlet.Filter:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class AngularRoutingFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = ((HttpServletRequest) request);
String requestURI = httpServletRequest.getRequestURI();
if (shouldDispatch(requestURI)) {
request.getRequestDispatcher("/").forward(request, response);
} else {
chain.doFilter(request, response);
}
}
#Override
public void init(FilterConfig filterConfig) {}
#Override
public void destroy() {}
private boolean shouldDispatch(String requestURI) {
/* Exclude/Inlclude URLs here */
return !(requestURI.startsWith("/api") || requestURI.equals("/"));
}
}
I am trying to create filter that should be invoked on every request and check if user is authorizated. My implementation is text-book like.
#WebFilter("/*")
public class MiddleWareAuth implements Filter {
#Override
public void destroy() {
// ...
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("hi");
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String xHeader = ((HttpServletRequest)request).getHeader("Authorization");
System.out.println("I am here");
System.out.println(xHeader);
}
}
However what troubles me is that i am not sure where i should register the filter, to let spring know that it should put every request through it.
I read that i should use <filter> tag in web.xml file , however my project does not have such file.
I am running my project on intelij 2017.
Where should i let spring know to register my filter?
Thanks for help!.