Configuring Thymeleaf spring security 4 integration module using Yaml - spring-security

I'm trying to use spring security 4 integration module (https://github.com/thymeleaf/thymeleaf-extras-springsecurity), Seems like I have to use java config and this can't be done in Yaml.
I'm not using any spring xml configuration. only Yaml and java configs.
Is there anyway to configure spring security integration module yet not mess up with thymeleaf auto configuration provided by Spring boot?
Right now I'm doing the configuration like this :
#Bean
public ViewResolver viewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
dialects.add(new org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect());
engine.setAdditionalDialects(dialects);
engine.setTemplateResolver(templateResolver());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/templates/");
resolver.setTemplateMode("HTML5");
return resolver;
}
But I'm getting java.lang.NoClassDefFoundError: org/thymeleaf/dialect/IProcessorDialect
Thank you in advance,

Related

Is there a way to up only security context in Spring Boot tests?

I want to write some kind of unit test which depends on Spring Security.
For example, I have some service method which uses some repository and marked with #PreAuthorize annotation. Repository I can mock with Mockito, there is no problem. Also I can mock Security Context by #WithSecurityContext annotation. But when I run test, the #PreAuthorize annotation is just ignored. Of course I can run that test with #SpringBootTest annotation as an integration test and in this case the Security Context is up but this way is heavy and slow.
Is there a way to run unit test with only Spring Security Context raised?
UPDATE
Made an example of such kind of test. Thanks to #Sam Brannen for giving right direction.
#ActiveProfiles("method-security-test")
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ExampleService.class, ExampleServiceTest.MethodSecurityConfiguration.class})
public class ExampleServiceTest {
private ExampleService service;
#Autowired
public void setService(ExampleService service) {
this.service = service;
}
#Test
#WithMockUser(username = "john_doe")
public void testAuthenticated() {
String actualMessage = service.example();
Assert.assertEquals("Message of john_doe", actualMessage);
}
#Test(expected = AuthenticationException.class)
public void testNotAuthenticated() {
service.example();
Assert.fail();
}
#TestConfiguration
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
}
}
#Service
class ExampleService {
#PreAuthorize("isAuthenticated()")
String example() {
Principal principal = SecurityContextHolder.getContext().getAuthentication();
return "Message of " + principal.getName();
}
The #PreAuthorize annotation from Spring Security will only be honored if Spring Security proxies your component (e.g., service bean).
The simplest way to make that happen is by annotating an #Configuration class with #EnableGlobalMethodSecurity(prePostEnabled = true), having your component registered as a bean (e.g., via component scanning or an #Bean method), and including your AuthenticationManager setup.
You can then create a focused integration test using #ContextConfiguration (without Spring Boot testing support) to load an ApplicationContext from your #Configuration class. And you can use #Autowired to get access to your proxied component which will be advised with the #PreAuthorize security check support.
You might find this old blog post useful as well for background information: https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/

Spring WebFlux 5.0.RELEASE and Spring Security 5.0.M5

I am trying to build a web service using WebFlux. When I tried to configure Spring Security with Spring WebFlux, the requests are not intercepted by Spring Security. My Spring Security config is:
#EnableWebFlux
#EnableWebFluxSecurity
#Configuration
public class WebConfig {
#Bean
public MapUserDetailsRepository userDetailsRepository() {
UserDetails cust =
User.withUsername("user1").password("password")
.roles("USER").build();
UserDetails admin =
User.withUsername("admin1").password("password")
.roles("ADMIN").build();
return new MapUserDetailsRepository(cust, admin);
}
#Bean
public SecurityWebFilterChain springWebFilterChain(
HttpSecurity httpSecurity) {
return httpSecurity.authorizeExchange().anyExchange().
authenticated().and().build();
}
}
One way is to use method security. You need to add #EnableReactiveMethodSecurity to your configuration class and then secure handler component methods with annotations, such as #PreAuthorize("isAuthenticated()")
This is how I managed to get this working with Spring Boot 2.0.0.M4, but again this may depend on what kind of request handling you are doing.
This is an issue when using Spring Security with WebFlux. The workaround is posted here: https://jira.spring.io/browse/SPR-16144

Spring Amqp annotations based

I am new to Spring AMQP and want to use annotation based configuration for both producers and consumers using latest spring amqp 1.5.4 ,
Is there any pseoudo code available for configuration which does the logic for creating connection or #Queue etc.
Probably the quickest way to get started would be use Spring Boot - boot will create all the beans you need (connecting to localhost by default but easily overridable with properties).
You can also look at some of the Spring AMQP test cases.
Have a class annotated with #Configuration in Spring Boot which can provide you with annotation based bean definition :
Here is a sample :
#Configuration
public class QueueConfig {
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(connectionFactory());
}
#Bean
public RabbitTemplate rabbitTemplate() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
rabbitTemplate.setExchange("myQueue");
return rabbitTemplate;
}
#Bean
Queue rabbitQueue() {
return new Queue(WORKERS_QUEUE_NAME, true, false, false, null);
}
}

Spring security DefaultMethodSecurityExpressionHandler bean is not registered for Integration Test's default spring security config

I am attempting to write Spring MVC integration test with Spring Security and Thymeleaf for the view layer.
I have setup my MockMvc object with Spring Security Integration just like all the examples from the documentation.
Integration Test setUp:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
//.defaultRequest(get("/").with(user(someUser)))
.apply(springSecurity())
.build();
}
Thymeleaf is configured to utilize the SpringSecurityDialect. (thymeleaf-extras-springsecurity4)
additionalDialects.add( new SpringSecurityDialect());
For the purpose of being able to utilize spring security expressions in the view layer (example).
<p sec:authorize="hasRole('ROLE_USER')"> User logged in</p>
Now my configuration works perfectly fine outside of testing however, when I try to make an integration test Thymeleaf throws an exception stating that
(org.thymeleaf.extras.springsecurity4.auth.AuthUtils.class)
#SuppressWarnings("unchecked")
private static SecurityExpressionHandler<FilterInvocation> getExpressionHandler(final ServletContext servletContext) {
final ApplicationContext ctx =
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
final Map<String, SecurityExpressionHandler> expressionHandlers =
ctx.getBeansOfType(SecurityExpressionHandler.class);
for (SecurityExpressionHandler handler : expressionHandlers.values()) {
if (FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(handler.getClass(), SecurityExpressionHandler.class))) {
return handler;
}
}
throw new TemplateProcessingException(
"No visible SecurityExpressionHandler instance could be found in the application " +
"context. There must be at least one in order to support expressions in Spring Security " +
"authorization queries.");
This exception is valid because SecurityExpressionHandler.class is missing from the application context during the integration test.
So my question is... how come a SecurityExpressionHandler.class is registered as spring bean in a regular servlet environment but when using the Integration Test config ctx.getBeansOfType(SecurityExpressionHandler.class) is missing from the context? Is this a bug in Spring Security? Or do I need to add additional logic to register a SecurityExpressionHandler bean for the integration test only?
I tried to "force create" a SecurityExpressionHandler by extending GlobalMethodSecurityConfiguration and #Overriding the createExpressionHandler() and adding it to my test config but still the bean was not registered with the WebApplicationContext.
This is a blocker for me right now because I cannot perform any integration testing on any view file that contains Spring Security expressions embedded inside them.
Spring v4.1.6
Spring Security 4.0.1
Thymeleaf v2.1.4
If you are loading the WebApplicationContext for your test using #ContextHierarchy, then this will not work with Spring Framework 4.1.4 through 4.1.6 due to a confirmed bug that will be fixed in 4.1.7.
See SPR-13075 for details.

SpringVaadinServlet blocking SpringBoot features

In our Muhuru-Bay-Microgrid-Dashboad project we're using code from https://github.com/xpoft/spring-vaadin in an attempt to get Spring Boot and Vaadin to play nicely. The problem - with this approach we can't access many of the other rest service Spring Boot registers at startup such as
/configprops
/health
/dump
/info
/trace
/mappings
/error
/autoconfig
Our startup code looks like:
#Bean
public ServletRegistrationBean servletRegistrationBean() {
final ServletRegistrationBean servletRegistrationBean
= new ServletRegistrationBean(
new ru.xpoft.vaadin.SpringVaadinServlet(),
"/*", "/VAADIN/*");
return servletRegistrationBean;
}
When we try to access Spring Boot's registered REST services we get redirected to /error - which also doesn't work correctly. Any hints greatly appreciated.
Try to use this addon to integrate Spring Boot and Vaadin:
https://github.com/peholmst/vaadin4spring
It's still in beta, but in my opinion it works much better than the Xpoft addon.
Using https://github.com/peholmst/vaadin4spring with Spring Boot, I had the same problem of getting HTTP 404 when accessing the application's other REST services.
What worked for me was to set VaadinServletConfiguration.SERVLET_URL_MAPPING_PARAMETER_NAME in the spring environment to send the Vaadin UI to a different context path (/ui/*):
#SpringBootApplication
public class AppSpringConfig {
public static void main(String[] args) {
new SpringApplicationBuilder(AppSpringConfig.class).initializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
public void initialize(ConfigurableApplicationContext applicationContext)
{
ConfigurableEnvironment appEnvironment = applicationContext.getEnvironment();
Properties props = new Properties();
props.put(VaadinServletConfiguration.SERVLET_URL_MAPPING_PARAMETER_NAME, "/ui/*");
PropertySource< ? > source = new PropertiesPropertySource("vaadin", props);
appEnvironment.getPropertySources().addFirst(source);
}
}).run(args);
}
}

Resources