Verified Commit 0ef5210d authored by João Capucho's avatar João Capucho
Browse files

Seal service order order items secrets

parent 2d4da1cc
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
package org.etsi.osl.secretcontroller;

import org.etsi.osl.tmf.so641.model.ServiceOrderUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsClient;
@@ -19,6 +20,9 @@ public class CatalogClient {
    @Value("${topics.CATALOG_UPD_RESOURCE}")
    private String CATALOG_UPD_RESOURCE;

    @Value("${topics.CATALOG_UPD_SERVICE_ORDER}")
    private String CATALOG_UPD_SERVICE_ORDER;

    @Autowired
    public CatalogClient(JmsClient jmsClient, ObjectMapper objectMapper) {
        this.jmsClient = jmsClient;
@@ -46,4 +50,14 @@ public class CatalogClient {
        jmsClient.destination(CATALOG_UPD_RESOURCE)
                .send(payload, map);
    }

    public void updateServiceOrder(String orderId, ServiceOrderUpdate svcOrderUpdate) {
        final var map = new HashMap<String, Object>();
        map.put("orderid", orderId);

        final var payload = this.objectMapper.writeValueAsString(svcOrderUpdate);

        jmsClient.destination(CATALOG_UPD_SERVICE_ORDER)
                .send(payload, map);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@ public class ServiceRulesService {
        return new ServiceRulesApplier(this.ruleEvaluatorService, Optional.ofNullable(rule));
    }

    public ServiceRulesApplier getServiceRules(org.etsi.osl.tmf.so641.model.ServiceRestriction svc) {
        final var name = svc.getName();
        final var rule = this.rulesConfig.getServiceRules().get(name);
        return new ServiceRulesApplier(this.ruleEvaluatorService, Optional.ofNullable(rule));
    }

    public static class ServiceRulesApplier {
        private final Optional<ServiceRule> rule;
        private final RuleEvaluatorService ruleEvaluatorService;
+2 −2
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@ public class VaultService {
        this.vaultBaseSecretUri = String.format("%s/v1/%s/data/", vaultUri, kvPath);
    }

    public String getVaultKey(String namespace, String key) {
        return String.format("%s/%s", namespace, key);
    public String getVaultKey(String namespace, String... keys) {
        return String.format("%s/%s", namespace, String.join("/", keys));
    }

    public String getVaultUri(String secretKey) {
+122 −0
Original line number Diff line number Diff line
package org.etsi.osl.secretcontroller.listeners;

import org.etsi.osl.secretcontroller.CatalogClient;
import org.etsi.osl.secretcontroller.SecretApplyResult;
import org.etsi.osl.secretcontroller.ServiceRulesService;
import org.etsi.osl.secretcontroller.VaultService;
import org.etsi.osl.tmf.so641.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import tools.jackson.databind.ObjectMapper;

import java.util.HashMap;

@Component
public class ServiceOrderEventsListener {
    private static final String SECRET_NAMESPACE = "service-order";

    private final VaultService vaultService;

    private final CatalogClient catalogClient;
    private final ServiceRulesService serviceRulesService;

    private final ObjectMapper objectMapper;

    @Autowired
    public ServiceOrderEventsListener(
            VaultService vaultService,
            CatalogClient catalogClient,
            ServiceRulesService serviceRulesService,
            ObjectMapper objectMapper
    ) {
        this.vaultService = vaultService;
        this.catalogClient = catalogClient;
        this.serviceRulesService = serviceRulesService;
        this.objectMapper = objectMapper;
    }

    @JmsListener(destination = "${topics.EVENT_SERVICE_ORDER_CREATE}", containerFactory =
            "topicJmsListenerContainerFactory")
    public void processServiceCreate(String content) {
        final var res = this.objectMapper.readValue(content, ServiceOrderCreateNotification.class);
        this.processServiceOrder(res.getEvent().getServiceOrder());
    }

    @JmsListener(destination = "${topics.EVENT_SERVICE_ORDER_ATTRIBUTE_VALUE_CHANGED}", containerFactory =
            "topicJmsListenerContainerFactory")
    public void processServiceAttributeChange(String content) {
        final var res = this.objectMapper.readValue(content, ServiceOrderAttributeValueChangeNotification.class);
        this.processServiceOrder(res.getEvent().getServiceOrder());
    }

    private void processServiceOrder(ServiceOrder serviceOrder) {
        final var svcOrderUpdate = new ServiceOrderUpdate();

        var isDirty = false;
        for (final var orderItem : serviceOrder.getOrderItem()) {
            if (orderItem.getService() == null)
                continue;

            final var ruleApplier = this.serviceRulesService.getServiceRules(orderItem.getService());
            final var svc = new ServiceRestriction();
            final var secretData = new HashMap<String, String>();

            final var vaultKey = this.vaultService.getVaultKey(SECRET_NAMESPACE, "services", orderItem.getId());
            final var secretURI = this.vaultService.getVaultUri(vaultKey);

            var svcIsDirty = false;
            for (final var characteristic : orderItem.getService().getServiceCharacteristic()) {
                // Characteristic was already stored, ignore it
                if (this.vaultService.isAlreadySecret(characteristic.getValue().getValue()))
                    continue;

                final var storeSecret = ruleApplier.saveCharacteristic(characteristic);
                if (storeSecret.action != SecretApplyResult.Action.Ignore)
                    svcIsDirty = true;

                switch (storeSecret.action) {
                    case Replace -> {
                        secretData.put(characteristic.getName(), storeSecret.getValue());
                        characteristic.getValue().setValue(secretURI);
                        svc.addServiceCharacteristicItem(characteristic);
                    }
                    case Erase -> {
                        characteristic.getValue().setValue("Erased by secret controller");
                        svc.addServiceCharacteristicItem(characteristic);
                    }
                }
            }

            if (!svcIsDirty)
                continue;

            if (!secretData.isEmpty())
                this.vaultService.upsertSecret(vaultKey, secretData);

            final var updOrderItem = new ServiceOrderItem();
            updOrderItem.setUuid(updOrderItem.getUuid());
            updOrderItem.setService(svc);

            svcOrderUpdate.addOrderItemItem(orderItem);
            isDirty = true;
        }

        if (!isDirty)
            return;

        this.catalogClient.updateServiceOrder(serviceOrder.getId(), svcOrderUpdate);
    }

    @JmsListener(destination = "${topics.EVENT_SERVICE_ORDER_DELETE}", containerFactory =
            "topicJmsListenerContainerFactory")
    public void processServiceDelete(String content) {
        final var res = this.objectMapper.readValue(content, ServiceOrderDeleteNotification.class);
        final var svcOrder = res.getEvent().getServiceOrder();

        for (final var orderItem : svcOrder.getOrderItem()) {
            final var vaultKey = this.vaultService.getVaultKey(SECRET_NAMESPACE, "services", orderItem.getId());
            this.vaultService.deleteSecret(vaultKey);
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@ topics:
  EVENT_RESOURCE_ATTRIBUTE_VALUE_CHANGED: "EVENT.RESOURCE.ATTRCHANGED"
  EVENT_RESOURCE_DELETE: "EVENT.RESOURCE.DELETE"

  CATALOG_UPD_SERVICE_ORDER: "CATALOG.UPD.SERVICEORDER_BY_ID"
  EVENT_SERVICE_ORDER_CREATE: "EVENT.SERVICEORDER.CREATE"
  EVENT_SERVICE_ORDER_ATTRIBUTE_VALUE_CHANGED: "EVENT.SERVICEORDER.ATTRCHANGED"
  EVENT_SERVICE_ORDER_DELETE: "EVENT.SERVICEORDER.DELETE"

app:
  service-rules: { }
  resource-rules: { }