Grails 3 with Spring boot autoconfigure - grails

I'm trying to integrate a Grails application with the Netflix Eureka stuff for using Spring Cloud Ribbon for making REST calls to services. In a normal Spring Boot application it is nothing more than adding the required dependencies and the spring boot autoconfigure will make sure that my RestTemplate is configured for the Ribbon use.
But in our Grails (3.0.7) application the Spring Boot autoconfiguration will not kick in. Does anyone have an idea to get the Grails with Spring Boot autoconfigure working?

Found the problem. Spring boot's #AutoConfigure was working after all.
Problem when trying to use a Spring RestTemplate for rest with Ribbon:
class MyController {
RestTemplate restTemplate
def index() {
def result = restTemplate.getEntity("http://my-service/whatever", Void.class) // call gives nullPointerException due restTemplate is not injected
render "Response: $result"
}
}
Because Spring Boot registers the Ribbon enabled RestTemplate bean not under bean name restTemplate, the Grails convention based injection mechanism (field name must match bean name) doesn't work. To work around this problem it is needed to #Autowired to the restTemplate field and let Spring do the injection.
So this is the solution:
class MyController {
#AutoWired
RestTemplate restTemplate
def index() {
def result = restTemplate.getEntity("http://my-service/whatever", Void.class) // restTemplate is now injected using Spring instead of Grails
render "Response: $result"
}
}

Related

webflux security multi roles in same match

I use spring security in spring cloud gateway. cloud version is Finchely.SR2 and spring boot version is 2.0.x
Then i set two role in one matcher like this:
.pathMatchers("/apis/**").hasRole("TEST1")
.pathMatchers("/apis/**").hasRole("TEST2")
but, when i startup application and do test, just TEST1 role can access. TEST2 role get FORBIDDEN 403 response.
I know in spring-boot-starter-web with spring-security, it has any method like
.antMatchers("/apis/**").hasAnyRole("TEST1", "TEST2")
Does webflux spring security has any API like hasAnyRole(String...roles) to use?
There isn't one available in the base APIs from Spring Security, however I've been using the following for anyAuthority,
public class HasAnyAuthority<T> implements ReactiveAuthorizationManager<T> {
private final Collection<String> allowedAuthorities;
public HasAnyAuthority(Collection<String> allowedAuthorities) {
this.allowedAuthorities = allowedAuthorities;
}
#Override
public Mono<AuthorizationDecision> check(final Mono<Authentication> authentication,
T object) {
return authentication.filter(Authentication::isAuthenticated)
.flatMapIterable(Authentication::getAuthorities)
.map(GrantedAuthority::getAuthority).any(allowedAuthorities::contains)
.map(AuthorizationDecision::new)
.defaultIfEmpty(new AuthorizationDecision(false));
}
with usage like,
.access(new HasAnyAuthority<>(allowedAuth.getAuthorities())
hasAnyRole and hasAnyAuthority will be available in WebFlux in Spring Security 5.2.0.
You can try them out now in 5.2.0.M3.
The syntax is the same
.pathMatchers("/apis/**").hasAnyRole("TEST1", "TEST2")
If it helps anyone
.pathMatchers("/apis/**")
.access((mono, context) -> mono.map(auth -> auth.getAuthorities().stream()
.filter(e -> (e.getAuthority().contains(TEST1) || e.getAuthority().contains(TEST2)))
.count() > 0)
.map(AuthorizationDecision::new))

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

Swagger UI implementation via WebApplicationInitializer class

I am using spring 4.1.6 release version on was 8.5 for jackson jersery rest service. This has no web.xml. it is done thro WebApplicationInitializer class.Now i would like to implement swagger UI, I googled and didnt find any examples that fit my exact scenario. everyone is providing examples that is for rest controller thro spring mvc. i would like to know how to do it thro jackson jersey in spring4. please advise
#Bean
public SwaggerConfig swaggerConfig(){
return new SwaggerConfig();
}
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
}
using this swagger-ui is enabled with spring MVC

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