Skip to content

Commit ed2b428

Browse files
committed
feat(identity): support identity authentication for Zeebe
1 parent baf86fe commit ed2b428

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

camunda-sdk-java/java-common/src/main/java/io/camunda/common/auth/SelfManagedAuthentication.java

+33-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package io.camunda.common.auth;
22

33
import io.camunda.common.auth.identity.IdentityConfig;
4+
import io.camunda.common.exception.SdkException;
45
import io.camunda.identity.sdk.Identity;
56
import io.camunda.identity.sdk.authentication.Tokens;
6-
import io.camunda.identity.sdk.authentication.exception.TokenExpiredException;
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
99

@@ -14,10 +14,30 @@
1414

1515
public class SelfManagedAuthentication extends JwtAuthentication {
1616

17+
private static class Token {
18+
19+
public static final long EXPIRATION_BUFFER = 60 * 1000; // 1 minute
20+
private final String accessToken;
21+
private final long expiresAtMillis;
22+
23+
public Token(String accessToken, long expiresInSeconds) {
24+
this.accessToken = accessToken;
25+
expiresAtMillis = System.currentTimeMillis() + expiresInSeconds * 1000 - EXPIRATION_BUFFER;
26+
}
27+
28+
public String getAccessToken() {
29+
return accessToken;
30+
}
31+
32+
public boolean isExpired() {
33+
return expiresAtMillis < System.currentTimeMillis();
34+
}
35+
}
36+
1737
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
1838
private JwtConfig jwtConfig;
1939
private IdentityConfig identityConfig;
20-
private Map<Product, String> tokens;
40+
private final Map<Product, Token> tokens;
2141

2242
public SelfManagedAuthentication() {
2343
tokens = new HashMap<>();
@@ -51,24 +71,27 @@ public void resetToken(Product product) {
5171

5272
@Override
5373
public Map.Entry<String, String> getTokenHeader(Product product) {
54-
String token;
55-
if (tokens.containsKey(product)) {
56-
token = tokens.get(product);
57-
} else {
74+
Token token = tokens.computeIfAbsent(product, k -> getIdentityToken(product));
75+
if (token.isExpired()) {
76+
LOG.debug("Token for product {} is expired. Requesting new token", product);
5877
token = getIdentityToken(product);
5978
saveToken(product, token);
6079
}
61-
return new AbstractMap.SimpleEntry<>("Authorization", "Bearer " + token);
80+
return new AbstractMap.SimpleEntry<>("Authorization", "Bearer " + token.getAccessToken());
6281
}
6382

64-
private String getIdentityToken(Product product) {
83+
private Token getIdentityToken(Product product) {
6584
Identity identity = identityConfig.get(product).getIdentity();
6685
String audience = jwtConfig.getProduct(product).getAudience();
6786
Tokens identityTokens = identity.authentication().requestToken(audience);
68-
return identityTokens.getAccessToken();
87+
if (identityTokens.getAccessToken() == null) {
88+
throw new SdkException("Unable to get access token from identity");
89+
}
90+
LOG.debug("Received new token for product {}", product);
91+
return new Token(identityTokens.getAccessToken(), identityTokens.getExpiresIn());
6992
}
7093

71-
private void saveToken(Product product, String token) {
94+
private void saveToken(Product product, Token token) {
7295
tokens.put(product, token);
7396
}
7497
}

spring-boot-starter-camunda/src/main/java/io/camunda/zeebe/spring/client/configuration/CommonClientConfiguration.java

+54
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.camunda.identity.sdk.IdentityConfiguration;
88
import io.camunda.identity.sdk.Identity;
99
import io.camunda.zeebe.spring.client.properties.*;
10+
import org.slf4j.Logger;
1011
import org.springframework.beans.factory.annotation.Autowired;
1112
import org.springframework.boot.context.properties.EnableConfigurationProperties;
1213
import org.springframework.context.annotation.Bean;
@@ -16,6 +17,8 @@
1617
@EnableConfigurationProperties({CommonConfigurationProperties.class, ZeebeSelfManagedProperties.class})
1718
public class CommonClientConfiguration {
1819

20+
private final static Logger LOG = org.slf4j.LoggerFactory.getLogger(CommonClientConfiguration.class);
21+
1922

2023
@Autowired(required = false)
2124
CommonConfigurationProperties commonConfigurationProperties;
@@ -120,26 +123,39 @@ private JwtConfig configureJwtConfig() {
120123
JwtConfig jwtConfig = new JwtConfig();
121124
// ZEEBE
122125
if (zeebeClientConfigurationProperties.getCloud().getClientId() != null && zeebeClientConfigurationProperties.getCloud().getClientSecret() != null) {
126+
LOG.info("Using Cloud properties to determine credentials for Zeebe");
123127
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(
124128
zeebeClientConfigurationProperties.getCloud().getClientId(),
125129
zeebeClientConfigurationProperties.getCloud().getClientSecret(),
126130
zeebeClientConfigurationProperties.getCloud().getAudience(),
127131
zeebeClientConfigurationProperties.getCloud().getAuthUrl())
128132
);
129133
} else if (zeebeSelfManagedProperties.getClientId() != null && zeebeSelfManagedProperties.getClientSecret() != null) {
134+
LOG.info("Using Self Managed properties to determine credentials for Zeebe");
130135
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(
131136
zeebeSelfManagedProperties.getClientId(),
132137
zeebeSelfManagedProperties.getClientSecret(),
133138
zeebeSelfManagedProperties.getAudience(),
134139
zeebeSelfManagedProperties.getAuthServer())
135140
);
136141
} else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
142+
LOG.info("Using Common properties to determine credentials for Zeebe");
137143
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(
138144
commonConfigurationProperties.getClientId(),
139145
commonConfigurationProperties.getClientSecret(),
140146
zeebeClientConfigurationProperties.getCloud().getAudience(),
141147
zeebeClientConfigurationProperties.getCloud().getAuthUrl())
142148
);
149+
} else if (identityConfigurationFromProperties != null
150+
&& hasText(identityConfigurationFromProperties.getClientId())
151+
&& hasText(identityConfigurationFromProperties.getClientSecret())) {
152+
LOG.info("Using Identity SDK credentials for Zeebe");
153+
jwtConfig.addProduct(Product.ZEEBE, new JwtCredential(
154+
identityConfigurationFromProperties.getClientId(),
155+
identityConfigurationFromProperties.getClientSecret(),
156+
identityConfigurationFromProperties.getAudience(),
157+
identityConfigurationFromProperties.getIssuerBackendUrl())
158+
);
143159
}
144160

145161
// OPERATE
@@ -160,20 +176,25 @@ private JwtConfig configureJwtConfig() {
160176
}
161177

162178
if (operateClientConfigurationProperties.getClientId() != null && operateClientConfigurationProperties.getClientSecret() != null) {
179+
LOG.info("Using Operate Client properties to determine credentials for Operate");
163180
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(operateClientConfigurationProperties.getClientId(), operateClientConfigurationProperties.getClientSecret(), operateAudience, operateAuthUrl));
164181
} else if (identityConfigurationFromProperties != null && hasText(identityConfigurationFromProperties.getClientId()) && hasText(identityConfigurationFromProperties.getClientSecret())) {
182+
LOG.info("Using Identity SDK credentials for Operate");
165183
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(identityConfigurationFromProperties.getClientId(), identityConfigurationFromProperties.getClientSecret(), identityConfigurationFromProperties.getAudience(), identityConfigurationFromProperties.getIssuerBackendUrl()));
166184
}
167185
else if (commonConfigurationProperties.getClientId() != null && commonConfigurationProperties.getClientSecret() != null) {
186+
LOG.info("Using Common properties to determine credentials for Operate");
168187
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(
169188
commonConfigurationProperties.getClientId(),
170189
commonConfigurationProperties.getClientSecret(),
171190
operateAudience,
172191
operateAuthUrl)
173192
);
174193
} else if (zeebeClientConfigurationProperties.getCloud().getClientId() != null && zeebeClientConfigurationProperties.getCloud().getClientSecret() != null) {
194+
LOG.info("Using Zeebe Cloud properties to determine credentials for Operate");
175195
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(zeebeClientConfigurationProperties.getCloud().getClientId(), zeebeClientConfigurationProperties.getCloud().getClientSecret(), operateAudience, operateAuthUrl));
176196
} else if (zeebeSelfManagedProperties.getClientId() != null && zeebeSelfManagedProperties.getClientSecret() != null) {
197+
LOG.info("Using Zeebe Self Managed properties to determine credentials for Operate");
177198
jwtConfig.addProduct(Product.OPERATE, new JwtCredential(zeebeSelfManagedProperties.getClientId(), zeebeSelfManagedProperties.getClientSecret(), operateAudience, operateAuthUrl));
178199
} else {
179200
throw new SdkException("Unable to determine OPERATE credentials");
@@ -191,6 +212,11 @@ private IdentityConfig configureIdentities(JwtConfig jwtConfig) {
191212
IdentityContainer operateIdentityContainer = configureOperateIdentityContainer(jwtConfig);
192213
identityConfig.addProduct(Product.OPERATE, operateIdentityContainer);
193214
}
215+
// ZEEBE
216+
if (zeebeClientConfigurationProperties != null) {
217+
IdentityContainer zeebeIdentityContainer = configureZeebeIdentityContainer(jwtConfig);
218+
identityConfig.addProduct(Product.ZEEBE, zeebeIdentityContainer);
219+
}
194220
return identityConfig;
195221
}
196222

@@ -227,4 +253,32 @@ private IdentityContainer configureOperateIdentityContainer(JwtConfig jwtConfig)
227253
Identity operateIdentity = new Identity(operateIdentityConfiguration);
228254
return new IdentityContainer(operateIdentity, operateIdentityConfiguration);
229255
}
256+
257+
private IdentityContainer configureZeebeIdentityContainer(JwtConfig jwtConfig) {
258+
String issuer;
259+
String issuerBackendUrl;
260+
if (hasText(identityConfigurationFromProperties.getIssuer())) {
261+
issuer = identityConfigurationFromProperties.getIssuer();
262+
} else {
263+
issuer = jwtConfig.getProduct(Product.ZEEBE).getAuthUrl();
264+
}
265+
266+
if (hasText(identityConfigurationFromProperties.getIssuerBackendUrl())) {
267+
issuerBackendUrl = identityConfigurationFromProperties.getIssuerBackendUrl();
268+
} else {
269+
issuerBackendUrl = jwtConfig.getProduct(Product.ZEEBE).getAuthUrl();
270+
}
271+
272+
IdentityConfiguration zeebeIdentityConfiguration = new IdentityConfiguration.Builder()
273+
.withBaseUrl(identityConfigurationFromProperties.getBaseUrl())
274+
.withIssuer(issuer)
275+
.withIssuerBackendUrl(issuerBackendUrl)
276+
.withClientId(jwtConfig.getProduct(Product.ZEEBE).getClientId())
277+
.withClientSecret(jwtConfig.getProduct(Product.ZEEBE).getClientSecret())
278+
.withAudience(jwtConfig.getProduct(Product.ZEEBE).getAudience())
279+
.withType(identityConfigurationFromProperties.getType().name())
280+
.build();
281+
Identity zeebeIdentity = new Identity(zeebeIdentityConfiguration);
282+
return new IdentityContainer(zeebeIdentity, zeebeIdentityConfiguration);
283+
}
230284
}

0 commit comments

Comments
 (0)