Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<!-- check micrometer.version vertx-micrometer-metrics consumes before bumping up -->
<micrometer.version>1.12.2</micrometer.version>
<junit-jupiter.version>5.11.2</junit-jupiter.version>
<uid2-shared.version>10.1.0</uid2-shared.version>
<uid2-shared.version>10.3.0</uid2-shared.version>
<okta-jwt.version>0.5.10</okta-jwt.version>
<image.version>${project.version}</image.version>
</properties>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/uid2/admin/vertx/Endpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public enum Endpoints {
API_SERVICE_ADD("/api/service/add"),
API_SERVICE_UPDATE("/api/service/update"),
API_SERVICE_DELETE("/api/service/delete"),
API_SERVICE_REMOVE_LINK_ID_REGEX("/api/service/remove-link-id-regex"),

API_SHARING_LISTS("/api/sharing/lists"),
API_SHARING_LIST_SITEID("/api/sharing/list/:siteId"),
Expand Down
135 changes: 89 additions & 46 deletions src/main/java/com/uid2/admin/vertx/service/ServiceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

import static com.uid2.admin.vertx.Endpoints.*;
Expand Down Expand Up @@ -67,6 +69,11 @@ public void setupRoutes(Router router) {
this.handleDelete(ctx);
}
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.SUPER_USER));
router.post(API_SERVICE_REMOVE_LINK_ID_REGEX.toString()).blockingHandler(auth.handle((ctx) -> {
synchronized (writeLock) {
this.handleRemoveLinkIdRegex(ctx);
}
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.PRIVILEGED));
}

private void handleServiceListAll(RoutingContext rc) {
Expand Down Expand Up @@ -113,6 +120,7 @@ private void handleServiceAdd(RoutingContext rc) {
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
JsonArray rolesSpec = body.getJsonArray("roles");
String linkIdRegex = body.getString("link_id_regex");
if (siteId == null || name == null || rolesSpec == null || rolesSpec.isEmpty()) {
ResponseUtil.error(rc, 400, "required parameters: site_id, name, roles");
return;
Expand Down Expand Up @@ -147,11 +155,20 @@ private void handleServiceAdd(RoutingContext rc) {
return;
}

if (linkIdRegex != null && !linkIdRegex.isBlank()) {
if (!isValidRegex(linkIdRegex)) {
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
return;
}
} else {
linkIdRegex = null;
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());
final int serviceId = 1 + services.stream().mapToInt(Service::getServiceId).max().orElse(0);
Service service = new Service(serviceId, siteId, name, roles);
Service service = new Service(serviceId, siteId, name, roles, linkIdRegex);

services.add(service);

Expand All @@ -163,17 +180,17 @@ private void handleServiceAdd(RoutingContext rc) {
}
}

// Can update the site_id, name and roles
// Can update the site_id, name, roles, and link_id_regex
private void handleUpdate(RoutingContext rc) {
try {
serviceProvider.loadContent();
Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled

JsonObject body = rc.body().asJsonObject();
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return;
}
Integer serviceId = body.getInteger("service_id");
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
String linkIdRegex = body.getString("link_id_regex");

JsonArray rolesSpec = null;
if (body.getString("roles") != null && !body.getString("roles").isEmpty()) {
Expand All @@ -185,16 +202,7 @@ private void handleUpdate(RoutingContext rc) {
}
}

if (serviceId == null) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return;
}

final Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return;
}
int serviceId = service.getServiceId();

// check that this does not create a duplicate service
if (siteHasService(siteId, name, serviceId)) {
Expand Down Expand Up @@ -226,6 +234,14 @@ private void handleUpdate(RoutingContext rc) {
service.setRoles(roles);
}

if (linkIdRegex != null && !linkIdRegex.isBlank()) {
if (!isValidRegex(linkIdRegex)) {
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
return;
}
service.setLinkIdRegex(linkIdRegex);
}

if (siteId != null && siteId != 0) {
service.setSiteId(siteId);
}
Expand All @@ -234,10 +250,7 @@ private void handleUpdate(RoutingContext rc) {
service.setName(name);
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());

List<Service> services = getSortedServices();

storeWriter.upload(services, null);

Expand All @@ -248,40 +261,31 @@ private void handleUpdate(RoutingContext rc) {
}

private void handleDelete(RoutingContext rc) {
final int serviceId;
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return;
}
serviceId = body.getInteger("service_id", -1);
if (serviceId == -1) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return;
}

try {
serviceProvider.loadContent();

Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return;
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());

Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled
List<Service> services = getSortedServices();
services.remove(service);

storeWriter.upload(services, null);

rc.response().end(toJson(service).encodePrettily());
} catch (Exception e) {
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
}
}

private void handleRemoveLinkIdRegex(RoutingContext rc) {
try {
serviceProvider.loadContent();
Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled
service.setLinkIdRegex(null);
List<Service> services = getSortedServices();
storeWriter.upload(services, null);
rc.response().end(toJson(service).encodePrettily());
} catch (Exception e) {
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
}
}

private JsonObject toJson(Service s) {
Expand All @@ -290,6 +294,7 @@ private JsonObject toJson(Service s) {
jsonObject.put("site_id", s.getSiteId());
jsonObject.put("name", s.getName());
jsonObject.put("roles", s.getRoles());
jsonObject.put("link_id_regex", s.getLinkIdRegex());
return jsonObject;
}

Expand All @@ -302,4 +307,42 @@ private boolean siteHasService(Integer siteId, String name, int serviceId) {
&& serviceProvider.getAllServices().stream().anyMatch(s -> s.getServiceId() != serviceId
&& s.getSiteId() == siteId && s.getName().equals(name));
}


private Service findServiceFromRequest(RoutingContext rc) {
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return null;
}

int serviceId = body.getInteger("service_id", -1);
if (serviceId == -1) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return null;
}

Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return null;
}
return service;
}

private List<Service> getSortedServices() {
return serviceProvider.getAllServices()
.stream()
.sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());
}

private boolean isValidRegex(String regex) {
try {
Pattern.compile(regex);
return true;
} catch (PatternSyntaxException e) {
return false;
}
}
}
Loading