1
2
3
4
5
6 package org.tailormap.api.security;
7
8 import java.lang.invoke.MethodHandles;
9 import java.util.ArrayList;
10 import java.util.HashSet;
11 import java.util.List;
12 import java.util.Optional;
13 import java.util.Set;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16 import org.springframework.security.authentication.AnonymousAuthenticationToken;
17 import org.springframework.security.core.Authentication;
18 import org.springframework.security.core.GrantedAuthority;
19 import org.springframework.security.core.context.SecurityContextHolder;
20 import org.springframework.stereotype.Service;
21 import org.tailormap.api.persistence.Application;
22 import org.tailormap.api.persistence.GeoService;
23 import org.tailormap.api.persistence.Group;
24 import org.tailormap.api.persistence.Page;
25 import org.tailormap.api.persistence.json.AuthorizationRule;
26 import org.tailormap.api.persistence.json.AuthorizationRuleDecision;
27 import org.tailormap.api.persistence.json.GeoServiceLayer;
28 import org.tailormap.api.persistence.json.GeoServiceLayerSettings;
29 import org.tailormap.api.persistence.json.PageTile;
30
31
32
33
34
35 @Service
36 public class AuthorisationService {
37 private static final Logger logger =
38 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
39
40 public static final String ACCESS_TYPE_VIEW = "read";
41
42 private Optional<AuthorizationRuleDecision> isAuthorizedByRules(List<AuthorizationRule> rules) {
43 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
44 Set<String> groups;
45
46 if (auth == null || auth instanceof AnonymousAuthenticationToken) {
47 groups = Set.of(Group.ANONYMOUS);
48 } else {
49 groups = new HashSet<>();
50 groups.add(Group.ANONYMOUS);
51 groups.add(Group.AUTHENTICATED);
52
53 for (GrantedAuthority authority : auth.getAuthorities()) {
54 groups.add(authority.getAuthority());
55 }
56 }
57 logger.trace("Groups to check rules against: {}", groups);
58
59
60 if (groups.contains(Group.ADMIN)) {
61 logger.trace(
62 "Returning {} because {} is allowed access to anything.",
63 AuthorizationRuleDecision.ALLOW,
64 Group.ADMIN);
65 return Optional.of(AuthorizationRuleDecision.ALLOW);
66 }
67
68 boolean hasValidRule = false;
69
70 for (AuthorizationRule rule : rules) {
71 if (logger.isTraceEnabled()) {
72 logger.trace("Checking rule: \n{} against groups {}.", rule, groups);
73 }
74
75 boolean matchesGroup = groups.contains(rule.getGroupName());
76 if (!matchesGroup) {
77 continue;
78 }
79
80 hasValidRule = true;
81
82 AuthorizationRuleDecision value = rule.getDecisions().get(AuthorisationService.ACCESS_TYPE_VIEW);
83 if (value == null) {
84 logger.trace(
85 "No decision found for rule: \n{} and access: {}, returning <EMPTY>.",
86 rule,
87 AuthorisationService.ACCESS_TYPE_VIEW);
88 return Optional.empty();
89 }
90
91 if (value.equals(AuthorizationRuleDecision.ALLOW)) {
92 logger.trace(
93 "Returning {} because rule: \n{} allows {} access for access: {}.",
94 value,
95 rule,
96 rule.getGroupName(),
97 AuthorisationService.ACCESS_TYPE_VIEW);
98 return Optional.of(value);
99 }
100 }
101
102 if (hasValidRule) {
103 logger.trace(
104 "Returning {} because no valid rule allowed access for access: {}.",
105 AuthorizationRuleDecision.DENY,
106 AuthorisationService.ACCESS_TYPE_VIEW);
107 return Optional.of(AuthorizationRuleDecision.DENY);
108 }
109
110 logger.trace(
111 "Returning <EMPTY> because no rules matched for access: {}.", AuthorisationService.ACCESS_TYPE_VIEW);
112 return Optional.empty();
113 }
114
115
116
117
118
119
120
121 public boolean userAllowedToViewPage(Page page) {
122 logger.trace("Checking if user is allowed to view page {}.", page.getName());
123 final boolean allowed =
124 isAuthorizedByRules(page.getAuthorizationRules()).equals(Optional.of(AuthorizationRuleDecision.ALLOW));
125 logger.trace(
126 "User is{} allowed to view page: {} (isAuthorizedByRules={}).",
127 allowed ? "" : " not",
128 page.getName(),
129 allowed);
130 return allowed;
131 }
132
133
134
135
136
137
138
139 public boolean userAllowedToViewPageTile(PageTile pageTile) {
140 logger.trace("Checking if user is allowed to view page tile {}.", pageTile.getTitle());
141 final boolean allowed = isAuthorizedByRules(pageTile.getAuthorizationRules())
142 .equals(Optional.of(AuthorizationRuleDecision.ALLOW));
143 logger.trace(
144 "User is{} allowed to view page tile: {} (isAuthorizedByRules={}).",
145 allowed ? "" : " not",
146 pageTile.getTitle(),
147 allowed);
148 return allowed;
149 }
150
151
152
153
154
155
156
157 public boolean userAllowedToViewApplication(Application application) {
158 logger.trace(
159 "Checking if user is allowed to view Application {} ({}).",
160 application.getTitle(),
161 application.getTitle());
162 final boolean allowed = isAuthorizedByRules(application.getAuthorizationRules())
163 .equals(Optional.of(AuthorizationRuleDecision.ALLOW));
164 logger.trace(
165 "User is{} allowed to view application: {} (isAuthorizedByRules={}).",
166 allowed ? "" : " not",
167 application.getName(),
168 allowed);
169 return allowed;
170 }
171
172
173
174
175
176
177
178 public boolean userAllowedToViewGeoService(GeoService geoService) {
179 logger.trace(
180 "Checking if user is allowed to view GeoService {} ({}).", geoService.getId(), geoService.getTitle());
181 if (mustDenyAccessForSecuredProxy(geoService)) {
182 return false;
183 }
184 final boolean allowed = isAuthorizedByRules(geoService.getAuthorizationRules())
185 .equals(Optional.of(AuthorizationRuleDecision.ALLOW));
186 logger.trace(
187 "User is{} allowed to view GeoService: {} (isAuthorizedByRules={}).",
188 allowed ? "" : " not",
189 geoService.getTitle(),
190 allowed);
191 return allowed;
192 }
193
194
195
196
197
198
199
200
201 public boolean userAllowedToViewGeoServiceLayer(GeoService geoService, GeoServiceLayer layer) {
202 logger.trace(
203 "Checking if user is allowed to view GeoService '{}' and layer {} ({}).",
204 geoService.getTitle(),
205 layer.getName(),
206 layer.getTitle());
207
208 Optional<AuthorizationRuleDecision> geoserviceDecision =
209 isAuthorizedByRules(geoService.getAuthorizationRules());
210 if (geoserviceDecision.equals(Optional.of(AuthorizationRuleDecision.DENY))) {
211 logger.trace("Viewing GeoService {} is denied for user.", geoService.getTitle());
212 return false;
213 }
214
215 GeoServiceLayerSettings layerSettings =
216 geoService.getSettings().getLayerSettings().get(layer.getName());
217 if (layerSettings != null && layerSettings.getAuthorizationRules() != null) {
218 logger.trace(
219 "Checking layer settings rules for GeoService '{}' and layer '{}'. \nRules: {}",
220 geoService.getTitle(),
221 layer.getName(),
222 layerSettings.getAuthorizationRules());
223 List<AuthorizationRule> combinedRules = new ArrayList<>(geoService.getAuthorizationRules());
224 for (AuthorizationRule rule : layerSettings.getAuthorizationRules()) {
225
226
227 combinedRules.removeIf(r -> r.getGroupName().equals(rule.getGroupName()));
228 combinedRules.add(rule);
229 }
230 logger.trace(
231 "Combined rules for GeoService '{}' and layer '{}': \n{}",
232 geoService.getTitle(),
233 layer.getName(),
234 combinedRules);
235
236 Optional<AuthorizationRuleDecision> decision = isAuthorizedByRules(combinedRules);
237
238 if (decision.isPresent() || !layerSettings.getAuthorizationRules().isEmpty()) {
239 boolean allowed = decision.equals(Optional.of(AuthorizationRuleDecision.ALLOW));
240
241 logger.trace(
242 "Viewing GeoService '{}' and layer '{}' ({}) is {} for user.",
243 geoService.getTitle(),
244 layer.getName(),
245 layer.getTitle(),
246 (allowed ? "allowed" : "denied"));
247 return allowed;
248 }
249 }
250
251 boolean allowed = geoserviceDecision.equals(Optional.of(AuthorizationRuleDecision.ALLOW));
252 logger.trace(
253 "Viewing GeoService '{}' and layer '{}' ({}) is {} for user because service access is {3}.",
254 geoService.getTitle(), layer.getName(), layer.getTitle(), (allowed ? "allowed" : "denied"));
255 return allowed;
256 }
257
258
259
260
261
262
263
264
265 public boolean mustDenyAccessForSecuredProxy(GeoService geoService) {
266 if (!Boolean.TRUE.equals(geoService.getSettings().getUseProxy())) {
267 return false;
268 }
269 if (geoService.getAuthentication() == null) {
270 return false;
271 }
272 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
273 return auth == null || auth instanceof AnonymousAuthenticationToken;
274 }
275 }