Skip to content

Commit 2a60eb2

Browse files
committed
Ref #33886: add access-strict-expression
1 parent 54d58bd commit 2a60eb2

3 files changed

Lines changed: 76 additions & 10 deletions

File tree

src/main/java/eu/openanalytics/containerproxy/model/spec/AccessControl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class AccessControl {
2525
private String[] groups;
2626
private String[] users;
2727
private String expression;
28+
private String strictExpression;
2829

2930
public String[] getGroups() {
3031
return groups;
@@ -50,6 +51,14 @@ public void setExpression(String expression) {
5051
this.expression = expression;
5152
}
5253

54+
public String getStrictExpression() {
55+
return strictExpression;
56+
}
57+
58+
public void setStrictExpression(String strictExpression) {
59+
this.strictExpression = strictExpression;
60+
}
61+
5362
public boolean hasGroupAccess() {
5463
return groups != null && groups.length > 0;
5564
}
@@ -62,4 +71,8 @@ public boolean hasExpressionAccess() {
6271
return expression != null && expression.length() > 0;
6372
}
6473

74+
public boolean hasStrictExpressionAccess() {
75+
return strictExpression != null && strictExpression.length() > 0;
76+
}
77+
6578
}

src/main/java/eu/openanalytics/containerproxy/service/AccessControlEvaluationService.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
*/
2121
package eu.openanalytics.containerproxy.service;
2222

23+
import com.google.common.base.Supplier;
24+
import com.google.common.base.Suppliers;
2325
import eu.openanalytics.containerproxy.auth.IAuthenticationBackend;
2426
import eu.openanalytics.containerproxy.model.spec.AccessControl;
2527
import eu.openanalytics.containerproxy.model.spec.ProxySpec;
@@ -57,6 +59,26 @@ public boolean checkAccess(Authentication auth, ProxySpec spec, AccessControl ac
5759
}
5860
}
5961

62+
// create context only when necessary (lazy)
63+
Supplier<SpecExpressionContext> context = Suppliers.memoize(() -> {
64+
SpecExpressionContext.SpecExpressionContextBuilder contextBuilder = SpecExpressionContext
65+
.create(objects)
66+
.addServerName()
67+
.extend(spec);
68+
if (auth != null) {
69+
contextBuilder.extend(auth, auth.getPrincipal(), auth.getCredentials());
70+
}
71+
return contextBuilder.build();
72+
});
73+
74+
if (accessControl.hasStrictExpressionAccess()) {
75+
// strict expression is always checked
76+
if (!specExpressionResolver.evaluateToBoolean(accessControl.getStrictExpression(), context.get())) {
77+
// not allowed by strict expression
78+
return false;
79+
}
80+
}
81+
6082
if (hasNoAccessControl(accessControl)) {
6183
return true;
6284
}
@@ -69,7 +91,7 @@ public boolean checkAccess(Authentication auth, ProxySpec spec, AccessControl ac
6991
return true;
7092
}
7193

72-
return allowedByExpression(auth, spec, accessControl, objects);
94+
return allowedByExpression(context.get(), accessControl);
7395
}
7496

7597
public boolean hasNoAccessControl(AccessControl accessControl) {
@@ -108,20 +130,13 @@ public boolean allowedByUsers(Authentication auth, AccessControl accessControl)
108130
return false;
109131
}
110132

111-
public boolean allowedByExpression(Authentication auth, ProxySpec spec, AccessControl accessControl, Object... objects) {
133+
public boolean allowedByExpression(SpecExpressionContext context, AccessControl accessControl) {
112134
if (!accessControl.hasExpressionAccess()) {
113135
// no expression defined -> this user has no access based on the expression
114136
return false;
115137
}
116-
SpecExpressionContext.SpecExpressionContextBuilder contextBuilder = SpecExpressionContext
117-
.create(objects)
118-
.addServerName()
119-
.extend(spec);
120138

121-
if (auth != null) {
122-
contextBuilder.extend(auth, auth.getPrincipal(), auth.getCredentials());
123-
}
124-
return specExpressionResolver.evaluateToBoolean(accessControl.getExpression(), contextBuilder.build());
139+
return specExpressionResolver.evaluateToBoolean(accessControl.getExpression(), context);
125140
}
126141

127142
public boolean usernameEquals(String authenticatedUser, String other) {

src/test/java/eu/openanalytics/containerproxy/test/auth/AccessControlServiceTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,44 @@ public void expressionTest() {
247247
Assertions.assertTrue(accessControlService.canAccess(auth2, createProxySpec(proxyAccessControl)));
248248
}
249249

250+
@Test
251+
public void accessStrictExpressionTest() {
252+
when(authBackend.hasAuthorization()).thenReturn(true);
253+
AccessControl proxyAccessControl = new AccessControl();
254+
// proxyAccessControl.setGroups(new String[]{"myGroup1", "myGroupAbc", "xxy"});
255+
// proxyAccessControl.setUsers(new String[]{"myUser1", "myUser2"});
256+
proxyAccessControl.setStrictExpression("#{false}");
257+
258+
// no access control + expression is false -> never access to app
259+
Authentication auth1 = mock(Authentication.class);
260+
when(auth1.getName()).thenReturn("myUser1");
261+
Assertions.assertFalse(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
262+
263+
// access-groups + expression is false -> no access to app
264+
proxyAccessControl.setGroups(new String[]{"myGroup1", "myGroupAbc", "xxy"});
265+
when(userService.isMember(auth1, "myGroup1")).thenReturn(true);
266+
Assertions.assertFalse(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
267+
268+
// access-users + expression is false -> no access to app
269+
proxyAccessControl.setUsers(new String[]{"myUser1", "myUser2"});
270+
Assertions.assertFalse(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
271+
272+
// access-expression + expression is false -> no access to app
273+
proxyAccessControl.setExpression("#{true}");
274+
Assertions.assertFalse(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
275+
276+
// change expression to return true
277+
proxyAccessControl.setStrictExpression("#{true}");
278+
279+
// expression is true -> access to app based on group
280+
when(userService.isMember(auth1, "myGroup1")).thenReturn(true);
281+
Assertions.assertTrue(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
282+
283+
// expression is true -> access to app based on user
284+
when(userService.isMember(auth1, "myGroup1")).thenReturn(false);
285+
Assertions.assertTrue(accessControlService.canAccess(auth1, createProxySpec(proxyAccessControl)));
286+
}
287+
250288
private ProxySpec createProxySpec(AccessControl proxyAccessControl) {
251289
return ProxySpec.builder()
252290
.id("myId")

0 commit comments

Comments
 (0)