20

I'm trying to integrate the Thymeleaf security dialect (such as sec:authorize tag) into a Spring Boot + Spring Security application that is working properly.

After some research I found that the solution to activate that is to:

Add the dependency in the POM file:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    <version>3.0.0.RELEASE</version>
</dependency>

and include the tag at the top of the template file:

<html   xmlns:th="http://www.thymeleaf.org" lang="en"
        xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

So far, so good. Dependency is found, the tags recognized in the markup.

However they're not taken into account and appear in the final HTML generated.

Because of a problem in the Spring Boot auto-configuration which doesn't enable, it seems to be necessary to manually add a SpringSecurityDialect Bean to one @Configuration class to enable it (several questions found on StackOverflow have been solved by this):

@Bean
    public SpringSecurityDialect securityDialect() {
        return new SpringSecurityDialect();
    }

This is what causes a problem: when I add this Bean into my Spring Boot Configuration, it raises an Exception because it can't find the class org.thymeleaf.dialect.IProcessorDialect. Here is the error:

> java.lang.IllegalStateException: Could not evaluate condition on
> org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer
> due to org/thymeleaf/dialect/IProcessorDialect not found. Make sure
> your own configuration does not rely on that class. This can also
> happen if you are @ComponentScanning a springframework package (e.g.
> if you put a @ComponentScan in the default package by mistake)

What am I missing? Is this an error coming from Thymeleaf? Spring Boot? My own code? Thanks in advance for your help !

Here are some of my files concerned by my issue:

Application.java

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
      public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
              SecurityConstraint securityConstraint = new SecurityConstraint();
              securityConstraint.setUserConstraint("CONFIDENTIAL");
              SecurityCollection collection = new SecurityCollection();
              collection.addPattern("/*");
              securityConstraint.addCollection(collection);
              context.addConstraint(securityConstraint);
            }
          };

        tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
        return tomcat;
      }

      private Connector initiateHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);

        return connector;
      }
}

WebMvcConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    /**
     * Configure relationships between URLs and view names
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
    }

    @Bean
    public SpringSecurityDialect securityDialect() {
        return new SpringSecurityDialect();
    }
}

Thymeleaf template:

<!DOCTYPE html>
<html   xmlns:th="http://www.thymeleaf.org" lang="en"
        xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

....

<div sec:authorize="isAuthenticated()">
    LOGGED IN
</div>
<div sec:authorize="isAnonymous()">
    ANONYMOUS
</div>

....

The full console output when starting the application:

>  :: Spring Boot ::        (v1.3.4.RELEASE)
> 
> 2016-05-17 17:22:59.951  INFO 96267 --- [  restartedMain]
> edu.rmit.eres.estored.Application        : Starting Application on
> w8031808.local with PID 96267
> (/Users/guillaume/dev/workspace/e-stored/target/classes started by
> guillaume in /Users/guillaume/dev/workspace/e-stored) 2016-05-17
> 17:22:59.956  INFO 96267 --- [  restartedMain]
> edu.rmit.eres.estored.Application        : No active profile set,
> falling back to default profiles: default 2016-05-17 17:23:00.239 
> INFO 96267 --- [  restartedMain]
> ationConfigEmbeddedWebApplicationContext : Refreshing
> org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@16f53cde:
> startup date [Tue May 17 17:23:00 AEST 2016]; root of context
> hierarchy 2016-05-17 17:23:01.578 ERROR 96267 --- [  restartedMain]
> o.s.boot.SpringApplication               : Application startup failed
> 
> java.lang.IllegalStateException: Could not evaluate condition on
> org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer
> due to org/thymeleaf/dialect/IProcessorDialect not found. Make sure
> your own configuration does not rely on that class. This can also
> happen if you are @ComponentScanning a springframework package (e.g.
> if you put a @ComponentScan in the default package by mistake)    at
> org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:55)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:102)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:178)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:140)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:333)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:678)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:520)
> ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE]     at
> org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
> ~[spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]    at
> org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:1191)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> org.springframework.boot.SpringApplication.run(SpringApplication.java:1180)
> [spring-boot-1.3.4.RELEASE.jar:1.3.4.RELEASE]     at
> edu.rmit.eres.estored.Application.main(Application.java:24)
> [classes/:na]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method) ~[na:1.8.0_60]    at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> ~[na:1.8.0_60]    at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> ~[na:1.8.0_60]    at java.lang.reflect.Method.invoke(Method.java:497)
> ~[na:1.8.0_60]    at
> org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
> [spring-boot-devtools-1.3.4.RELEASE.jar:1.3.4.RELEASE] Caused by:
> java.lang.NoClassDefFoundError:
> org/thymeleaf/dialect/IProcessorDialect   at
> java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_60]  at
> java.lang.ClassLoader.defineClass(ClassLoader.java:760) ~[na:1.8.0_60]
>   at
> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
> ~[na:1.8.0_60]    at
> java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
> ~[na:1.8.0_60]    at
> java.net.URLClassLoader.access$100(URLClassLoader.java:73)
> ~[na:1.8.0_60]    at
> java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_60]
>   at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
> ~[na:1.8.0_60]    at java.security.AccessController.doPrivileged(Native
> Method) ~[na:1.8.0_60]    at
> java.net.URLClassLoader.findClass(URLClassLoader.java:361)
> ~[na:1.8.0_60]    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_60]
>   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
> ~[na:1.8.0_60]    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_60]
>   at
> org.springframework.boot.devtools.restart.classloader.RestartClassLoader.loadClass(RestartClassLoader.java:151)
> ~[spring-boot-devtools-1.3.4.RELEASE.jar:1.3.4.RELEASE]   at
> java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_60]
>   at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_60]
>   at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
> ~[na:1.8.0_60]    at java.lang.Class.getDeclaredMethods(Class.java:1975)
> ~[na:1.8.0_60]    at
> org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:612)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:524)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:510)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:570)
> ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE]    at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:683)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:627)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:597)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1445)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:975)
> ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE]   at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.addBeanTypeForNonAliasDefinition(BeanTypeRegistry.java:289)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.addBeanType(BeanTypeRegistry.java:278)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.BeanTypeRegistry$OptimizedBeanTypeRegistry.getNamesForType(BeanTypeRegistry.java:259)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:182)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:171)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:139)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:113)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  at
> org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
> ~[spring-boot-autoconfigure-1.3.4.RELEASE.jar:1.3.4.RELEASE]  ... 22
> common frames omitted Caused by: java.lang.ClassNotFoundException:
> org.thymeleaf.dialect.IProcessorDialect   at
> java.net.URLClassLoader.findClass(URLClassLoader.java:381)
> ~[na:1.8.0_60]    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_60]
>   at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
> ~[na:1.8.0_60]    at
> java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_60]
>   ... 56 common frames omitted
> 
> 2016-05-17 17:23:01.581  INFO 96267 --- [  restartedMain]
> .b.l.ClasspathLoggingApplicationListener : Application failed to start
> with classpath:
> [file:/Users/guillaume/dev/workspace/e-stored/target/classes/]
3
  • 2
    Mixing of THymleaf versions. Thyme leaf 3 isn't supported yet only 2 afaik.
    – M. Deinum
    Commented May 17, 2016 at 8:44
  • Where is you thymeleaf annotation config? the view resolvers and template engine etc ? And have you included the thymeleaf-spring dependency in your pom?
    – Lucky
    Commented May 17, 2016 at 12:50
  • 1
    Thank you for your replies. @M.Deinum is correct, I've changed the version of thymeleaf-extras-springsecurity4 to the latest 2.x.x version (2.1.2 at the moment of this post) and it did fix the issue ! Commented May 17, 2016 at 23:26

4 Answers 4

28

Thanks for M. Deinum helpful comment!

It appears indeed that "Thymeleaf Extras for Spring Security 4" version 3.0.0 isn't supported yet.

I have changed the Maven dependency version of Thymeleaf thymeleaf-extras-springsecurity4 in my POM file from 3.0.0 to the latest 2.x.x version (2.1.2 at the moment of this post), and it fixed the issue.

From:

    <!-- http://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>3.0.0.RELEASE</version>
    </dependency>

to:

    <!-- http://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        <version>2.1.2.RELEASE</version>
    </dependency>

The issue doesn't appear anymore, the web application starts properly, and the tags are recognised :)

1
  • Your question and your answer helped me a lot, thanks! (I had the same problem, not with thymeleaf-extras-springsecurity4 but with thymeleaf-extras-java8time instead). Now when you know the answer, would you please consider editing your original question so you remove all the information which is NOT relevant to the actual cause? It would make it even more helpful :) Commented Jun 28, 2017 at 12:26
0

Finally it works with the default spring boot configurations as follows - spring boot version 1.5.8.RELEASE

 <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
         <groupId>org.thymeleaf.extras</groupId>
         <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    </dependency>

This will add

  • Thymeleaf-spring4 version 2.1.5.RELEASE
  • Thymeleaf vesrsion 2.1.5.RELEASE
  • Thymeleaf-extra-springsecurity4 version 2.1.3.RELEASE
  • Spring-security 4.2.3.RELEASE

    Be sure to ignore the bean definition SpringSecurityDialect in configuration file, it won't work. just use the default unless you need to do other things.

0

This saves my life.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Using: Maven 3.5.0
Java 1.8.0_152
Spring: https://start.spring.io --> Spring Boot :: (v2.0.0.BUILD-SNAPSHOT)

0

Changing the

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>

to

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity4</artifactId>
    <version>3.0.0.RELEASE</version>
</dependency>

worked without a problem and without having to add anything to the header.

The thymeleaf-extras-springsecurity5 is supposed to work with the 'spring-boot-starter-security' but so far, lots of people seem to have some error with it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.