From 129fcbe58b3216984049d82a644c30945fee3ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Jim=C3=A9nez?= Date: Thu, 17 Oct 2024 17:02:54 +0200 Subject: [PATCH] feat: first commit importing old project --- .github/workflows/release.yml | 60 ++++++++++++++++ .gitignore | 2 + README.md | 7 ++ pom.xml | 59 +++++++++++++++ .../WebhookEventListenerProvider.java | 71 +++++++++++++++++++ .../WebhookEventListenerProviderFactory.java | 41 +++++++++++ ...ycloak.events.EventListenerProviderFactory | 1 + .../java/com/example/keycloak/AppTest.java | 18 +++++ 8 files changed, 259 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 pom.xml create mode 100644 src/main/java/com/example/keycloak/WebhookEventListenerProvider.java create mode 100644 src/main/java/com/example/keycloak/WebhookEventListenerProviderFactory.java create mode 100644 src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory create mode 100644 src/test/java/com/example/keycloak/AppTest.java diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..16b6a8a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,60 @@ +name: Build and Release + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '11' + + - name: Build with Maven + run: mvn clean package + + - name: Upload JAR as artifact + uses: actions/upload-artifact@v3 + with: + name: keycloak-webhook-listener + path: target/*.jar + + # Comment the release workflow for now, as we lack the permissions to create a release on GitHub + # release: + # needs: build + # runs-on: ubuntu-latest + # steps: + # - name: Download JAR artifact + # uses: actions/download-artifact@v3 + # with: + # name: keycloak-webhook-listener + + # - name: Create Release + # id: create_release + # uses: actions/create-release@v1 + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # with: + # tag_name: v1.0.${{ github.run_number }} + # release_name: Release v1.0.${{ github.run_number }} + # draft: false + # prerelease: false + + # - name: Upload JAR to Release + # uses: actions/upload-release-asset@v1 + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # with: + # upload_url: ${{ steps.create_release.outputs.upload_url }} + # asset_path: target/*.jar + # asset_name: keycloak-webhook-listener.jar + # asset_content_type: application/java-archive diff --git a/.gitignore b/.gitignore index 524f096..acc6b3c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* replay_pid* + +target/ diff --git a/README.md b/README.md index 39e32a8..2d4ec1e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # keycloak-webhook-listener + Custom listener for using webhooks in Keycloak + +To build the project, run: + +``` +mvn clean package +``` diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8db57db --- /dev/null +++ b/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + com.example.keycloak + keycloak-webhook-listener + jar + 1.0.0 + keycloak-webhook-listener + http://maven.apache.org + + + org.keycloak + keycloak-core + ${keycloak.version} + provided + + + org.keycloak + keycloak-server-spi + ${keycloak.version} + provided + + + org.keycloak + keycloak-server-spi-private + ${keycloak.version} + provided + + + org.keycloak + keycloak-services + ${keycloak.version} + provided + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + junit + junit + 4.13.2 + test + + + + com.fasterxml.jackson.core + jackson-databind + 2.11.3 + + + + 20.0.5 + 11 + 11 + + diff --git a/src/main/java/com/example/keycloak/WebhookEventListenerProvider.java b/src/main/java/com/example/keycloak/WebhookEventListenerProvider.java new file mode 100644 index 0000000..9702f5d --- /dev/null +++ b/src/main/java/com/example/keycloak/WebhookEventListenerProvider.java @@ -0,0 +1,71 @@ +package com.example.keycloak; + +import org.keycloak.events.Event; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.admin.AdminEvent; +import org.keycloak.models.KeycloakSession; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class WebhookEventListenerProvider implements EventListenerProvider { + private static final Logger logger = LoggerFactory.getLogger(WebhookEventListenerProvider.class); + private final KeycloakSession session; + + public WebhookEventListenerProvider(KeycloakSession session) { + this.session = session; + } + + @Override + public void onEvent(Event event) { + logger.info("Received event: {}", event); + String realmName = session.getContext().getRealm().getName(); + String webhookUrl = getWebhookUrlForRealm(realmName); + sendWebhook("USER_EVENT", event, webhookUrl); + } + + private String getWebhookUrlForRealm(String realmName) { + String envVarName = "WEBHOOK_URL_" + realmName.toUpperCase().replace("-", "_"); + String webhookUrl = System.getenv(envVarName); + if (webhookUrl == null) { + throw new IllegalArgumentException("Webhook URL not specified for realm: " + realmName + + ". Please set the WEBHOOK_URL_" + realmName.toUpperCase().replace("-", "_) environment variable.")); + } + return webhookUrl; + } + + @Override + public void onEvent(AdminEvent event, boolean includeRepresentation) { + logger.info("Received admin event: {}", event); + String realmName = session.getContext().getRealm().getName(); + String webhookUrl = getWebhookUrlForRealm(realmName); + sendWebhook("ADMIN_EVENT", event, webhookUrl); + } + + @Override + public void close() { + logger.info("Closing WebhookEventListenerProvider"); + } + + private void sendWebhook(String type, Object event, String webhookUrl) { + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(webhookUrl); + httpPost.setHeader("Content-Type", "application/json"); + + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(event); + + httpPost.setEntity(new StringEntity(json)); + + logger.info("Sending webhook for event type: {}", type); + client.execute(httpPost); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/example/keycloak/WebhookEventListenerProviderFactory.java b/src/main/java/com/example/keycloak/WebhookEventListenerProviderFactory.java new file mode 100644 index 0000000..9eb7d0c --- /dev/null +++ b/src/main/java/com/example/keycloak/WebhookEventListenerProviderFactory.java @@ -0,0 +1,41 @@ +package com.example.keycloak; + +import org.keycloak.models.KeycloakSession; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.EventListenerProviderFactory; +import org.jboss.logging.Logger; + +public class WebhookEventListenerProviderFactory implements EventListenerProviderFactory { + + private static final Logger logger = Logger.getLogger(WebhookEventListenerProviderFactory.class); + + @Override + public EventListenerProvider create(KeycloakSession session) { + logger.info("Creating WebhookEventListenerProvider"); + return new WebhookEventListenerProvider(session); + } + + @Override + public void init(org.keycloak.Config.Scope config) { + // Initialize configuration if needed + logger.info("Initializing WebhookEventListenerProviderFactory"); + } + + @Override + public void postInit(org.keycloak.models.KeycloakSessionFactory factory) { + // Post-initialization configuration if needed + logger.info("Post-initializing WebhookEventListenerProviderFactory"); + } + + @Override + public void close() { + // Cleanup resources if needed + logger.info("Closing WebhookEventListenerProviderFactory"); + } + + @Override + public String getId() { + // This ID should be unique and used to identify the provider in Keycloak + return "webhook-event-listener"; + } +} diff --git a/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory new file mode 100644 index 0000000..695a577 --- /dev/null +++ b/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory @@ -0,0 +1 @@ +com.example.keycloak.WebhookEventListenerProviderFactory diff --git a/src/test/java/com/example/keycloak/AppTest.java b/src/test/java/com/example/keycloak/AppTest.java new file mode 100644 index 0000000..038b056 --- /dev/null +++ b/src/test/java/com/example/keycloak/AppTest.java @@ -0,0 +1,18 @@ +package com.example.keycloak; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +/** + * Unit test for simple App. + */ +public class AppTest { + + /** + * Rigorous Test :-) + */ + @Test + public void testApp() { + assertTrue(true); + } +}