How to disallow TRACE http method in spring boot actuator - java

I have a server on port = 8078 and spring boot actuator on port = 8081.I want to disable TRACE Http method on both. I already create customizer bean(see below). But with this bean I disallowed only Trace on 8078. It's looks like actuator doesn't see this bean. How to disable TRACE http method on management server?
#ManagementContextConfiguration
public class CustomUndertowCustomizer {
#Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> undertowCustomizer() {
return (factory) ->
factory.addDeploymentInfoCustomizers(deploymentInfo ->
deploymentInfo.addInitialHandlerChainWrapper(handler -> {
HttpString[] disallowedHttpMethods = {HttpString.tryFromString("TRACE"),
HttpString.tryFromString("TRACK")};
return new DisallowedMethodsHandler(handler, disallowedHttpMethods);
}));
}
}

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
#Component
public class Filter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain)
{
try {
if (req.getMethod().equals("TRACE")) {
res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
} else {
filterChain.doFilter(req, res);
}
} catch(Exception e){}
}
}

Related

Spring boot Interceptor dont show #ControllerAdvice errorhandler?

Implemetation: Im trying to implementin project with Interceptor but the Error handling in showing only in Terminal which is good but i need also to show in restapi in postman and its showing empty.
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class WebInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(WebInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
logger.error("WebInterceptor preHandle is now logged");
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
logger.error("WebInterceptor posthandle is now logged");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
logger.error("WebInterceptor afterCompletion is now logged");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class AppConfig implements WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new WebInterceptor()).addPathPatterns("/cart/**").order(1);
registry.addInterceptor(new WebInterceptor()).addPathPatterns("/product/**").order(2);
}
}
import com.kongapigateway.KongAPIgateway.ModelException.DATE_FORMAT_ERROR;
import com.kongapigateway.KongAPIgateway.ModelException.ProductExecption;
import com.kongapigateway.KongAPIgateway.ModelException.ProductIDnotFound;
import com.kongapigateway.KongAPIgateway.ModelException.ProductValueNotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
#RestControllerAdvice
public class WEbAspectExceptionConfig {
private Logger logger = LoggerFactory.getLogger(WEbAspectExceptionConfig.class);
#ExceptionHandler(ProductValueNotNull.class)
#ResponseStatus
public void handle(ProductValueNotNull e) {
logger.error(e.getMessage());
}
#ExceptionHandler(DATE_FORMAT_ERROR.class)
#ResponseStatus
public void handle2(DATE_FORMAT_ERROR e) {
logger.error(e.getMessage());
}
#ExceptionHandler(ProductExecption.class)
#ResponseStatus
public void handle2(ProductExecption e) {
logger.error(e.getMessage());
}
#ExceptionHandler(ProductIDnotFound.class)
#ResponseStatus
public void handle2(ProductIDnotFound e) {
logger.error(e.getMessage());
}
}
Terminal Output:
This is the error handling message: Please input all field
kongapigateway | 2022-06-07 11:21:33.149 INFO 1 --- [nio-8095-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
kongapigateway | 2022-06-07 11:21:33.161 ERROR 1 --- [nio-8095-exec-1] c.k.K.Interceptor.WebInterceptor : WebInterceptor preHandle is now logged
kongapigateway | 2022-06-07 11:21:33.277 ERROR 1 --- [nio-8095-exec-1] c.k.K.AOP.WEbAspectExceptionConfig : Please input all field
kongapigateway | 2022-06-07 11:21:33.277 ERROR 1 --- [nio-8095-exec-1] c.k.K.Interceptor.WebInterceptor : WebInterceptor afterCompletion is now logged
Postman api error handler is Empty
Shown here
Kindly disregard this Post Question.
I used Spring AOP #Around for customize exception.
Thank you.

Handling Errors in a Spring Boot Controller

I want to process an error in the controller, I looked at how it is done, but the error is not processed, tell me what's wrong.
Controller
#ControllerAdvice
public class ErrorController {#ExceptionHandler(ResourceNotFoundException.class)
public String notFound(){
System.out.println("Hello");
return "error/not_found";
}
}
Exeption
public final class ResourceNotFoundException extends RuntimeException {
ResourceNotFoundException(String message){
super(message);
}
}
Filter where I return an error
package com.example.demo.HttpErrorConfig;
import com.example.demo.Controllers.web.ErrorController;
import com.example.demo.Exception.ResourceNotFoundException;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HttpStatusFilter extends GenericFilterBean {
private final HttpStatusProvider httpStatusProvider =
new HttpStatusProvider();
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
int status = httpStatusProvider.getStatus((HttpServletResponse) servletResponse);
filterChain.doFilter(servletRequest,servletResponse);
if (status==404){
System.out.println(404);
throw new ResourceNotFoundException("e");
}
}
}

Spring-boot: Apply Servlet Filter to all routes except one

A question for spring-boot gurus!
Use Case:
I want my application to behave differently depending on following routes:
/ no authentication, no authorization
/render authorization via a json web token (jwt) sent as an URL parameter (I know, it's weird)
any other routes: authorization via a json web token (jwt) sent as an URL parameter (I know, it's weird)
The secret for the jwt is stored as an element of the application configuration (application.yaml) (I'm aware that this is not best practice, it's a demo app so I don't care)
I'm using SpringBoot 2.0.5 and io.jsonwebtoken as the jwt library.
I've implemented it using a Servlet Filter, and it is working, but it feels really ugly. I couldn't find a way to say 'Apply this Servlet Filter to all endpoints except this list'. I've resorted to including the logic within the doFilter method, but this seems really ugly.
Is there a 'best practise' for this?
My current code is as follows:
SecurityConfiguration
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/render").permitAll()
.anyRequest().authenticated();
httpSecurity.headers().frameOptions().disable();
}
}
WebConfigurer
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;
#Configuration
public class WebConfigurer implements ServletContextInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initFilter(servletContext, disps);
}
private void initFilter(ServletContext servletContext,
EnumSet<DispatcherType> disps) {
FilterRegistration.Dynamic myFilter =
servletContext.addFilter("myFilter",
new JWTAuthenticationFilter());
myFilter.addMappingForUrlPatterns(disps, true, "/app/*");
myFilter.setAsyncSupported(true);
}
}
JWTAuthenticationFilter
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.TextCodec;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class JWTAuthenticationFilter extends GenericFilterBean {
#Value("${security.jwt.token.secret-key}")
private String secret;
#Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
String path = request.getRequestURI();
if (!path.equals("/")) {
String jwsString = request.getParameter("jwt");
Jws<Claims> jws;
String base64_encoded_secret = TextCodec.BASE64.encode(secret);
jws = Jwts.parser()
.setSigningKey(base64_encoded_secret)
.parseClaimsJws(jwsString);
}
} catch (Exception e) {
System.out.println(e);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
}
Found the solution! I used a FilterRegistrationBean. There is no way to exclude URLs. My solution is to put all the app under the app/ directory, so I didn't need to put a filter on the root /.
#Bean
public FilterRegistrationBean FilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(1);
registration.addUrlPatterns("/app/*");
return registration;
}

Javax WebSockets won't work with programmattic Tomcat 7 instantiation

Here's what I'm trying to do:
Set up a Tomcat 7 server programmatically - that works with a simple servlet. I'm defining Tomcat's endpoints from within the code only, there are no settings nor routers on the file system (this is a constraint).
Have the said Tomcat server include a websocket server endpoint using Javax Websockets API (1.1) - that doesn't work.
My app/server entry point:
package com.myapp;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
import org.apache.catalina.startup.Tomcat;
public class App
{
public static void main(String[] args) throws LifecycleException
{
int port = 8080;
Tomcat webServer = new Tomcat();
webServer.setPort(port);
webServer.setHostname("localhost");
String appBase = ".";
webServer.getHost().setAppBase(appBase);
File docBase = new File(System.getProperty("java.io.tmpdir"));
Context context = webServer.addContext("", docBase.getAbsolutePath());
// both MyServlet and MyFilter exist and work.
Class servletClass = MyServlet.class;
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
context.addServletMapping("/my-servlet/*", servletClass.getSimpleName());
Class filterClass = MyFilter.class;
FilterDef myFilterDef = new FilterDef();
myFilterDef.setFilterClass(filterClass.getName());
myFilterDef.setFilterName(filterClass.getSimpleName());
context.addFilterDef(myFilterDef);
FilterMap myFilterMap = new FilterMap();
myFilterMap.setFilterName(filterClass.getSimpleName());
myFilterMap.addURLPattern("/my-servlet/*");
context.addFilterMap(myFilterMap);
webServer.start();
webServer.getServer().await();
}
}
My websocket server endpoint class:
package com.myapp;
import java.nio.ByteBuffer;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/web-socket/")
public class WebSocket
{
#OnOpen
public void onOpen()
{
System.out.println("Open Connection ...");
}
#OnMessage
public static void onTextMessage(Session session, String msg) {
System.out.println("On Message for Web Socket");
}
#OnMessage
public void onBinaryMessage(Session session, ByteBuffer msg){
System.out.println("On Message for Web Socket");
}
#OnMessage
public void onPongMessage(Session session, PongMessage pMsg) {
System.out.println("On Message for Web Socket");
}
#OnClose
public void onClose(Session session) {
System.out.println("Connection Close for Web Socket");
}
#OnError
public void onError(Throwable e)
{
e.printStackTrace();
}
}
I'm using Maven, and I'm including the WebSocket API with <scope>provided</scope>, as I've seen in other questions that this was the root of other problems.
When I run the server, I can hit the my-servlet endpoint successfully (as a web page, of course), but when I try to create a WS object, simply within the browser's dev console using var webSocket = new WebSocket("ws://localhost:8080/web-socket"), it says that it can't hit the endpoint:
WebSocket connection to 'ws://localhost:8080/web-socket' failed: Error during WebSocket handshake: Unexpected response code: 404
My question: What am I missing? The error message (from Chrome) suggests that the endpoint isn't registered (hence the 404). How do I register the websocket ServerEndpoint? Thanks!
EDIT:
Here's my implementation of MyServlet class:
package com.myapp;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet
{
#Override
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp) throws IOException
{
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write("Works...");
resp.getWriter().flush();
resp.getWriter().close();
}
}
And here's my implementation of MyFilter:
package com.myapp;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class MyFilter implements Filter
{
#Override
public void init(FilterConfig filterConfig)
{
// ...
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("myHeader", "myHeaderValue");
chain.doFilter(request, httpResponse);
}
#Override
public void destroy()
{
// ...
}
}
Try this to manually add web socket endpoint:
String serverContainerClass = ServerContainer.class.getName();
//should be "javax.websocket.server.ServerContainer", if not, some external package could have hogged the implementation
final ServerContainer serverContainer = (ServerContainer) context.getServletContext().getAttribute(serverContainerClass);
try
{
serverContainer.addEndpoint(WebSocket.class);
}
catch (DeploymentException e)
{
TraceWriter.Error(this, "Failed to initialize websocket", e);
}
You should put this code after you add servlet to context

Spring Cache not working in doFilter

Spring Cache not working if called from doFilter.
Note that Spring cache is working if NOT called from doFilter() (e.g if called from rest service)
How can I enable cache in doFilter() ? (maybe cache is not allowed in doFilter?)
#Configuration
#EnableCaching
public class CredentialsInjectionFilter implements javax.servlet.Filter {
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("tenants")
));
return cacheManager;
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
display(5);
filterChain.doFilter(servletRequest, servletResponse);
}
#Cacheable("tenants")
public void display(int number) {
// if cache working properly, code below will not execute after the first calling
for(int i=0; i<50; i++) {
System.out.println("ramon called" +number);
}
}
How about extending org.springframework.web.filter.GenericFilterBean, and moving the caching details into a separate service class
CacheService
import java.util.Arrays;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
#Component
public class CacheService{
#Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("tenants")
));
return cacheManager;
}
#Cacheable("tenants")
public void display(int number) {
// if cache working properly, code below will not execute after the first calling
for(int i=0; i<50; i++) {
System.out.println("ramon called" +number);
}
}
}
CredentialsInjectionFilter
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.GenericFilterBean;
#Component
public class CredentialsInjectionFilter extends GenericFilterBean {
#Autowired
private CacheService cacheService;
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
cacheService.display(5);
filterChain.doFilter(servletRequest, servletResponse);
}
}

Categories