Skip to content

Commit b14141c

Browse files
committed
feat: add license validation
1 parent 61e0a33 commit b14141c

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ai.timefold.solver.core.enterprise;
2+
3+
public final class License {
4+
5+
// TODO - Replace with the correct signed CA
6+
public static final String CA = """
7+
-----BEGIN CERTIFICATE-----
8+
MIIFYTCCA0mgAwIBAgIUb39y+k9L8Nn+/5gLsOFkhBlpJ5MwDQYJKoZIhvcNAQEL
9+
BQAwQDELMAkGA1UEBhMCQkUxETAPBgNVBAoMCFRpbWVmb2xkMR4wHAYDVQQDDBVU
10+
aW1lZm9sZCBMaWNlbnNpbmcgQ0EwHhcNMjUxMjA5MTEwOTE3WhcNMzUxMjA3MTEw
11+
OTE3WjBAMQswCQYDVQQGEwJCRTERMA8GA1UECgwIVGltZWZvbGQxHjAcBgNVBAMM
12+
FVRpbWVmb2xkIExpY2Vuc2luZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
13+
AgoCggIBAMMzRBxF5B0KT/DlZ894bkoYD/nqK+qUoSC9P/E87yeX7oZiVfITGXjy
14+
ZpJuG48zRH+7BLYG4ELHBixGI8OsLlGbAihPm70pn8QU/0aHJ9lSUDa5dsyuYmr7
15+
gEhb45tHKgGscinCikjC8po3SGKIbgzqm5B/UmSWPoGeNHU0suYg37zlkwvyV1uj
16+
rG1Pm2RJS35/U79bunyOpNjKmP6c75ccYMCG4VSdueF3et6bPiiYMY3I6mAS9anz
17+
X9jKXgSJQR0uJPPUo9FfI91K8zLjhuze4BP4GAyHrIIdQgjRx1++90Vtgdfj9Odo
18+
oQY64QDouO/nLNIGPV3K2cb5nQgtL41BpGfgFkkkDZZRua4GREDyW1LoPRD6wlGr
19+
Ud0pnntL+KA7Ul75D5w4pqP5ZezuFVaHW/mT/gyDclei5QlebHJk/2Ibx1lrdwA7
20+
MhD87aW1gfmiHUPbg6et+Oo/Dir8xja5SnZ0j008zUCXPVUk/BnCOPtEpCZ3aNIp
21+
y3b8CQ7EIBU4VLE07B2tI6ZoArEXp+yRBCplxAUpmx88e9WaO9eLOFoDJnpHZcOz
22+
QOer2uLmw7cesV8piuSGRB0aRWcW626Th6OgwGhYGHH2EXk1JZAO89nnEatpRDTW
23+
0W1WTzH7q3yZ1eUwyy6WwZByTNYl9kyiXQaQ64v2Rh3hlobY3Dk7AgMBAAGjUzBR
24+
MB0GA1UdDgQWBBQnum2seFZuX6i1e2nnqMY3IhxmBTAfBgNVHSMEGDAWgBQnum2s
25+
eFZuX6i1e2nnqMY3IhxmBTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
26+
A4ICAQCBCRZEfv2Iog2r28dFd7FrhwnFt3s2jh2BSYDTJMbVUPl52Mvwandjnem9
27+
Rd+bIpWIP9wQrbGHuBpK5fBLq/HI6MrWGEI9a2ZI3hOVD8igAfU1nJedu3FKtTkk
28+
xhfXc+VG6Djr3Uv5w4euYhdxV86jIUwQnuiJB3vZCVdZlNpyhm7D7f8eappOP0qf
29+
syhGFhfJ0jm7FGVjwX8B8UMwsG1hvvrAiupubbTzRdRxqNc9zmjKGL6o+DDwVWSA
30+
FPz3dOCTcV+w6R9IjH6KyYT7Xj6/lOOwMpzzhraB5KTxLOZf4N0s4PVF7C6PT1Z/
31+
0hMYVCS28Gw56XjhPbMGtTHCgAx76w4uIuUNHJNa2DC/1nudxl1bQwxwkrCUC3Hh
32+
iuGWUWAeoIbJrJQdPGDru+JKchkBafRdUpVvvRwcnjSw2cuKgP93elX+dHYrGfXm
33+
mXbhHHQNixRAQj7i78vzoXQcEsJRvdWGFXkjt8yIVObRNtuMlZPmce+btFWq8cTl
34+
ncuhpe+jwz9C0BjqVtAc8nH+eYPKFyGTDlsz7hzQb7gNrYTrNdhFCkpuhb+axfGp
35+
ZPj0mbAaNlpYm/mlYt+jY5YmYJNomZKhxM8O09pOwLNrLbWUhrLczbeph1Iu33LE
36+
KYb0W/hmsuvLXt6O5/fudgMzZ2oaVGKX4B89B2U8aYY28xyu/w==
37+
-----END CERTIFICATE-----""";
38+
39+
private License() {
40+
// Empty constructor
41+
}
42+
}

core/src/main/java/ai/timefold/solver/core/enterprise/TimefoldSolverEnterpriseService.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ai.timefold.solver.core.enterprise;
22

33
import java.lang.reflect.InvocationTargetException;
4+
import java.security.cert.CertificateException;
45
import java.util.Objects;
56
import java.util.function.BiFunction;
67
import java.util.function.Function;
@@ -57,7 +58,7 @@ static String identifySolverVersion() {
5758
return packaging + " " + version;
5859
}
5960

60-
private static String getVersionString(Class<?> clz) {
61+
static String getVersionString(Class<?> clz) {
6162
var version = clz.getPackage().getImplementationVersion();
6263
return (version == null ? DEVELOPMENT_SNAPSHOT : "v" + version);
6364
}
@@ -86,8 +87,15 @@ static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
8687
var communityVersion = getVersionString(TimefoldSolverEnterpriseService.class);
8788
var enterpriseVersion = getVersionString(service.getClass());
8889
if (Objects.equals(communityVersion, enterpriseVersion)) { // Identical versions.
90+
// We validate the user license at this point
91+
try {
92+
service.validateUserLicense();
93+
} catch (CertificateException e) {
94+
throw new IllegalStateException(e);
95+
}
8996
return service;
9097
} else if (enterpriseVersion.equals(DEVELOPMENT_SNAPSHOT)) { // Don't enforce when running Enterprise tests.
98+
// We do not validate the user license for development snapshots.
9199
return service;
92100
}
93101
throw new IllegalStateException("""
@@ -100,13 +108,25 @@ static TimefoldSolverEnterpriseService loadOrFail(Feature feature) {
100108
static <T> T buildOrDefault(Function<TimefoldSolverEnterpriseService, T> builder, Supplier<T> defaultValue) {
101109
try {
102110
var service = load();
111+
var enterpriseVersion = getVersionString(service.getClass());
112+
if (!enterpriseVersion.equals(DEVELOPMENT_SNAPSHOT)) {
113+
// We validate the user license at this point
114+
service.validateUserLicense();
115+
}
103116
return builder.apply(service);
104117
} catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException
105118
| IllegalAccessException e) {
106119
return defaultValue.get();
120+
} catch (CertificateException e) {
121+
throw new IllegalStateException(e);
107122
}
108123
}
109124

125+
/**
126+
* It performs a security validation to ensure that the user licenseo is valid.
127+
*/
128+
void validateUserLicense() throws CertificateException;
129+
110130
TopologicalOrderGraph buildTopologyGraph(int size);
111131

112132
Class<? extends ConstraintProvider>

0 commit comments

Comments
 (0)