Skip to content

Commit a06f76c

Browse files
committed
refactored authentication and builders
1 parent 774f3ed commit a06f76c

File tree

9 files changed

+173
-162
lines changed

9 files changed

+173
-162
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,66 @@
11
package io.camunda.common.auth;
22

3-
/**
4-
* TODO: Figure out common functionality between SaaS and Self Managed that can be inserted here
5-
* to reduce code duplication. If not, remove this class
6-
*/
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.lang.invoke.MethodHandles;
7+
import java.time.LocalDateTime;
8+
import java.util.AbstractMap;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
import java.util.Map.Entry;
12+
13+
714
public abstract class JwtAuthentication implements Authentication {
15+
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles
16+
.lookup().lookupClass());
17+
18+
private final JwtConfig jwtConfig;
19+
private final Map<Product, JwtToken> tokens = new HashMap<>();
20+
21+
protected JwtAuthentication(JwtConfig jwtConfig) {this.jwtConfig = jwtConfig;}
22+
23+
@Override
24+
public final void resetToken(Product product) {
25+
tokens.remove(product);
26+
}
27+
@Override
28+
public final Entry<String, String> getTokenHeader(Product product) {
29+
if (!tokens.containsKey(product) || !isValid(tokens.get(product))) {
30+
JwtToken newToken = generateToken(product,jwtConfig.getProduct(product));
31+
tokens.put(product, newToken);
32+
}
33+
return authHeader(tokens.get(product).getToken());
34+
}
35+
36+
protected abstract JwtToken generateToken(Product product, JwtCredential credential);
37+
38+
private Entry<String,String> authHeader(String token){
39+
return new AbstractMap.SimpleEntry<>("Authorization", "Bearer " + token);
40+
}
41+
42+
private boolean isValid(JwtToken jwtToken) {
43+
// a token is only counted valid if it is only valid for at least 30 seconds
44+
return jwtToken.getExpiry().isAfter(LocalDateTime.now().minusSeconds(30));
45+
}
46+
47+
48+
49+
protected static class JwtToken {
50+
private final String token;
51+
private final LocalDateTime expiry;
52+
53+
public JwtToken(String token, LocalDateTime expiry) {
54+
this.token = token;
55+
this.expiry = expiry;
56+
}
57+
58+
public String getToken() {
59+
return token;
60+
}
861

62+
public LocalDateTime getExpiry() {
63+
return expiry;
64+
}
65+
}
966
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.camunda.common.auth;
2+
3+
import io.camunda.common.auth.Authentication.AuthenticationBuilder;
4+
5+
public abstract class JwtAuthenticationBuilder<
6+
T extends JwtAuthenticationBuilder<?>> implements AuthenticationBuilder {
7+
private JwtConfig jwtConfig;
8+
9+
public final T withJwtConfig(JwtConfig jwtConfig) {
10+
this.jwtConfig = jwtConfig;
11+
return self();
12+
}
13+
14+
@Override
15+
public final Authentication build() {
16+
return build(jwtConfig);
17+
}
18+
19+
protected abstract T self();
20+
21+
protected abstract Authentication build(JwtConfig jwtConfig);
22+
}

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

+24-42
Original file line numberDiff line numberDiff line change
@@ -19,69 +19,51 @@
1919
public class SaaSAuthentication extends JwtAuthentication {
2020

2121
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
22-
private JwtConfig jwtConfig;
23-
private Map<Product, String> tokens;
2422

25-
// TODO: have a single object mapper to be used all throughout the SDK, i.e.bean injection
26-
private JsonMapper jsonMapper = new SdkObjectMapper();
23+
private final JsonMapper jsonMapper;
2724

28-
public SaaSAuthentication() {
29-
tokens = new HashMap<>();
25+
public SaaSAuthentication(JwtConfig jwtConfig, JsonMapper jsonMapper) {
26+
super(jwtConfig);
27+
this.jsonMapper = jsonMapper;
3028
}
3129

3230
public static SaaSAuthenticationBuilder builder() {
3331
return new SaaSAuthenticationBuilder();
3432
}
3533

36-
public JwtConfig getJwtConfig() {
37-
return jwtConfig;
38-
}
39-
40-
public void setJwtConfig(JwtConfig jwtConfig) {
41-
this.jwtConfig = jwtConfig;
42-
}
43-
44-
@Override
45-
public Authentication build() {
46-
return this;
47-
}
4834

49-
@Override
50-
public void resetToken(Product product) {
51-
tokens.remove(product);
52-
}
53-
54-
private String retrieveToken(Product product, JwtCredential jwtCredential) {
55-
try(CloseableHttpClient client = HttpClients.createDefault()){
56-
HttpPost request = buildRequest(jwtCredential);
57-
TokenResponse tokenResponse = client.execute(request, response ->
58-
jsonMapper.fromJson(EntityUtils.toString(response.getEntity()), TokenResponse.class)
59-
);
60-
tokens.put(product, tokenResponse.getAccessToken());
61-
} catch (Exception e) {
35+
private TokenResponse retrieveToken(Product product, JwtCredential jwtCredential) {
36+
try (CloseableHttpClient client = HttpClients.createDefault()) {
37+
HttpPost request = buildRequest(jwtCredential);
38+
return client.execute(
39+
request,
40+
response ->
41+
jsonMapper.fromJson(EntityUtils.toString(response.getEntity()), TokenResponse.class));
42+
} catch (Exception e) {
6243
LOG.error("Authenticating for " + product + " failed due to " + e);
6344
throw new RuntimeException("Unable to authenticate", e);
6445
}
65-
return tokens.get(product);
6646
}
6747

6848
private HttpPost buildRequest(JwtCredential jwtCredential) {
6949
HttpPost httpPost = new HttpPost(jwtCredential.getAuthUrl());
7050
httpPost.addHeader("Content-Type", "application/json");
71-
TokenRequest tokenRequest = new TokenRequest(jwtCredential.getAudience(), jwtCredential.getClientId(), jwtCredential.getClientSecret());
51+
TokenRequest tokenRequest =
52+
new TokenRequest(
53+
jwtCredential.getAudience(),
54+
jwtCredential.getClientId(),
55+
jwtCredential.getClientSecret());
7256
httpPost.setEntity(new StringEntity(jsonMapper.toJson(tokenRequest)));
7357
return httpPost;
7458
}
7559

60+
61+
7662
@Override
77-
public Map.Entry<String, String> getTokenHeader(Product product) {
78-
String token;
79-
if (tokens.containsKey(product)) {
80-
token = tokens.get(product);
81-
} else {
82-
JwtCredential jwtCredential = jwtConfig.getProduct(product);
83-
token = retrieveToken(product, jwtCredential);
84-
}
85-
return new AbstractMap.SimpleEntry<>("Authorization", "Bearer " + token);
63+
protected JwtToken generateToken(Product product, JwtCredential credential) {
64+
TokenResponse tokenResponse = retrieveToken(product, credential);
65+
return new JwtToken(
66+
tokenResponse.getAccessToken(),
67+
LocalDateTime.now().plusSeconds(tokenResponse.getExpiresIn()));
8668
}
8769
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
package io.camunda.common.auth;
22

3-
public class SaaSAuthenticationBuilder {
3+
import io.camunda.common.json.JsonMapper;
44

5-
SaaSAuthentication saaSAuthentication;
5+
public class SaaSAuthenticationBuilder extends JwtAuthenticationBuilder<SaaSAuthenticationBuilder> {
6+
private JsonMapper jsonMapper;
67

7-
SaaSAuthenticationBuilder() {
8-
saaSAuthentication = new SaaSAuthentication();
8+
public SaaSAuthenticationBuilder withJsonMapper(JsonMapper jsonMapper) {
9+
this.jsonMapper = jsonMapper;
10+
return this;
911
}
1012

11-
public SaaSAuthenticationBuilder jwtConfig(JwtConfig jwtConfig) {
12-
saaSAuthentication.setJwtConfig(jwtConfig);
13+
@Override
14+
protected SaaSAuthenticationBuilder self() {
1315
return this;
1416
}
1517

16-
public Authentication build() {
17-
return saaSAuthentication.build();
18+
@Override
19+
protected SaaSAuthentication build(JwtConfig jwtConfig) {
20+
return new SaaSAuthentication(jwtConfig, jsonMapper);
1821
}
19-
2022
}

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

+14-47
Original file line numberDiff line numberDiff line change
@@ -3,72 +3,39 @@
33
import io.camunda.common.auth.identity.IdentityConfig;
44
import io.camunda.identity.sdk.Identity;
55
import io.camunda.identity.sdk.authentication.Tokens;
6-
import io.camunda.identity.sdk.authentication.exception.TokenExpiredException;
7-
import org.slf4j.Logger;
8-
import org.slf4j.LoggerFactory;
9-
106
import java.lang.invoke.MethodHandles;
7+
import java.time.LocalDateTime;
118
import java.util.AbstractMap;
129
import java.util.HashMap;
1310
import java.util.Map;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
1413

1514
public class SelfManagedAuthentication extends JwtAuthentication {
1615

1716
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
18-
private JwtConfig jwtConfig;
19-
private IdentityConfig identityConfig;
20-
private Map<Product, String> tokens;
17+
private final IdentityConfig identityConfig;
2118

22-
public SelfManagedAuthentication() {
23-
tokens = new HashMap<>();
19+
public SelfManagedAuthentication(JwtConfig jwtConfig, IdentityConfig identityConfig) {
20+
super(jwtConfig);
21+
this.identityConfig = identityConfig;
2422
}
2523

2624
public static SelfManagedAuthenticationBuilder builder() {
2725
return new SelfManagedAuthenticationBuilder();
2826
}
2927

30-
public JwtConfig getJwtConfig() {
31-
return jwtConfig;
32-
}
33-
34-
public void setJwtConfig(JwtConfig jwtConfig) {
35-
this.jwtConfig = jwtConfig;
36-
}
37-
38-
public void setIdentityConfig(IdentityConfig identityConfig) {
39-
this.identityConfig = identityConfig;
40-
}
41-
42-
@Override
43-
public Authentication build() {
44-
return this;
45-
}
46-
4728
@Override
48-
public void resetToken(Product product) {
49-
tokens.remove(product);
29+
protected JwtToken generateToken(Product product, JwtCredential credential) {
30+
Tokens token = getIdentityToken(product, credential);
31+
return new JwtToken(
32+
token.getAccessToken(), LocalDateTime.now().plusSeconds(token.getExpiresIn()));
5033
}
5134

52-
@Override
53-
public Map.Entry<String, String> getTokenHeader(Product product) {
54-
String token;
55-
if (tokens.containsKey(product)) {
56-
token = tokens.get(product);
57-
} else {
58-
token = getIdentityToken(product);
59-
saveToken(product, token);
60-
}
61-
return new AbstractMap.SimpleEntry<>("Authorization", "Bearer " + token);
62-
}
63-
64-
private String getIdentityToken(Product product) {
35+
private Tokens getIdentityToken(Product product, JwtCredential credential) {
6536
Identity identity = identityConfig.get(product).getIdentity();
66-
String audience = jwtConfig.getProduct(product).getAudience();
67-
Tokens identityTokens = identity.authentication().requestToken(audience);
68-
return identityTokens.getAccessToken();
37+
String audience = credential.getAudience();
38+
return identity.authentication().requestToken(audience);
6939
}
7040

71-
private void saveToken(Product product, String token) {
72-
tokens.put(product, token);
73-
}
7441
}

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

+10-13
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@
22

33
import io.camunda.common.auth.identity.IdentityConfig;
44

5-
public class SelfManagedAuthenticationBuilder {
5+
public class SelfManagedAuthenticationBuilder
6+
extends JwtAuthenticationBuilder<SelfManagedAuthenticationBuilder> {
7+
private IdentityConfig identityConfig;
68

7-
SelfManagedAuthentication selfManagedAuthentication;
8-
9-
SelfManagedAuthenticationBuilder() {
10-
selfManagedAuthentication = new SelfManagedAuthentication();
11-
}
12-
13-
public SelfManagedAuthenticationBuilder jwtConfig(JwtConfig jwtConfig) {
14-
selfManagedAuthentication.setJwtConfig(jwtConfig);
9+
public SelfManagedAuthenticationBuilder withIdentityConfig(IdentityConfig identityConfig) {
10+
this.identityConfig = identityConfig;
1511
return this;
1612
}
1713

18-
public SelfManagedAuthenticationBuilder identityConfig(IdentityConfig identityConfig) {
19-
selfManagedAuthentication.setIdentityConfig(identityConfig);
14+
@Override
15+
protected SelfManagedAuthenticationBuilder self() {
2016
return this;
2117
}
2218

23-
public Authentication build() {
24-
return selfManagedAuthentication.build();
19+
@Override
20+
protected Authentication build(JwtConfig jwtConfig) {
21+
return new SelfManagedAuthentication(jwtConfig, identityConfig);
2522
}
2623
}

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

+6-22
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,19 @@ public class SimpleAuthentication implements Authentication {
1717

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

20-
private String simpleUrl;
21-
private SimpleConfig simpleConfig;
22-
private Map<Product, String> tokens;
20+
private final SimpleConfig simpleConfig;
21+
private final Map<Product, String> tokens = new HashMap<>();
2322

24-
private String authUrl;
23+
private final String authUrl;
2524

26-
public void setSimpleUrl(String simpleUrl) {
27-
this.simpleUrl = simpleUrl;
28-
}
29-
30-
public SimpleConfig getSimpleConfig() {
31-
return simpleConfig;
32-
}
33-
34-
public void setSimpleConfig(SimpleConfig simpleConfig) {
25+
public SimpleAuthentication(String simpleUrl, SimpleConfig simpleConfig) {
3526
this.simpleConfig = simpleConfig;
36-
}
37-
38-
public SimpleAuthentication() {
39-
tokens = new HashMap<>();
27+
this.authUrl = simpleUrl+"/api/login";
4028
}
4129

4230
public static SimpleAuthenticationBuilder builder() { return new SimpleAuthenticationBuilder(); }
4331

44-
@Override
45-
public Authentication build() {
46-
authUrl = simpleUrl+"/api/login";
47-
return this;
48-
}
32+
4933

5034
private String retrieveToken(Product product, SimpleCredential simpleCredential) {
5135
try(CloseableHttpClient client = HttpClients.createDefault()) {

0 commit comments

Comments
 (0)