Skip to content

Commit ef9ad99

Browse files
committed
Add AccessControlService to centralise Authorization/ACL
1 parent 89e14e8 commit ef9ad99

3 files changed

Lines changed: 166 additions & 18 deletions

File tree

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

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,55 @@
2525
public class ProxyAccessControl {
2626

2727
private String[] groups;
28+
private String[] users;
29+
private String expression;
2830

2931
public String[] getGroups() {
3032
return groups;
3133
}
3234

35+
public String[] getUsers() {
36+
return users;
37+
}
38+
39+
public String getExpression() {
40+
return expression;
41+
}
42+
3343
public void setGroups(String[] groups) {
3444
this.groups = groups;
3545
}
36-
46+
47+
public void setUsers(String[] users) {
48+
this.users = users;
49+
}
50+
51+
public void setExpression(String expression) {
52+
this.expression = expression;
53+
}
54+
3755
public void copy(ProxyAccessControl target) {
3856
if (groups != null) {
3957
target.setGroups(Arrays.copyOf(groups, groups.length));
4058
}
59+
if (users != null) {
60+
target.setUsers(Arrays.copyOf(users, users.length));
61+
}
62+
if (expression != null) {
63+
target.setExpression(expression);
64+
}
4165
}
42-
66+
67+
public boolean hasGroupAccess() {
68+
return groups != null && groups.length > 0;
69+
}
70+
71+
public boolean hasUserAccess() {
72+
return users != null && users.length > 0;
73+
}
74+
75+
public boolean hasExpressionAccess() {
76+
return expression != null && expression.length() > 0;
77+
}
78+
4379
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* ContainerProxy
3+
*
4+
* Copyright (C) 2016-2021 Open Analytics
5+
*
6+
* ===========================================================================
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the Apache License as published by
10+
* The Apache Software Foundation, either version 2 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* Apache License for more details.
17+
*
18+
* You should have received a copy of the Apache License
19+
* along with this program. If not, see <http://www.apache.org/licenses/>
20+
*/
21+
package eu.openanalytics.containerproxy.service;
22+
23+
import eu.openanalytics.containerproxy.auth.IAuthenticationBackend;
24+
import eu.openanalytics.containerproxy.model.spec.ProxyAccessControl;
25+
import eu.openanalytics.containerproxy.model.spec.ProxySpec;
26+
import eu.openanalytics.containerproxy.spec.IProxySpecProvider;
27+
import org.springframework.context.annotation.Lazy;
28+
import org.springframework.security.authentication.AnonymousAuthenticationToken;
29+
import org.springframework.security.core.Authentication;
30+
import org.springframework.stereotype.Service;
31+
32+
import javax.inject.Inject;
33+
34+
@Service
35+
public class AccessControlService {
36+
37+
@Lazy
38+
@Inject
39+
private IAuthenticationBackend authBackend;
40+
41+
@Inject
42+
private UserService userService;
43+
44+
@Inject
45+
private IProxySpecProvider specProvider;
46+
47+
public boolean canAccess(Authentication auth, String specId) {
48+
return canAccess(auth, specProvider.getSpec(specId));
49+
}
50+
51+
public boolean canAccess(Authentication auth, ProxySpec spec) {
52+
if (auth == null || spec == null) {
53+
return false;
54+
}
55+
56+
if (auth instanceof AnonymousAuthenticationToken && !authBackend.hasAuthorization()) {
57+
return true;
58+
}
59+
60+
if (specHasNoAccessControl(spec.getAccessControl())) {
61+
return true;
62+
}
63+
64+
if (allowedByGroups(auth, spec)) {
65+
return true;
66+
}
67+
68+
if (allowedByUsers(auth, spec)) {
69+
return true;
70+
}
71+
72+
if (allowedByExpression(auth, spec)) {
73+
return true;
74+
}
75+
76+
return false;
77+
}
78+
79+
public boolean specHasNoAccessControl(ProxyAccessControl accessControl) {
80+
if (accessControl == null) {
81+
return true;
82+
}
83+
84+
return !accessControl.hasGroupAccess()
85+
&& !accessControl.hasUserAccess()
86+
&& !accessControl.hasExpressionAccess();
87+
}
88+
89+
public boolean allowedByGroups(Authentication auth, ProxySpec spec) {
90+
if (!spec.getAccessControl().hasGroupAccess()) {
91+
// no groups defined -> this user has no access based on the groups
92+
return false;
93+
}
94+
for (String group : spec.getAccessControl().getGroups()) {
95+
if (userService.isMember(auth, group)) {
96+
return true;
97+
}
98+
}
99+
return false;
100+
}
101+
102+
public boolean allowedByUsers(Authentication auth, ProxySpec spec) {
103+
if (!spec.getAccessControl().hasUserAccess()) {
104+
// no users defined -> this user has no access based on the users
105+
return false;
106+
}
107+
for (String user : spec.getAccessControl().getUsers()) {
108+
if (auth.getName().equals(user)) {
109+
return true;
110+
}
111+
}
112+
return false;
113+
}
114+
115+
public boolean allowedByExpression(Authentication auth, ProxySpec spec) {
116+
if (!spec.getAccessControl().hasExpressionAccess()) {
117+
// no expression defined -> this user has no access based on the expression
118+
return false;
119+
}
120+
return false;
121+
}
122+
123+
}

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

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public class UserService {
7575
@Inject
7676
private ApplicationEventPublisher applicationEventPublisher;
7777

78+
@Inject
79+
private AccessControlService accessControlService;
80+
7881
public Authentication getCurrentAuth() {
7982
return SecurityContextHolder.getContext().getAuthentication();
8083
}
@@ -127,23 +130,9 @@ public boolean isAdmin(Authentication auth) {
127130
}
128131

129132
public boolean canAccess(ProxySpec spec) {
130-
return canAccess(getCurrentAuth(), spec);
133+
return accessControlService.canAccess(getCurrentAuth(), spec);
131134
}
132-
133-
public boolean canAccess(Authentication auth, ProxySpec spec) {
134-
if (auth == null || spec == null) return false;
135-
if (auth instanceof AnonymousAuthenticationToken) return !authBackend.hasAuthorization();
136135

137-
if (spec.getAccessControl() == null) return true;
138-
139-
String[] groups = spec.getAccessControl().getGroups();
140-
if (groups == null || groups.length == 0) return true;
141-
for (String group: groups) {
142-
if (isMember(auth, group)) return true;
143-
}
144-
return false;
145-
}
146-
147136
public boolean isOwner(Proxy proxy) {
148137
return isOwner(getCurrentAuth(), proxy);
149138
}
@@ -153,7 +142,7 @@ public boolean isOwner(Authentication auth, Proxy proxy) {
153142
return proxy.getUserId().equals(getUserId(auth));
154143
}
155144

156-
private boolean isMember(Authentication auth, String groupName) {
145+
public boolean isMember(Authentication auth, String groupName) {
157146
if (auth == null || auth instanceof AnonymousAuthenticationToken || groupName == null) return false;
158147
for (String group: getGroups(auth)) {
159148
if (group.equalsIgnoreCase(groupName)) return true;

0 commit comments

Comments
 (0)