Good morning, I'm redoing a demo and I have a compilation error,I have 3 exceptions which all have a link : threw exception with message: authorizationUri cannot be empty.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file [C:\Users\chres\Documents\jetBrainProjects\intellij-idea-projects\sdia2\target\classes\com\example\sdia2\secu\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'clientRegistrationRepository' defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.class]: Failed to instantiate [org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository]: Factory method 'clientRegistrationRepository' threw exception with message: **authorizationUri cannot be empty**
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:797) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:236) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1350) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1187) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:558) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:949) ~[spring-context-6.0.16.jar:6.0.16]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:615) ~[spring-context-6.0.16.jar:6.0.16]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.1.8.jar:3.1.8]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:738) ~[spring-boot-3.1.8.jar:3.1.8]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:440) ~[spring-boot-3.1.8.jar:3.1.8]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) ~[spring-boot-3.1.8.jar:3.1.8]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1317) ~[spring-boot-3.1.8.jar:3.1.8]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-3.1.8.jar:3.1.8]
at com.example.sdia2.Sdia2Application.main(Sdia2Application.java:15) ~[classes/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.1.8.jar:3.1.8]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientRegistrationRepository' defined in class path resource [org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.class]: Failed to instantiate [org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository]: Factory method 'clientRegistrationRepository' **threw exception with message: authorizationUri cannot be empty**
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:650) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1330) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:558) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:518) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:906) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:784) ~[spring-beans-6.0.16.jar:6.0.16]
... 22 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository]: Factory method **'clientRegistrationRepository' threw exception with message: authorizationUri cannot be empty**
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.0.16.jar:6.0.16]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:646) ~[spring-beans-6.0.16.jar:6.0.16]
... 36 common frames omitted
Caused by: java.lang.IllegalArgumentException: **authorizationUri cannot be empty**
at org.springframework.util.Assert.hasText(Assert.java:294) ~[spring-core-6.0.16.jar:6.0.16]
at org.springframework.security.oauth2.client.registration.ClientRegistration$Builder.validateAuthorizationCodeGrantType(ClientRegistration.java:660) ~[spring-security-oauth2-client-6.1.6.jar:6.1.6]
at org.springframework.security.oauth2.client.registration.ClientRegistration$Builder.build(ClientRegistration.java:610) ~[spring-security-oauth2-client-6.1.6.jar:6.1.6]
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper.getClientRegistration(OAuth2ClientPropertiesMapper.java:87) ~[spring-boot-autoconfigure-3.1.8.jar:3.1.8]
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper.lambda$asClientRegistrations$0(OAuth2ClientPropertiesMapper.java:65) ~[spring-boot-autoconfigure-3.1.8.jar:3.1.8]
at java.base/java.util.HashMap.forEach(HashMap.java:1429) ~[na:na]
at org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper.asClientRegistrations(OAuth2ClientPropertiesMapper.java:64) ~[spring-boot-autoconfigure-3.1.8.jar:3.1.8]
at org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientRegistrationRepositoryConfiguration.clientRegistrationRepository(OAuth2ClientRegistrationRepositoryConfiguration.java:49) ~[spring-boot-autoconfigure-3.1.8.jar:3.1.8]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139) ~[spring-beans-6.0.16.jar:6.0.16]
... 37 common frames omitted
application.properties
spring.application.name=customer-app
server.port=8084
spring.security.oauth2.client.registration.google.client-id=290479700275-7t9jjpd5agua1u7n881fubvd2ceqg7aq.apps.googleusercontent.com
spring.security.oauth2.client.registration.google.client-secret=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
spring.security.oauth2.client.provider.github.user-name-attribute=login
spring.security.oauth2.client.registration.github.client-id=Iv1.3369f41e3d67c0a3
spring.security.oauth2.client.registration.github.client-secret=f7cb85296f581390511d1bf4aa29bcc43af7b163
spring.security.oauth2.client.provider.google.user-name-attribute=email
spring.datasource.url=jdbc:h2:mem:customers-db
spring.h2.console.enabled=true
spring.security.oauth2.client.registration.keycloak.client-name=keycloak
spring.security.oauth2.client.registration.keycloak.client-id=client-cree-customer
spring.security.oauth2.client.registration.keycloak.client-secret=C6JJFHCOkDSvaZwLAy673yHVnXkDu6k3
spring.security.oauth2.client.registration.keycloak.scope=openid, profile, email, offline_access
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8084/login/oauth2/code/sdia3
spring.security.oauth2.client.registration.keycloak.issuer-uri=http://localhost:8080/realms/sdia3/account
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
@Controller
public class CustomerController {
/**
* acces a interface
*/
private CustomerRepository customerRepository;
public CustomerController(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@GetMapping("/customers")
@PreAuthorize("hasAuthority('ADMIN')")
public String customers(Model model){
List<Customer> customersList = customerRepository.findAll();
model.addAttribute("customers", customersList);
return "customers";
}
@GetMapping("/products")
public String products(Model model){
return "products";
}
@GetMapping("/auth")
@ResponseBody//vu que ce n'est pas un rest controller, il doit y avoir cette anotation pour retourner la reponse sous format json
public Authentication auth(Authentication authentication){
return authentication;
}
@GetMapping("/")
public String index(){
return "index";
}
}
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sdia2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sdia2</name>
<description>sdia2</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity6 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven.shared/maven-dependency-tree -->
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-dependency-tree</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-messaging -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
<version>6.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.11.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
SecurityConfig
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
//stock les diff providers conf dans l'appli pour la connection clients
private final ClientRegistrationRepository clientRegistrationRepository;
//inj de dependance via constructeur
public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository){
this.clientRegistrationRepository=clientRegistrationRepository;
}
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(Customizer.withDefaults())//config par def.
.authorizeHttpRequests(ar-> ar.anyRequest().authenticated())//toutes requetes necessite une authentification
.authorizeHttpRequests(ar->ar.requestMatchers("/","/webjars/**","/h2-console/**").permitAll())//toute url sans besoin de s'authentifier:parefeu
.oauth2Login(Customizer.withDefaults())
.logout((logout)->logout
.logoutSuccessHandler(oidcLogoutSuccessHandler())
.logoutSuccessUrl("/").permitAll()
.clearAuthentication(true)
.deleteCookies("JSESSIONID"));
return http.build();
}
private OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() {
final OidcClientInitiatedLogoutSuccessHandler oidcClientInitiatedLogoutSuccessHandler=
new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
oidcClientInitiatedLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}?logoutsuccess=true");
return oidcClientInitiatedLogoutSuccessHandler;
}
}
Main
@SpringBootApplication
public class Sdia2Application {
public static void main(String[] args) {
SpringApplication.run(Sdia2Application.class, args);
}
//s'execute au demarrage=onInit() avec en para l'int customerrepository pour utiliser ses methodes REST=inj dep
@Bean
CommandLineRunner commandLineRunner(CustomerRepository customerRepository) {
return args -> {
customerRepository.save(Customer.builder().name("casfr").email("[email protected]").build());
customerRepository.save(Customer.builder().name("chrissdf").email("[email protected]").build());
customerRepository.save(Customer.builder().name("lor").email("[email protected]").build());
};
}
}
CustomerRepository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
I clearly defined this in my property file:
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8084/login/oauth2/code/sdia3
spring.security.oauth2.client.registration.keycloak.issuer-uri=http://localhost:8080/realms/sdia3/account
is this not enough?
You have not set the
providerandregistrationproperties correctly for Keycloak:user-name-attributeis present forproviderconf, which is not enoughissuer-uriis aproviderproperty, not aregistrationone (your IDE should lint that)issuer-uriis probablyhttp://localhost:8080/realms/sdia3(and nothttp://localhost:8080/realms/sdia3/account)googleis), you should explicitly reference theproviderto use in theregistrationAs Keycloak is OIDC compliant, setting
spring.security.oauth2.client.provider.keycloak.issuer-uri=with the exact value of theissclaim in one of your tokens should be enough (even trailing slash, if any, and case are important). Spring will pull the rest of the conf from the.well-known/openid-configuration.Here is the configuration you're probably looking for (in the YAML format):
As you seem to be at the very beginning of your Spring with OAuth2 journey, you might find this tutorials I wrote useful.