From 39a94a66396722752fa5bdcdc29ecb6680836bd3 Mon Sep 17 00:00:00 2001 From: Christophe Date: Mon, 1 Aug 2022 11:53:16 +0200 Subject: [PATCH] Add the connection to a local setup with identity and keycloak --- README.md | 10 +- build.gradle | 2 +- .../camunda/operate/CamundaOperateClient.java | 11 ++- .../auth/LocalIdentityAuthentication.java | 95 +++++++++++++++++++ 4 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/camunda/operate/auth/LocalIdentityAuthentication.java diff --git a/README.md b/README.md index f05b8f9..ec98c38 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ List incidents = client.searchIncidents(incidentQuery); Incident incident = client.getIncident(incidents.get(0).getKey()); ``` +# Authentication +You can use the ***SimpleAuthentication*** to connect to a local Camunda TaskList if your setup is "simple": ***without identity and keycloak***. To connect to the **SaaS** Operate, you need to use the **SaasAuthentication** rather than the SimpleAuthentication. The SaaSAuthentication requires the ClientId and SecretId @@ -67,8 +69,14 @@ To connect to the **SaaS** Operate, you need to use the **SaasAuthentication** r SaasAuthentication sa = new SaasAuthentication("2~nB1MwkUU45FuXXX", "aBRKtreXQF3uD2MYYY"); CamundaOperateClient client = new CamundaOperateClient.Builder().authentication(sa) .taskListUrl("https://bru-2.tasklist.camunda.io/757dbc30-5127-4bed-XXXX-XXXXXXXXXXXX").build(); +``` +To connect to the **Local** TaskList with **Identity & Keycloak**, you need to use the **LocalIdentityAuthentication**. The SaaSAuthentication requires the clientId and clientSecret. You can also change the Keycloak realm and the baseUrl depending on your installation. +```java +LocalIdentityAuthentication la = new LocalIdentityAuthentication().clientId("java").clientSecret("foTPogjlI0hidwbDZcYFWzmU8FOQwLx0").baseUrl("http://localhost:18080").keycloakRealm("camunda-platform"); +CamundaOperateClient client = new CamundaOperateClient.Builder().authentication(la) + .operateUrl("http://localhost:8081/").build(); ``` # Use the Beta client @@ -92,7 +100,7 @@ You can import it to your maven or gradle project as a dependency io.camunda camunda-operate-client-java - 1.0.3 + 1.1.0 ``` diff --git a/build.gradle b/build.gradle index 1af864e..83381ec 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'io.camunda' -version = '1.0.3' +version = '1.1.0' sourceCompatibility = '8' repositories { diff --git a/src/main/java/io/camunda/operate/CamundaOperateClient.java b/src/main/java/io/camunda/operate/CamundaOperateClient.java index 12597b5..40e90e3 100644 --- a/src/main/java/io/camunda/operate/CamundaOperateClient.java +++ b/src/main/java/io/camunda/operate/CamundaOperateClient.java @@ -209,7 +209,7 @@ public Builder authentication(AuthInterface authentication) { } public Builder operateUrl(String operateUrl) { - this.operateUrl = operateUrl; + this.operateUrl = formatUrl(operateUrl); return this; } @@ -224,5 +224,14 @@ public CamundaOperateClient build() throws OperateException { authentication.authenticate(client); return client; } + + private String formatUrl(String url) { + if (url.endsWith("/")) { + return url.substring(0, url.length()-1); + } + return url; + } } + + } diff --git a/src/main/java/io/camunda/operate/auth/LocalIdentityAuthentication.java b/src/main/java/io/camunda/operate/auth/LocalIdentityAuthentication.java new file mode 100644 index 0000000..ec7fbfd --- /dev/null +++ b/src/main/java/io/camunda/operate/auth/LocalIdentityAuthentication.java @@ -0,0 +1,95 @@ +package io.camunda.operate.auth; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import org.apache.hc.core5.http.message.BasicHeader; + +import com.fasterxml.jackson.databind.JsonNode; + +import io.camunda.operate.CamundaOperateClient; +import io.camunda.operate.exception.OperateException; +import io.camunda.operate.util.JsonUtils; + +public class LocalIdentityAuthentication implements AuthInterface { + + private String clientId; + private String clientSecret; + private String baseUrl = "http://localhost:18080"; + private String keycloakRealm = "camunda-platform"; + + public LocalIdentityAuthentication() { + } + + public LocalIdentityAuthentication(String clientId, String clientSecret) { + this.clientId = clientId; + this.clientSecret = clientSecret; + } + + public LocalIdentityAuthentication clientId(String clientId) { + this.clientId = clientId; + return this; + } + public LocalIdentityAuthentication clientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + public LocalIdentityAuthentication baseUrl(String url) { + this.baseUrl = url; + return this; + } + public LocalIdentityAuthentication keycloakRealm(String keycloakRealm) { + this.keycloakRealm = keycloakRealm; + return this; + } + + private String encode(String value) throws UnsupportedEncodingException { + return URLEncoder.encode(value, StandardCharsets.UTF_8); + } + + private String getConnectionString() throws UnsupportedEncodingException{ + return "grant_type=client_credentials&client_id="+encode(clientId)+"&client_secret="+encode(clientSecret); + } + + @Override + public void authenticate(CamundaOperateClient client) throws OperateException { + try { + URL url = new URL(this.baseUrl+"/auth/realms/"+keycloakRealm+"/protocol/openid-connect/token"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setUseCaches(false); + conn.setConnectTimeout(1000 * 5); + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + + String data = getConnectionString(); + + conn.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); + conn.connect(); + + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"))) { + StringBuilder response = new StringBuilder(); + String responseLine = null; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + JsonNode responseBody = JsonUtils.toJsonNode(response.toString()); + String token = responseBody.get("access_token").asText(); + client.setAuthHeader(new BasicHeader("Authorization", "Bearer " + token)); + } + } else { + throw new OperateException("Error "+conn.getResponseCode()+" obtaining access token : "+conn.getResponseMessage()); + } + } catch (IOException e) { + throw new OperateException(e); + } + } +}