diff --git a/src/main/java/openfoodfacts/github/keycloak/events/OpenFoodFactsEventListenerProviderFactory.java b/src/main/java/openfoodfacts/github/keycloak/events/OpenFoodFactsEventListenerProviderFactory.java index 8580e7f8..11cec106 100644 --- a/src/main/java/openfoodfacts/github/keycloak/events/OpenFoodFactsEventListenerProviderFactory.java +++ b/src/main/java/openfoodfacts/github/keycloak/events/OpenFoodFactsEventListenerProviderFactory.java @@ -11,6 +11,7 @@ import org.keycloak.events.admin.AdminEvent; import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.ResourceType; +import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; @@ -56,8 +57,10 @@ public void onEvent(Event event) { boolean isUserRegistrationEvent = isUserRegistrationEvent(event, realm); if (isUserRegistrationEvent) { final UserModel user = keycloakSession.users().getUserById(realm, event.getUserId()); + if (user.getFirstAttribute(UserAttributes.REGISTERED) == null) { - OpenFoodFactsEventListenerProviderFactory.this.client.postUserRegistered(user, realm); + // Note that for normal events the clientId is the normal clientId, not the internal GUID + OpenFoodFactsEventListenerProviderFactory.this.client.postUserRegistered(user, realm, event.getClientId()); user.setSingleAttribute(UserAttributes.REGISTERED, UserAttributes.REGISTERED); } } @@ -79,9 +82,16 @@ public void onEvent(AdminEvent event, boolean includeRepresentation) { return; } + // Note for admin events the clientId in the AuthDetails is the internal GUID + final ClientModel client = keycloakSession.clients().getClientById(realm, event.getAuthDetails().getClientId()); + if (client == null) { + log.errorf("Failed to find client: %s", event.getAuthDetails().getClientId()); + return; + } + if ((!realm.isVerifyEmail() || user.isEmailVerified()) && user.getFirstAttribute(UserAttributes.REGISTERED) == null) { - OpenFoodFactsEventListenerProviderFactory.this.client.postUserRegistered(user, realm); + OpenFoodFactsEventListenerProviderFactory.this.client.postUserRegistered(user, realm, client.getClientId()); user.setSingleAttribute(UserAttributes.REGISTERED, UserAttributes.REGISTERED); } } diff --git a/src/main/java/openfoodfacts/github/keycloak/events/RedisClient.java b/src/main/java/openfoodfacts/github/keycloak/events/RedisClient.java index fbd0d705..94b4b3a6 100644 --- a/src/main/java/openfoodfacts/github/keycloak/events/RedisClient.java +++ b/src/main/java/openfoodfacts/github/keycloak/events/RedisClient.java @@ -20,7 +20,7 @@ public RedisClient(final String url) { this.jedis = new JedisPooled(url); } - public void postUserRegistered(final UserModel user, final RealmModel realm) { + public void postUserRegistered(final UserModel user, final RealmModel realm, final String clientId) { if (user == null) { throw new IllegalArgumentException("user"); } @@ -37,6 +37,8 @@ public void postUserRegistered(final UserModel user, final RealmModel realm) { final String requestedOrg = user.getFirstAttribute(UserAttributes.REQUESTED_ORG); putIfNotNull(additionalData, "requestedOrg", requestedOrg); + additionalData.put("clientId", clientId); + postUserEvent("user-registered", user, realm, additionalData); } diff --git a/src/test/java/openfoodfacts/github/keycloak/events/EmailVerificationEventIsForwardedToRedisIfValidationIsEnabledTest.java b/src/test/java/openfoodfacts/github/keycloak/events/EmailVerificationEventIsForwardedToRedisIfValidationIsEnabledTest.java index caf3e30d..33289ec1 100644 --- a/src/test/java/openfoodfacts/github/keycloak/events/EmailVerificationEventIsForwardedToRedisIfValidationIsEnabledTest.java +++ b/src/test/java/openfoodfacts/github/keycloak/events/EmailVerificationEventIsForwardedToRedisIfValidationIsEnabledTest.java @@ -57,6 +57,10 @@ public EventType getType() { return EventType.VERIFY_EMAIL; } + @Override + public String getClientId() { + return "test-client-client-id"; + } }); // Assert @@ -75,6 +79,7 @@ public EventType getType() { Assertions.assertEquals("theUserName", fields.get("userName")); Assertions.assertEquals("open-products-facts", fields.get("realm")); Assertions.assertEquals("subscribe", fields.get("newsletter")); + Assertions.assertEquals("test-client-client-id", fields.get("clientId")); } } diff --git a/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsDisabledTest.java b/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsDisabledTest.java index 2677ce17..b0476077 100644 --- a/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsDisabledTest.java +++ b/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsDisabledTest.java @@ -57,6 +57,10 @@ public EventType getType() { return EventType.REGISTER; } + @Override + public String getClientId() { + return "test-client-client-id"; + } }); // Assert @@ -74,6 +78,7 @@ public EventType getType() { Assertions.assertEquals("someUser@example.org", fields.get("email")); Assertions.assertEquals("theUserName", fields.get("userName")); Assertions.assertEquals("open-products-facts", fields.get("realm")); + Assertions.assertEquals("test-client-client-id", fields.get("clientId")); } } diff --git a/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsEnabledButValidated.java b/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsEnabledButValidated.java index cc7c304a..414193fa 100644 --- a/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsEnabledButValidated.java +++ b/src/test/java/openfoodfacts/github/keycloak/events/UserRegisteredEventIsForwardedToRedisIfValidationIsEnabledButValidated.java @@ -59,7 +59,7 @@ public EventType getType() { @Override public String getClientId() { - return "test-client-id"; + return "test-client-client-id"; } }); @@ -78,7 +78,7 @@ public String getClientId() { Assertions.assertEquals("someUser@example.org", fields.get("email")); Assertions.assertEquals("theUserName", fields.get("userName")); Assertions.assertEquals("open-products-facts", fields.get("realm")); - Assertions.assertEquals("test-client-id", fields.get("clientId")); + Assertions.assertEquals("test-client-client-id", fields.get("clientId")); } } diff --git a/tests/login.spec.ts b/tests/login.spec.ts index 810c00c0..2d4610b6 100644 --- a/tests/login.spec.ts +++ b/tests/login.spec.ts @@ -93,7 +93,8 @@ test("locale from app is respected", async ({ page }) => { const myMessage2 = await redisClient.getMessageForUser(userName); expect(myMessage2).toBeTruthy(); - + expect(myMessage2?.message.clientId).toBe(process.env.TEST_CLIENT_ID); + // Fetch the user via API and make sure locale is set correctly const headers = await getKeycloakHeaders(); const users = await (await fetch(`${keycloakUserUrl}?exact=true&username=${userName}`, {headers})).json(); diff --git a/tests/register.spec.ts b/tests/register.spec.ts index 96fd61eb..a9da8a0e 100644 --- a/tests/register.spec.ts +++ b/tests/register.spec.ts @@ -66,6 +66,7 @@ test("newsletter and producer fields", async ({ page }) => { expect(myMessage).toBeTruthy(); expect(myMessage?.message.newsletter).toBe('subscribe'); expect(myMessage?.message.requestedOrg).toBe('carrefour'); + expect(myMessage?.message.clientId).toBe('account-console'); // Newsletter field should be hidden on edit await expect(page.getByLabel('^newsletter_description^')).not.toBeVisible(); @@ -109,7 +110,7 @@ test("user created by API doesn't need email verification", async ({page}) => { expect(myMessage?.message.clientId).toBe(process.env.TEST_CLIENT_ID); }); -test("migrated user with invlaid email loaded with no messages", async ({page}) => { +test("migrated user with invalid email loaded with no messages", async ({page}) => { const redisClient = await createRedisClient('user-registered'); const {userName, password, email} = generateRandomUser();