Skip to content

Commit

Permalink
Merge pull request #555 from camunda-community-hub/backport/feature/s…
Browse files Browse the repository at this point in the history
…upport-old-and-new-operate-properties

[backport] Support old and new operate properties schema
  • Loading branch information
1nb0und authored Dec 13, 2023
2 parents 598309c + 9fae933 commit b5807d2
Show file tree
Hide file tree
Showing 12 changed files with 349 additions and 95 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,23 @@ zeebe.client.connection-mode=CLOUD
zeebe.client.connection-mode=ADDRESS
```

You can also configure other components like Operate. Note that you must set `operate.client.enabled` to `true`. If you use different credentials for different components:
You can also configure other components like Operate. If you use different credentials for different components:

```properties
operate.client.enabled=true
# Old scheme (will be deprecated soon)
camunda.operate.client.clientId=xxx
camunda.operate.client.clientSecret=xxx
```

```properties
# New scheme
operate.client.clientId=xxx
operate.client.clientSecret=xxx
```

Otherwise, if you use same credentials across all components:

```properties
operate.client.enabled=true
common.clientId=xxx
common.clientSecret=xxx
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package io.camunda.common.auth;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.invoke.MethodHandles;
import java.util.Map;

/**
* Default implementation for Authentication
* Typically you will replace this by a proper authentication by setting the right properties
*/
public class DefaultNoopAuthentication implements Authentication {

private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

@Override
public Authentication build() {
throw new UnsupportedOperationException("Unable to determine authentication");
LOG.error("Unable to determine authentication. Please check your configuration");
return this;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public SimpleAuthenticationBuilder simpleConfig(SimpleConfig simpleConfig) {
return this;
}

public SimpleAuthenticationBuilder simpleUrl(String simpleUrl) {
simpleAuthentication.setSimpleUrl(simpleUrl);
return this;
}

public Authentication build() {
return simpleAuthentication.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@
import io.camunda.zeebe.client.ZeebeClient;
import io.camunda.zeebe.client.api.JsonMapper;
import io.camunda.zeebe.client.impl.ZeebeObjectMapper;
import io.camunda.zeebe.spring.client.configuration.MetricsDefaultConfiguration;
import io.camunda.zeebe.spring.client.configuration.OperateClientProdAutoConfiguration;
import io.camunda.zeebe.spring.client.configuration.ZeebeActuatorConfiguration;
import io.camunda.zeebe.spring.client.configuration.ZeebeClientAllAutoConfiguration;
import io.camunda.zeebe.spring.client.configuration.ZeebeClientProdAutoConfiguration;
import io.camunda.zeebe.spring.client.configuration.CommonClientConfiguration;
import io.camunda.zeebe.spring.client.configuration.*;
import io.camunda.zeebe.spring.client.event.ZeebeLifecycleEventProducer;
import io.camunda.zeebe.spring.client.testsupport.SpringZeebeTestContext;
import org.slf4j.Logger;
Expand All @@ -36,10 +31,10 @@
ZeebeClientProdAutoConfiguration.class,
ZeebeClientAllAutoConfiguration.class,
CommonClientConfiguration.class,
CamundaOperateClientConfiguration.class, // deprecated
OperateClientProdAutoConfiguration.class,

ZeebeActuatorConfiguration.class,
MetricsDefaultConfiguration.class,
MetricsDefaultConfiguration.class
})
@AutoConfigureAfter(JacksonAutoConfiguration.class) // make sure Spring created ObjectMapper is preferred if available
public class CamundaAutoConfiguration {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.camunda.zeebe.spring.client.configuration;

import io.camunda.common.auth.Authentication;
import io.camunda.operate.CamundaOperateClient;
import io.camunda.operate.CamundaOperateClientBuilder;
import io.camunda.zeebe.spring.client.configuration.condition.CamundaOperateClientCondition;
import io.camunda.zeebe.spring.client.properties.CamundaOperateClientConfigurationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;

import java.lang.invoke.MethodHandles;

/**
* This will be deprecated once we move to the new schema (i.e. not prefixing with camunda.*)
*/
@Deprecated
@Conditional(CamundaOperateClientCondition.class)
@EnableConfigurationProperties(CamundaOperateClientConfigurationProperties.class)
public class CamundaOperateClientConfiguration {

private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

@Autowired
Authentication authentication;

@Bean
public CamundaOperateClient camundaOperateClient(CamundaOperateClientConfigurationProperties props) {
LOG.warn("Using a deprecated operate properties");
CamundaOperateClient client;
try {
client = new CamundaOperateClientBuilder()
.authentication(authentication)
.operateUrl(props.getOperateUrl())
.setup()
.build();
} catch (Exception e) {
LOG.warn("An attempt to connect to Operate failed: " + e);
throw new RuntimeException(e);
}
return client;
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -28,75 +28,88 @@ public class CommonClientConfiguration {
@Autowired(required = false)
TasklistClientConfigurationProperties tasklistClientConfigurationProperties;

// TODO: Remove below properties when we deprecate camunda.[product].client.*
@Autowired(required = false)
CamundaOperateClientConfigurationProperties camundaOperateClientConfigurationProperties;

@Bean
public Authentication authentication() {

// TODO: Refactor
if (zeebeClientConfigurationProperties != null) {
JwtConfig jwtConfig = new JwtConfig();

if (zeebeClientConfigurationProperties.isEnabled()) {
if (zeebeClientConfigurationProperties.getCloud().getClientId() != null && zeebeClientConfigurationProperties.getCloud().getClientSecret() != null) {
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(zeebeClientConfigurationProperties.getCloud().getClientId(), zeebeClientConfigurationProperties.getCloud().getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
// check if Zeebe has clusterId provided, then must be SaaS
if (zeebeClientConfigurationProperties.getCloud() != null) {
if (zeebeClientConfigurationProperties.getCloud().getClientId() != null) {
return SaaSAuthentication.builder()
.jwtConfig(configureJwtConfig())
.build();
}
}

if (operateClientConfigurationProperties != null) {
if (operateClientConfigurationProperties.getClientId() != null && operateClientConfigurationProperties.getClientSecret() != null && operateClientConfigurationProperties.getEnabled()) {
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(operateClientConfigurationProperties.getClientId(), operateClientConfigurationProperties.getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
} else if (zeebeClientConfigurationProperties.getBroker().getGatewayAddress() != null) {
// figure out if Self-Managed JWT or Self-Managed Basic
// TODO: Remove when we deprecate camunda.[product].client.*
if (camundaOperateClientConfigurationProperties != null) {
if (camundaOperateClientConfigurationProperties.getKeycloakUrl() != null) {
return SelfManagedAuthentication.builder()
.jwtConfig(configureJwtConfig())
.keycloakUrl(camundaOperateClientConfigurationProperties.getKeycloakUrl())
.keycloakRealm(camundaOperateClientConfigurationProperties.getKeycloakRealm())
.build();
} else if (camundaOperateClientConfigurationProperties.getUsername() != null && camundaOperateClientConfigurationProperties.getPassword() != null) {
SimpleConfig simpleConfig = new SimpleConfig();
SimpleCredential simpleCredential = new SimpleCredential(camundaOperateClientConfigurationProperties.getUsername(), camundaOperateClientConfigurationProperties.getPassword());
simpleConfig.addProduct(Product.OPERATE, simpleCredential);
return SimpleAuthentication.builder()
.simpleConfig(simpleConfig)
.simpleUrl(camundaOperateClientConfigurationProperties.getUrl())
.build();
}
}
}

if (consoleClientConfigurationProperties != null) {
if (consoleClientConfigurationProperties.getClientId() != null && consoleClientConfigurationProperties.getClientSecret() != null && consoleClientConfigurationProperties.getEnabled()) {
jwtConfig.addProduct(Product.CONSOLE, new JwtCredential(consoleClientConfigurationProperties.getClientId(), consoleClientConfigurationProperties.getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.CONSOLE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
if (commonConfigurationProperties != null) {
if (commonConfigurationProperties.getKeycloak().getUrl() != null) {
return SelfManagedAuthentication.builder()
.jwtConfig(configureJwtConfig())
.keycloakUrl(commonConfigurationProperties.getKeycloak().getUrl())
.keycloakRealm(commonConfigurationProperties.getKeycloak().getRealm())
.build();
} else if (commonConfigurationProperties.getUsername() != null && commonConfigurationProperties.getPassword() != null) {
SimpleConfig simpleConfig = new SimpleConfig();
SimpleCredential simpleCredential = new SimpleCredential(commonConfigurationProperties.getUsername(), commonConfigurationProperties.getPassword());
simpleConfig.addProduct(Product.OPERATE, simpleCredential);
return SimpleAuthentication.builder()
.simpleConfig(simpleConfig)
.simpleUrl(commonConfigurationProperties.getUrl())
.build();
}
}
}
}

if (optimizeClientConfigurationProperties != null) {
if (optimizeClientConfigurationProperties.getClientId() != null && optimizeClientConfigurationProperties.getClientSecret() != null && optimizeClientConfigurationProperties.getEnabled()) {
jwtConfig.addProduct(Product.OPTIMIZE, new JwtCredential(optimizeClientConfigurationProperties.getClientId(), optimizeClientConfigurationProperties.getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.OPTIMIZE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
}
return new DefaultNoopAuthentication().build();
}

private JwtConfig configureJwtConfig() {
JwtConfig jwtConfig = new JwtConfig();
if (zeebeClientConfigurationProperties.isEnabled()) {
if (zeebeClientConfigurationProperties.getCloud().getClientId() != null && zeebeClientConfigurationProperties.getCloud().getClientSecret() != null) {
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(zeebeClientConfigurationProperties.getCloud().getClientId(), zeebeClientConfigurationProperties.getCloud().getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
}
}

if (tasklistClientConfigurationProperties != null) {
if (tasklistClientConfigurationProperties.getClientId() != null && tasklistClientConfigurationProperties.getClientSecret() != null && tasklistClientConfigurationProperties.getEnabled()) {
jwtConfig.addProduct(Product.TASKLIST, new JwtCredential(tasklistClientConfigurationProperties.getClientId(), tasklistClientConfigurationProperties.getClientSecret()));
if (operateClientConfigurationProperties != null) {
if (operateClientConfigurationProperties.getEnabled()) {
if (operateClientConfigurationProperties.getClientId() != null && operateClientConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(operateClientConfigurationProperties.getClientId(), operateClientConfigurationProperties.getClientSecret()));
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
jwtConfig.addProduct(Product.TASKLIST, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(commonConfigurationProperties.getClientId(), commonConfigurationProperties.getClientSecret()));
}
}

if (commonConfigurationProperties != null && commonConfigurationProperties.getKeycloak().getUrl() != null) {
return SelfManagedAuthentication.builder()
.jwtConfig(jwtConfig)
.keycloakUrl(commonConfigurationProperties.getKeycloak().getUrl())
.keycloakRealm(commonConfigurationProperties.getKeycloak().getRealm())
.build();
} else {
return SaaSAuthentication.builder()
.jwtConfig(jwtConfig)
.build();
}
} else if (commonConfigurationProperties != null && commonConfigurationProperties.getUsername() != null) {
SimpleConfig simpleConfig = new SimpleConfig();
SimpleCredential common = new SimpleCredential(commonConfigurationProperties.getUsername(), commonConfigurationProperties.getPassword());
simpleConfig.addProduct(Product.OPERATE, common);
simpleConfig.addProduct(Product.CONSOLE, common);
simpleConfig.addProduct(Product.OPTIMIZE, common);
simpleConfig.addProduct(Product.TASKLIST, common);
return SimpleAuthentication.builder()
.simpleConfig(simpleConfig)
.build();
} else {
return new DefaultNoopAuthentication();
} else if (camundaOperateClientConfigurationProperties != null) {
// TODO: Remove this else if block when we deprecate camunda.[product].client.*
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(camundaOperateClientConfigurationProperties.getClientId(), camundaOperateClientConfigurationProperties.getClientSecret()));
}
return jwtConfig;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.camunda.common.auth.Authentication;
import io.camunda.operate.CamundaOperateClient;
import io.camunda.operate.CamundaOperateClientBuilder;
import io.camunda.zeebe.spring.client.configuration.condition.OperateClientCondition;
import io.camunda.zeebe.spring.client.properties.OperateClientConfigurationProperties;
import io.camunda.zeebe.spring.client.testsupport.SpringZeebeTestContext;
import org.slf4j.Logger;
Expand All @@ -12,10 +13,12 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;

import java.lang.invoke.MethodHandles;

@ConditionalOnProperty(prefix = "operate.client", name = "enabled", havingValue = "true", matchIfMissing = false)
@Conditional(OperateClientCondition.class)
@ConditionalOnProperty(prefix = "operate.client", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnMissingBean(SpringZeebeTestContext.class)
@EnableConfigurationProperties(OperateClientConfigurationProperties.class)
public class OperateClientProdAutoConfiguration {
Expand All @@ -36,10 +39,12 @@ public class OperateClientProdAutoConfiguration {

// TODO: Handle resiliency when connecting to Operate
@Bean
@ConditionalOnMissingBean
public CamundaOperateClient camundaOperateClient(OperateClientConfigurationProperties props) {
LOG.debug("Using a newer operate properties");
CamundaOperateClient client;
try {
client = new CamundaOperateClientBuilder()
client = new CamundaOperateClientBuilder()
.authentication(authentication)
.operateUrl(props.getOperateUrl())
.setup()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.camunda.zeebe.spring.client.configuration.condition;

import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

/**
* This will be deprecated once we move to the new schema (i.e. not prefixing with camunda.*)
*/
@Deprecated
public class CamundaOperateClientCondition extends AnyNestedCondition {
public CamundaOperateClientCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}

@ConditionalOnProperty(name = "camunda.operate.client.client-id")
static class ClientIdCondition {

}

@ConditionalOnProperty(name = "camunda.operate.client.username")
static class UsernameCondition {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.camunda.zeebe.spring.client.configuration.condition;

import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

public class OperateClientCondition extends AnyNestedCondition {
public OperateClientCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}

@ConditionalOnProperty(name = "operate.client.client-id")
static class ClientIdCondition {

}

@ConditionalOnProperty(name = "operate.client.username")
static class UsernameCondition {

}
}
Loading

0 comments on commit b5807d2

Please sign in to comment.