diff --git a/gateway/pom.xml b/gateway/pom.xml
index 959bcbeb..1460d4e4 100644
--- a/gateway/pom.xml
+++ b/gateway/pom.xml
@@ -66,6 +66,14 @@
lombok
true
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+ org.springframework.amqp
+ spring-rabbit
+
+
+ org.json
+ json
+ 20230618
+
diff --git a/gateway/src/main/java/org/georchestra/gateway/app/GeorchestraGatewayApplication.java b/gateway/src/main/java/org/georchestra/gateway/app/GeorchestraGatewayApplication.java
index f215b719..4b08b342 100644
--- a/gateway/src/main/java/org/georchestra/gateway/app/GeorchestraGatewayApplication.java
+++ b/gateway/src/main/java/org/georchestra/gateway/app/GeorchestraGatewayApplication.java
@@ -42,7 +42,6 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.reactive.result.view.Rendering;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
diff --git a/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsAutoConfiguration.java b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsAutoConfiguration.java
new file mode 100644
index 00000000..5d423ff5
--- /dev/null
+++ b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsAutoConfiguration.java
@@ -0,0 +1,37 @@
+package org.georchestra.gateway.events;
+
+import org.springframework.amqp.core.AmqpTemplate;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.amqp.core.Queue;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
+import org.springframework.context.annotation.*;
+
+@Profile("!test && !it")
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureAfter(GatewayAutoConfiguration.class)
+@ImportResource({ "classpath:rabbit-listener-context.xml", "classpath:rabbit-sender-context.xml" })
+@ConditionalOnExpression("${georchestra.gateway.security.enableRabbitmqEvents:true}")
+public class RabbitmqEventsAutoConfiguration {
+
+ @Bean
+ @DependsOn({ "eventTemplate" })
+ public RabbitmqEventsSender eventsSender(AmqpTemplate eventTemplate) {
+ return new RabbitmqEventsSender(eventTemplate);
+ }
+
+ Queue OAuth2ReplyQueue() {
+ return new Queue("OAuth2ReplyQueue", false);
+ }
+
+ MessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
+ SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
+ simpleMessageListenerContainer.setConnectionFactory(connectionFactory);
+ simpleMessageListenerContainer.setQueues(OAuth2ReplyQueue());
+ simpleMessageListenerContainer.setMessageListener(new RabbitmqEventsListener());
+ return simpleMessageListenerContainer;
+ }
+}
\ No newline at end of file
diff --git a/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsListener.java b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsListener.java
new file mode 100644
index 00000000..bb2f5b39
--- /dev/null
+++ b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsListener.java
@@ -0,0 +1,31 @@
+package org.georchestra.gateway.events;
+
+import lombok.extern.slf4j.Slf4j;
+import org.json.JSONObject;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageListener;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+@Slf4j(topic = "org.georchestra.gateway.events")
+public class RabbitmqEventsListener implements MessageListener {
+
+ public static final String OAUTH2_ACCOUNT_CREATION_RECEIVED = "OAUTH2-ACCOUNT-CREATION-RECEIVED";
+
+ private static Set synReceivedMessageUid = Collections.synchronizedSet(new HashSet());
+
+ public void onMessage(Message message) {
+ String messageBody = new String(message.getBody());
+ JSONObject jsonObj = new JSONObject(messageBody);
+ String uid = jsonObj.getString("uid");
+ String subject = jsonObj.getString("subject");
+ if (subject.equals(OAUTH2_ACCOUNT_CREATION_RECEIVED)
+ && !synReceivedMessageUid.stream().anyMatch(s -> s.equals(uid))) {
+ String msg = jsonObj.getString("msg");
+ synReceivedMessageUid.add(uid);
+ log.info(msg);
+ }
+ }
+}
\ No newline at end of file
diff --git a/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsSender.java b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsSender.java
new file mode 100644
index 00000000..7e46a787
--- /dev/null
+++ b/gateway/src/main/java/org/georchestra/gateway/events/RabbitmqEventsSender.java
@@ -0,0 +1,35 @@
+package org.georchestra.gateway.events;
+
+import org.json.JSONObject;
+import org.springframework.amqp.core.AmqpTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+
+import java.util.UUID;
+
+public class RabbitmqEventsSender {
+
+ public static final String OAUTH2_ACCOUNT_CREATION = "OAUTH2-ACCOUNT-CREATION";
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private AmqpTemplate eventTemplate;
+
+ public RabbitmqEventsSender(AmqpTemplate eventTemplate) {
+ this.eventTemplate = eventTemplate;
+ }
+
+ public void sendNewOAuthAccountMessage(String username, String email, String provider) throws Exception {
+ // beans
+ // getting a reference to
+ // the sender
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("uid", UUID.randomUUID());
+ jsonObj.put("subject", OAUTH2_ACCOUNT_CREATION);
+ jsonObj.put("username", username); // bean
+ jsonObj.put("email", email); // bean
+ jsonObj.put("provider", provider); // bean
+ eventTemplate.convertAndSend("routing-gateway", jsonObj.toString());// send
+ }
+}
\ No newline at end of file
diff --git a/gateway/src/main/java/org/georchestra/gateway/security/GatewaySecurityConfiguration.java b/gateway/src/main/java/org/georchestra/gateway/security/GatewaySecurityConfiguration.java
index e636f15f..14940e35 100644
--- a/gateway/src/main/java/org/georchestra/gateway/security/GatewaySecurityConfiguration.java
+++ b/gateway/src/main/java/org/georchestra/gateway/security/GatewaySecurityConfiguration.java
@@ -58,7 +58,7 @@ public class GatewaySecurityConfiguration {
* {@link ServerHttpSecurity#build build} the {@link SecurityWebFilterChain}.
*/
- @Autowired
+ @Autowired(required = false)
ServerLogoutSuccessHandler oidcLogoutSuccessHandler;
@Bean
@@ -82,8 +82,12 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http,
log.info("Security filter chain initialized");
- return http.formLogin().loginPage("/login").and().logout().logoutUrl("/logout")
- .logoutSuccessHandler(oidcLogoutSuccessHandler).and().build();
+ if (oidcLogoutSuccessHandler != null) {
+ return http.formLogin().loginPage("/login").and().logout().logoutUrl("/logout")
+ .logoutSuccessHandler(oidcLogoutSuccessHandler).and().build();
+ } else {
+ return http.formLogin().loginPage("/login").and().logout().logoutUrl("/logout").and().build();
+ }
}
private Stream sortedCustomizers(List customizers) {
diff --git a/gateway/src/main/java/org/georchestra/gateway/security/ldap/LdapConfigProperties.java b/gateway/src/main/java/org/georchestra/gateway/security/ldap/LdapConfigProperties.java
index 9c817ab0..a3159f0f 100644
--- a/gateway/src/main/java/org/georchestra/gateway/security/ldap/LdapConfigProperties.java
+++ b/gateway/src/main/java/org/georchestra/gateway/security/ldap/LdapConfigProperties.java
@@ -65,6 +65,8 @@ public class LdapConfigProperties implements Validator {
private boolean createNonExistingUsersInLDAP = true;
+ private boolean enableRabbitmqEvents = true;
+
@Valid
private Map ldap = Map.of();
diff --git a/gateway/src/main/java/org/georchestra/gateway/security/oauth2/OpenIdConnectUserMapper.java b/gateway/src/main/java/org/georchestra/gateway/security/oauth2/OpenIdConnectUserMapper.java
index 8e1dc768..646fe2fb 100644
--- a/gateway/src/main/java/org/georchestra/gateway/security/oauth2/OpenIdConnectUserMapper.java
+++ b/gateway/src/main/java/org/georchestra/gateway/security/oauth2/OpenIdConnectUserMapper.java
@@ -35,6 +35,7 @@
import org.georchestra.ds.security.UserMapperImpl;
import org.georchestra.ds.security.UsersApiImpl;
import org.georchestra.ds.users.*;
+import org.georchestra.gateway.events.RabbitmqEventsSender;
import org.georchestra.gateway.security.ldap.LdapConfigProperties;
import org.georchestra.security.model.GeorchestraUser;
import org.slf4j.Logger;
@@ -153,6 +154,9 @@ public class OpenIdConnectUserMapper extends OAuth2UserMapper {
@Autowired(required = false)
private RoleDao roleDao;
+ @Autowired(required = false)
+ private RabbitmqEventsSender eventsSender;
+
private final @NonNull OpenIdConnectCustomClaimsConfigProperties nonStandardClaimsConfig;
protected @Override Predicate tokenFilter() {
@@ -165,6 +169,7 @@ public class OpenIdConnectUserMapper extends OAuth2UserMapper {
}
protected @Override Optional map(OAuth2AuthenticationToken token) {
+
if (config.isCreateNonExistingUsersInLDAP()) {
String oAuth2ProviderId = String.format("%s;%s", token.getAuthorizedClientRegistrationId(),
token.getName());
@@ -190,12 +195,19 @@ public class OpenIdConnectUserMapper extends OAuth2UserMapper {
accountDao.insert(newAccount);
roleDao.addUser(Role.USER, newAccount);
userOpt = usersApi.findByOAuth2ProviderId(oAuth2ProviderId);
+ if (config.isEnableRabbitmqEvents() && eventsSender != null) {
+ eventsSender.sendNewOAuthAccountMessage(
+ oidcUser.getGivenName() + " " + oidcUser.getFamilyName(), oidcUser.getEmail(),
+ token.getAuthorizedClientRegistrationId());
+ }
} catch (DuplicatedUidException e) {
throw new IllegalStateException(e);
} catch (DuplicatedEmailException e) {
throw new IllegalStateException(e);
} catch (DataServiceException e) {
throw new IllegalStateException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
}
diff --git a/gateway/src/main/resources/META-INF/spring.factories b/gateway/src/main/resources/META-INF/spring.factories
index 95c56c86..156d9d89 100644
--- a/gateway/src/main/resources/META-INF/spring.factories
+++ b/gateway/src/main/resources/META-INF/spring.factories
@@ -4,4 +4,5 @@ org.georchestra.gateway.autoconfigure.security.WebSecurityAutoConfiguration,\
org.georchestra.gateway.autoconfigure.security.LdapSecurityAutoConfiguration,\
org.georchestra.gateway.autoconfigure.security.OAuth2SecurityAutoConfiguration,\
org.georchestra.gateway.autoconfigure.app.FiltersAutoConfiguration,\
-org.georchestra.gateway.autoconfigure.app.RoutePredicateFactoriesAutoConfiguration
\ No newline at end of file
+org.georchestra.gateway.autoconfigure.app.RoutePredicateFactoriesAutoConfiguration,\
+org.georchestra.gateway.events.RabbitmqEventsAutoConfiguration
\ No newline at end of file
diff --git a/gateway/src/main/resources/application.yml b/gateway/src/main/resources/application.yml
index 38b8e450..f8b964f1 100644
--- a/gateway/src/main/resources/application.yml
+++ b/gateway/src/main/resources/application.yml
@@ -133,6 +133,7 @@ logging:
'[org.georchestra.gateway.config.security.accessrules]': debug
'[org.georchestra.gateway.security.ldap]': debug
'[org.georchestra.gateway.security.oauth2]': debug
+ '[org.georchestra.gateway.events]': debug
---
spring.config.activate.on-profile: dev
diff --git a/gateway/src/main/resources/rabbit-listener-context.xml b/gateway/src/main/resources/rabbit-listener-context.xml
new file mode 100644
index 00000000..78183e3b
--- /dev/null
+++ b/gateway/src/main/resources/rabbit-listener-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gateway/src/main/resources/rabbit-sender-context.xml b/gateway/src/main/resources/rabbit-sender-context.xml
new file mode 100644
index 00000000..dc368c9d
--- /dev/null
+++ b/gateway/src/main/resources/rabbit-sender-context.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
\ No newline at end of file