Skip to content

Commit a84d764

Browse files
authored
Merge pull request #757 from swisspost/allow-startup-halt-on-broken-ACL
add flag allow halt app when Acl failed to parsing
2 parents e75d4e5 + 23051b2 commit a84d764

2 files changed

Lines changed: 50 additions & 7 deletions

File tree

gateleen-security/src/main/java/org/swisspush/gateleen/security/authorization/Authorizer.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,17 @@ public Authorizer(Vertx vertx, final ResourceStorage storage, String securityRoo
7070
this(vertx, storage, securityRoot, rolePattern, rolePrefix, properties, true);
7171
}
7272

73+
public Authorizer(Vertx vertx, final ResourceStorage storage, String securityRoot, String rolePattern,
74+
String rolePrefix, Map<String, Object> properties, boolean grantAccessWithoutRoles) {
75+
this(vertx, storage, securityRoot, rolePattern, rolePrefix, properties, grantAccessWithoutRoles, false);
76+
}
77+
7378
/*
7479
* Initializes the ACL security system with the RoleMapper from the corresponding storage resources containing the
7580
* ACL groups (without the role prefix) and the RoleMapper resource. Requests without roles can be granted or rejected
7681
*/
7782
public Authorizer(Vertx vertx, final ResourceStorage storage, String securityRoot, String rolePattern,
78-
String rolePrefix, Map<String, Object> properties, boolean grantAccessWithoutRoles) {
83+
String rolePrefix, Map<String, Object> properties, boolean grantAccessWithoutRoles, boolean haltIfAclInitFailed) {
7984
this.vertx = vertx;
8085
this.storage = storage;
8186
String aclRoot = UriBuilder.concatUriSegments(securityRoot, aclKey, "/");
@@ -89,6 +94,18 @@ public Authorizer(Vertx vertx, final ResourceStorage storage, String securityRoo
8994

9095
// Receive update notifications
9196
eb.consumer(UPDATE_ADDRESS, (Handler<Message<String>>) role -> updateAllConfigs());
97+
roleAuthorizer.init().onComplete(event -> {
98+
if (event.succeeded()) {
99+
log.debug("role authorizer initialized");
100+
} else {
101+
if (haltIfAclInitFailed) {
102+
log.error("role authorizer initialization failed, application will shutdown", event.cause());
103+
vertx.close().onComplete(ar -> System.exit(1));
104+
} else {
105+
log.error("role authorizer initialization failed", event.cause());
106+
}
107+
}
108+
});
92109
}
93110

94111
@Override

gateleen-security/src/main/java/org/swisspush/gateleen/security/authorization/RoleAuthorizer.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.swisspush.gateleen.security.authorization;
22

3+
import io.vertx.core.Future;
34
import io.vertx.core.Promise;
45
import io.vertx.core.buffer.Buffer;
56
import io.vertx.core.http.HttpServerRequest;
@@ -16,6 +17,7 @@
1617

1718
import java.util.*;
1819
import java.util.Map.Entry;
20+
import java.util.concurrent.atomic.AtomicBoolean;
1921
import java.util.regex.Matcher;
2022

2123

@@ -40,6 +42,7 @@ public class RoleAuthorizer implements ConfigurationResource {
4042
private final RoleExtractor roleExtractor;
4143
private final Map<PatternHolder, Map<String, Set<String>>> initialGrantedRoles;
4244
private final boolean grantAccessWithoutRoles;
45+
private final AtomicBoolean initialized = new AtomicBoolean(false);
4346

4447
// URI -> Method -> Roles
4548
private Map<PatternHolder, Map<String, Set<String>>> grantedRoles = new HashMap<>();
@@ -75,8 +78,13 @@ public class RoleAuthorizer implements ConfigurationResource {
7578
initialGrantedRoles.get(aclUriPattern).get("PUT").add(adminRole);
7679
initialGrantedRoles.get(aclUriPattern).get("GET").add(adminRole);
7780
initialGrantedRoles.get(aclUriPattern).get("DELETE").add(adminRole);
81+
}
7882

79-
configUpdate();
83+
public Future<Void> init() {
84+
if (initialized.compareAndSet(false, true)) {
85+
return configUpdateInternal();
86+
}
87+
return Future.failedFuture("RoleAuthorizer already initialized");
8088
}
8189

8290
public void handleIsAuthorized(final HttpServerRequest request, Promise<Boolean> promise) {
@@ -96,21 +104,35 @@ public void checkConfigResource(Buffer buffer) throws ValidationException {
96104

97105
@Override
98106
public void configUpdate() {
107+
configUpdateInternal();
108+
}
109+
110+
private Future<Void> configUpdateInternal() {
111+
final Promise<Void> promise = Promise.promise();
99112
storage.get(aclRoot, buffer -> {
113+
final List<Future<Void>> futures = new ArrayList<>();
100114
if (buffer != null) {
101115
grantedRoles = new HashMap<>();
102116
for (Object roleObject : new JsonObject(buffer).getJsonArray(aclKey)) {
103117
String role = (String) roleObject;
104-
updateAcl(role);
118+
futures.add(updateAcl(role));
105119
}
106120
} else {
107121
log.warn("No ACLs in storage, using initial authorization.");
108122
grantedRoles = initialGrantedRoles;
123+
futures.add(Future.succeededFuture());
109124
}
125+
Future.all(futures).onComplete(event -> {
126+
if (event.failed()) {
127+
promise.fail(event.cause());
128+
} else {
129+
promise.complete();
130+
}
131+
});
110132
});
133+
return promise.future();
111134
}
112135

113-
114136
/**
115137
* Extracts the Users Roles from the Request and further validates if the user is allowed to access
116138
* the URL according to the ACL
@@ -211,19 +233,23 @@ private boolean checkRole(Map<String, RoleMapper.MappedRole> roles, HttpServerRe
211233
return authorized;
212234
}
213235

214-
private void updateAcl(final String role) {
236+
private Future<Void> updateAcl(final String role) {
237+
final Promise<Void> promise = Promise.promise();
215238
storage.get(aclRoot + role, buffer -> {
216239
if (buffer != null) {
217240
try {
218241
log.info("Applying acl for {}", role);
219242
mergeAcl(role, buffer);
243+
promise.complete(null);
220244
} catch (ValidationException validationException) {
221-
log.error("Could not parse acls: {}", validationException.toString());
245+
log.error("Could not parse acls: {}", role, validationException);
246+
promise.fail(validationException);
222247
}
223248
} else {
224-
log.error("No acl for role {} found in storage", role);
249+
promise.fail("No acl for role " + role + " found in storage");
225250
}
226251
});
252+
return promise.future();
227253
}
228254

229255
private void mergeAcl(String role, Buffer buffer) throws ValidationException {

0 commit comments

Comments
 (0)