-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLeaseGuard.java
More file actions
90 lines (79 loc) · 2.69 KB
/
LeaseGuard.java
File metadata and controls
90 lines (79 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package dev.arcp.runtime.lease;
import dev.arcp.core.error.LeaseExpiredException;
import dev.arcp.core.error.PermissionDeniedException;
import dev.arcp.core.lease.Lease;
import dev.arcp.core.lease.LeaseConstraints;
import java.time.Clock;
import java.util.List;
import org.jspecify.annotations.Nullable;
/**
* §9.3 / §9.5 enforcement against a static lease + constraints. Glob matching uses a minimal {@code
* *}/{@code **} subset that satisfies the spec examples.
*/
public final class LeaseGuard {
private final Lease lease;
private final LeaseConstraints constraints;
private final Clock clock;
public LeaseGuard(Lease lease, LeaseConstraints constraints, Clock clock) {
this.lease = lease;
this.constraints = constraints;
this.clock = clock;
}
public Lease lease() {
return lease;
}
public LeaseConstraints constraints() {
return constraints;
}
public void authorize(String namespace, String pattern)
throws PermissionDeniedException, LeaseExpiredException {
if (constraints.expiresAt() != null && !clock.instant().isBefore(constraints.expiresAt())) {
throw new LeaseExpiredException(
"lease expired at " + constraints.expiresAt() + " for " + namespace);
}
List<String> patterns = lease.patterns(namespace);
if (patterns.stream().noneMatch(allowed -> matches(allowed, pattern))) {
throw new PermissionDeniedException(
namespace + " does not permit " + pattern + "; allowed=" + patterns);
}
}
public void authorizeModel(String modelId)
throws PermissionDeniedException, LeaseExpiredException {
authorize("model.use", modelId);
}
static boolean matches(String pattern, String value) {
return globToRegex(pattern).matcher(value).matches();
}
private static java.util.regex.Pattern globToRegex(String glob) {
StringBuilder sb = new StringBuilder("^");
int i = 0;
while (i < glob.length()) {
char c = glob.charAt(i);
if (c == '*') {
if (i + 1 < glob.length() && glob.charAt(i + 1) == '*') {
sb.append(".*");
i += 2;
continue;
}
sb.append("[^/]*");
} else if ("\\.+()[]{}^$|?".indexOf(c) >= 0) {
sb.append('\\').append(c);
} else {
sb.append(c);
}
i++;
}
sb.append('$');
return java.util.regex.Pattern.compile(sb.toString());
}
public static @Nullable LeaseExpiredException expiredOrNull(
LeaseConstraints constraints, Clock clock) {
if (constraints.expiresAt() == null) {
return null;
}
if (!clock.instant().isBefore(constraints.expiresAt())) {
return new LeaseExpiredException("lease expired at " + constraints.expiresAt());
}
return null;
}
}