Disable http TRACK/TRACE in undertow using spring boot - java

I want to disable http TRACE in undertow. I am using spring boot and undertow is provided with it by default. I have excluded tomcat and using undertow. I got the answer for tomcat in other stackoverflow post (here) but I am unable to find the same for undertow. This is what I have done till now.
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container.getClass().isAssignableFrom(UndertowEmbeddedServletContainerFactory.class)) {
UndertowEmbeddedServletContainerFactory underTowContainer = (UndertowEmbeddedServletContainerFactory) container;
underTowContainer.addDeploymentInfoCustomizers(new ContextSecurityCustomizer());
}
}
};
}
private static class ContextSecurityCustomizer implements UndertowDeploymentInfoCustomizer {
#Override
public void customize(DeploymentInfo deploymentInfo) {
DeploymentInfo info = new DeploymentInfo();
// What next after this
}
}
Please help me complete this code. Am I even moving in the right direction? Thanks in advance

You can use the DisallowedMethodsHandler from undertow:
import io.undertow.server.handlers.DisallowedMethodsHandler;
#Component
public class UndertowWebServerCustomizer
implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
#Override
public void customize(UndertowServletWebServerFactory factory) {
factory.addDeploymentInfoCustomizers(deploymentInfo -> {
deploymentInfo.addInitialHandlerChainWrapper(new HandlerWrapper() {
#Override
public HttpHandler wrap(HttpHandler handler) {
HttpString[] disallowedHttpMethods = { HttpString.tryFromString("TRACE"),
HttpString.tryFromString("TRACK") };
return new DisallowedMethodsHandler(handler, disallowedHttpMethods);
}
});
});
}
}

This should work for undertow:
#Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container.getClass().isAssignableFrom(UndertowEmbeddedServletContainerFactory.class)) {
UndertowEmbeddedServletContainerFactory undertowContainer = (UndertowEmbeddedServletContainerFactory) container;
undertowContainer.addDeploymentInfoCustomizers(new ContextSecurityCustomizer());
}
}
};
}
private static class ContextSecurityCustomizer implements UndertowDeploymentInfoCustomizer {
#Override
public void customize(io.undertow.servlet.api.DeploymentInfo deploymentInfo) {
SecurityConstraint constraint = new SecurityConstraint();
WebResourceCollection traceWebresource = new WebResourceCollection();
traceWebresource.addUrlPattern("/*");
traceWebresource.addHttpMethod(HttpMethod.TRACE.toString());
constraint.addWebResourceCollection(traceWebresource);
deploymentInfo.addSecurityConstraint(constraint);
}
}

Related

Spring batch: get ExecutionContext in the listener

I am new to Spring batch.
I need to count the element read, written and that have gone in error.
I've defined a step like this:
/*...*/
#Bean
public Step stepMain(StepBuilderFactory stepBuilderFactory) {
return stepBuilderFactory.get("stepMain").<T, T> chunk(this.chuckSize).reader(reader(null, null)).processor(new Processor()).writer(writer()).faultTolerant().skipPolicy(new AlwaysSkipItemSkipPolicy()).listener(new ListenerReader()).listener(new ListenerProcessor()).listener(new ListenerWriter()).listener(new ListenerChunk()).build();
}
/*...*/
And, for example, an ListenerReader like this:
#Log4j2
public class ListenerReader implements ItemReadListener<T> {
#Value("#{jobExecution.executionContext}")
private ExecutionContext executionContext;
#Override
public void afterRead(T item) {
Integer read = (Integer) executionContext.get("reportRead");
read++;
executionContext.put("reportRead", read);
}
#Override
public void onReadError(Exception ex) {
Integer error = (Integer) executionContext.get("reportError");
error++;
executionContext.put("reportError", error);
}
}
But in ListenerReader i've no visibility of executionContext field.
How can i solve?
You can do it like
Define a Bean with JobScope
Use it in Step as usual
Inject it via Listener.
Below is an example
#Bean
#JobScope
public SimpleReaderListener simpleReaderListener() {
return new SimpleReaderListener();
}
#Bean
public Step step1() {
return stepBuilderFactory.get("step1").<SoccerTeam, SoccerTeam> chunk(1)
.reader(simpleReader()).listener(simpleReaderListener()).processor(new SimpleProcessor())
.writer(new SimpleWriter()).build();
}
public class SimpleReaderListener implements ItemReadListener<SoccerTeam> {
#Value("#{jobExecution.executionContext}")
private ExecutionContext executionContext;
#Override
public void afterRead(SoccerTeam soccerTeam) {
}

How to configure JNDI File resource in springboot?

Migrating a Spring application running on WAS to Springboot with embedded tomcat.
The application uses multiple jar libraries to load a file using jndi. How do I configure something similar to load the file using jndi in my springboot app?
SpringBoot Class :
#SpringBootApplication
#ComponentScan
public class BootApplication {
#Value("${refEnv.url}")
private String refEnvUrl;
#Value("${refEnvironmentFile.jndi-name}")
private String refEnvJNDI;
public String getRefEnvUrl() {
return refEnvUrl;
}
public void setRefEnvUrl(String refEnvUrl) {
this.refEnvUrl = refEnvUrl;
}
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
#Bean
public ServletWebServerFactory servletContainer() {
return new CustomTomcatServletWebServerFactory();
}
private class CustomTomcatServletWebServerFactory extends TomcatServletWebServerFactory {
#Override
protected void postProcessContext(Context context) {
ContextResource refEnvFile = new ContextResource();
refEnvFile.setName(refEnvJNDI);
refEnvFile.setType(URL.class.getName());
refEnvFile.setProperty("factory", "com.config.utils.URLFactory");
refEnvFile.setProperty("file", refEnvUrl);
context.getNamingResources().addResource(refEnvFile);
}
#Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
tomcat.enableNaming();
TomcatWebServer container = super.getTomcatWebServer(tomcat);
for (Container child : container.getTomcat().getHost().findChildren()) {
if (child instanceof Context) {
ClassLoader contextClassLoader = ((Context) child).getLoader().getClassLoader();
Thread.currentThread().setContextClassLoader(contextClassLoader);
break;
}
}
return container;
}
}
}
URL Factory Class :
public class URLFactory implements ObjectFactory {
public Object getObjectInstance(Object obj, Name name,
Context nameCtx, Hashtable environment) throws Exception {
Reference ref = (Reference) obj;
String urlString = (String) ref.get("file").getContent();
return new URL(urlString);
}
}

Disable WebSession creation when using spring-security with spring-webflux

I am running a stateless spring-boot application with a rest api and want to disable the creation of WebSessions as described https://www.baeldung.com/spring-security-session
I have created my own WebSessionManager that does not store the session.
#Bean
public WebSessionManager webSessionManager() {
return new WebSessionManager() {
#Override
#NonNull
public Mono<WebSession> getSession(#NonNull final ServerWebExchange exchange) {
return Mono.just(new WebSession() {
#Override
#NonNull
public String getId() {
return "";
}
#Override
#NonNull
public Map<String, Object> getAttributes() {
return new HashMap<>();
}
#Override
public void start() {
}
#Override
public boolean isStarted() {
return true;
}
#Override
#NonNull
public Mono<Void> changeSessionId() {
return Mono.empty();
}
#Override
#NonNull
public Mono<Void> invalidate() {
return Mono.empty();
}
#Override
#NonNull
public Mono<Void> save() {
return Mono.empty();
}
#Override
public boolean isExpired() {
return false;
}
#Override
#NonNull
public Instant getCreationTime() {
return Instant.now();
}
#Override
#NonNull
public Instant getLastAccessTime() {
return Instant.now();
}
#Override
public void setMaxIdleTime(#NonNull final Duration maxIdleTime) {
}
#Override
#NonNull
public Duration getMaxIdleTime() {
return Duration.ofMinutes(1);
}
});
}
};
}
It works but I wonder if there is a better way to not create a session.
The Issue #6552: Session Creation Policy with Webflux Security is going to be fixed by Spring team.
The problem is that the request cache is being invoked for every request to see if there is a value saved to replay and thus the WebSession is being looked up for every request. Since the WebSession is being looked up with an invalid session id, Spring WebFlux invalidates the SESSION cookie. ~ rwinch
Solution suggested by DarrenJiang1990 is:
.and().securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
The security context in a WebFlux application is stored in a ServerSecurityContextRepository. Its WebSessionServerSecurityContextRepository implementation, which is used by default, stores the context in session. Configuring a NoOpServerSecurityContextRepository instead would make our application stateless
You can track the progress of patching in Issue #7157 ServerRequestCacheWebFilter causes WebSession to be read every request.
I've disabled WebSessionManager by the following trick
#Bean
public WebSessionManager webSessionManager() {
// Emulate SessionCreationPolicy.STATELESS
return exchange -> Mono.empty();
}
All other solutions didn't help for me.
Use the: NoOpServerSecurityContextRepository intended for this purpose.
#Configuration
#EnableWebFluxSecurity
#ComponentScan(value = {"my.package.security"})
public class SpringSecurityConfig2 {
#Autowired private MyHeaderExchangeMatcher myHeaderExchangeMatcher;
#Autowired private MyReactiveAuthenticationManager myReactiveAuthenticationManager;
#Autowired private MyTokenAuthenticationConverter myTokenAuthenticationConverter;
#Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
http.httpBasic().disable().formLogin().disable().csrf().disable().logout().disable();
http...
.addFilterAt(webFilter(), SecurityWebFiltersOrder.AUTHORIZATION)
...;
return http.build();
}
#Bean
public AuthenticationWebFilter webFilter() {
AuthenticationWebFilter authenticationWebFilter =
new AuthenticationWebFilter(myReactiveAuthenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(myTokenAuthenticationConverter);
authenticationWebFilter.setRequiresAuthenticationMatcher(myHeaderExchangeMatcher);
// NoOpServerSecurityContextRepository is used to for stateless sessions so no session or state is persisted between requests.
// The client must send the Authorization header with every request.
NoOpServerSecurityContextRepository sessionConfig = NoOpServerSecurityContextRepository.getInstance();
authenticationWebFilter.setSecurityContextRepository(sessionConfig);
return authenticationWebFilter;
}
}

What is the proper spring boot way to apply dependency injection

I am currently working on an spring boot application that wires some beans together in the following way (heavily simplified example):
#Component
#Order(0)
public class PlayingFieldByBeans implements CommandLineRunner {
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from lazy beans variant: ");
names.forEach(n -> {
System.out.println(player(n));
});
}
#Bean
#Lazy
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
private Shoes shoes() {
return new Shoes("Adidas");
}
}
The actual beans however, require alot more configuration and setting than is shown here and it takes quite alot of lines of code in the PlayingFieldByBeans class when using the inner Lazy Bean methodology. So I created a different way of wiring it together using Component annotation:
#Component
#Order(1)
public class PlayingFieldByComponents implements CommandLineRunner {
#Autowired
private PlayerComponent playerComponent;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(playerComponent.player(n));
});
}
}
The PlayerComponent class looks like this:
#Component
public class PlayerComponent {
#Autowired
private ShoesComponent shoesComponent;
public Player player(String name) {
return new Player(name, shoesComponent.shoes());
}
}
The ShoesComponent is very similar to the PlayerComponent class.
For maintainablity and TDD purposes I am not sure what is the most proper way to use the spring framework here.
Question
Given the Player and Shoes beans require more then just one line of initialization (multiple settings, multiple dependencies on other beans etc), what is the best way to design and wire them?
Edit - based on suggestion
Added a configuration class to bundle the beans:
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
And the matching executing class:
#Component
#Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
#Autowired
private BeanConfiguration beanConfiguration;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(beanConfiguration.player(n));
});
}
}
Re uses the same first bean, so it doesn't seem to create a new one
Printing from component variant:
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
One solution would be to change scope of Player bean (and Shoes later on if we want to create different brands) as mentioned by Andriy Slobodyanyk
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
If above would not be sufficient (since you mentioned real case scenario is more compilcated) another option is to use FactoryBean
public class PlayerFactoryBean implements FactoryBean<Player> {
private String name;
private Shoes shoes;
public void setName(String name) {
this.name = name;
}
public void setShoes(Shoes shoes) {
this.shoes = shoes;
}
#Override
public Player getObject() throws Exception {
//initialization logic goes here
System.out.println("Creating bean using factory");
return new Player(name, shoes);
}
#Override
public Class<Player> getObjectType() {
return Player.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
#Bean
public PlayerFactoryBean playerFactoryBean(){
PlayerFactoryBean pfb = new PlayerFactoryBean();
pfb.setShoes(shoes());
return pfb;
}
}
#Component
#Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
#Autowired
private PlayerFactoryBean factoryBean;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
try {
factoryBean.setName(n);
System.out.println(factoryBean.getObject());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

how to auto-wire HibernateBundle with guice on dropwizard?

Im trying to configure hibernatebundle with guice/dropwizard and need help.
Im using hubspot / dropwizard-guice / 0.7.0 3rd party library in addition to dropwizard lib.
The code below obviously wont work and need help on figuring it out. How do I rewrite this so that hibernatebundle and ultimately, session factory, be auto injected to whatever bean that needs it.
MyApplication.java
public class MyApplication extends Application<MyAppConfiguration> {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle); // ???
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule())
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
}
MyAppModule.java
public class MyAppModule extends AbstractModule {
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
// really wrong as it creates new instance everytime.
return configuration.getHibernateBundle().getSessionFactory(); // ???
}
}
MyAppConfiguration.java
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
// ???
public HibernateBundle<MyAppConfiguration> getHibernateBundle() {
return new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return database;
}
};
}
}
Here is how I end up doing. I never got an answer from here or mailing list so I would consider this hackish and probably not the proper way to do it but it works for me.
In my module (that extends abstractmodule) :
private final HibernateBundle<MyConfiguration> hibernateBundle =
new HibernateBundle<MyConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Provides
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
}
return hibernateBundle.getSessionFactory();
}
revised:
public SessionFactory provideSessionFactory(MyConfiguration configuration,
Environment environment) {
SessionFactory sf = hibernateBundle.getSessionFactory();
if (sf == null) {
try {
hibernateBundle.run(configuration, environment);
return hibernateBundle.getSessionFactory();
} catch (Exception e) {
logger.error("Unable to run hibernatebundle");
}
} else {
return sf;
}
}
I thought the explicit run(configuration, environment) call (in the answer provided by #StephenNYC) was a bit weird so a digged a little deeper. I found out that AutoConfig in dropwizard-guice wasn't setting up ConfiguredBundle's correctly (HibernateBundle is such a type).
As of https://github.com/HubSpot/dropwizard-guice/pull/35 the code can now look like this instead:
#Singleton
public class MyHibernateBundle extends HibernateBundle<NoxboxConfiguration> implements ConfiguredBundle<MyConfiguration>
{
public MyHibernateBundle()
{
super(myDbEntities(), new SessionFactoryFactory());
}
private static ImmutableList<Class<?>> myDbEntities()
{
Reflections reflections = new Reflections("com.acme");
ImmutableList<Class<?>> entities = ImmutableList.copyOf(reflections.getTypesAnnotatedWith(Entity.class));
return entities;
}
#Override
public DataSourceFactory getDataSourceFactory(NoxboxConfiguration configuration)
{
return configuration.getMyDb();
}
}
#Provides
public SessionFactory sessionFactory(MyHibernateBundle hibernate)
{
return checkNotNull(hibernate.getSessionFactory());
}
The magic behind this is that MyHibernateBundle implements ConfiguredBundle which dropwizard-guice now automatically picks up and instantiates.
Here is the way I solved it :
Put the Hibernate bundle in the guice module and pass the bootstap object as argument of guice module constructor so the hibernate bundle can be added to it.
The configuration can remain exactly as you would use a hibernate-bundle without guice.
I got this working with dropwizard-hibernate v0.7.1 and dropwizard-guice v0.7.0.3
MyAppModule.java :
public class MyAppModule extends AbstractModule {
private final HibernateBundle<MyAppConfiguration> hibernateBundle = new HibernateBundle<MyAppConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
public MyAppModule(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}
#Override
protected void configure() {
}
#Provides
public SessionFactory provideSessionFactory() {
return hibernateBundle.getSessionFactory();
}
}
MyApplication.java :
public class MyApplication extends Application<MyAppConfiguration> {
#Override
public void initialize(Bootstrap<MyAppConfiguration> bootstrap) {
bootstrap.addBundle(
GuiceBundle.<MyAppConfiguration>newBuilder()
.addModule(new MyAppModule(bootstrap))
.enableAutoConfig(getClass().getPackage().getName())
.setConfigClass(MyAppConfiguration.class)
.build()
);
}
#Override
public void run(final MyAppConfiguration configuration, final Environment environment) throws Exception {
}
}
MyAppConfiguration.java :
public class MyAppConfiguration extends Configuration {
#Valid
#NotNull
#JsonProperty("database")
private DataSourceFactory database = new DataSourceFactory();
public DataSourceFactory getDataSourceFactory() {
return database;
}
}
I have not used hibernate in dropwizard, but I have used Guice and you really only need to worry about MyAppModule. That's where the magic will happen:
public class MyAppModule extends AbstractModule {
#Singleton
#Provides
public SessionFactory provideSessionFactory(MyAppConfiguration configuration) {
HibernateBundle<MyAppConfiguration> hibernate = new HibernateBundle<ExampleConfiguration>(MyModel.class) {
#Override
public DataSourceFactory getDataSourceFactory(MyAppConfiguration configuration) {
return configuration.getDataSourceFactory();
}
}
return hibernate.getSessionFactory();
}
}
(see here for multiple Classes)
MyAppConfiguration.java and MyApplication.java should not have any of the hibernate bundle references in. You should then be able to #Inject a SessionFactory where ever you need it.

Categories

Resources