Integrating an Antivirus Scan into enaio® coLab

enaio® coLab 11.10 »

In enaio® coLab, an antivirus scanner that checks documents that users want to upload or replace in coLab project rooms can be integrated via webhook (see enaio® coLabExternal link: icon). This extends these functions with HTTP calls. In this case, the object of the HTTP call consists of the document file uploaded to enaio® coLab and the webhook ID.

Two types of calls are possible, depending on the type of implementation: blocking and non-blocking. Developers can select an implementation type that meets their requirements. For example, a blocking implementation may be more suitable than a non-blocking one for small files and fast services. This may also depend on the type of antivirus software and the speed of the server on which the software is installed.

  • Example of blocking calls – multi-part query – response status 200

    POST http://<antivirus_service_IP:8067upload/{id} HTTP/1.1
    accept: application/json
    accept-encoding: gzip
    connection: Keep-Alive
    content-length: 235
    content-type: multipart/form-data; charset=UTF-8; boundary=1847a97df6a
    host: localhost:8067
    user-agent: okhttp/4.3.1

    --1847a97df6a
    Content-Disposition: form-data; name="file"; filename="9067d1f2-8b46-40fe-886a-a06740dcfd6d"
    Content-Type: application/octet-stream
    Content-Transfer-Encoding: binary

    ...
    Dies ist der Dateiinhalt
    ...
    --1847a97df6a--                

    HTTP/1.1 200 OK
    Connection: keep-alive
    Content-Type: application/json
    Date: Tue, 15 Nov 2022 09:21:30 GMT
    Keep-Alive: timeout=60
    Transfer-Encoding: chunked

    {"status":"OK","description":null}

    Possible results with corresponding description:

    * OK – zeigt an, dass die Datei sauber ist und im CoLab-Flow verarbeitet werden kann. Beschreibung Feld ist leer
    * GEFUNDEN – Datei ist infiziert, zusätzliche Vireninformationen im Beschreibungsfeld
    * FEHLER – Fehler bei der Dateiverarbeitung, zusätzliche Fehlerinformationen im Beschreibungsfeld
  • Example of non-blocking calls – multi-part query – response status 202

    HTTP/1.1 202 Accepted
    Connection: keep-alive
    Date: Tue, 15 Nov 2022 09:30:23 GMT
    Keep-Alive: timeout=60
    Transfer-Encoding: chunked

    After accepting the query, the antivirus service behind the webhook URI endpoint scans the file. Once the job has been completed, the service must send the result with the corresponding ID to the callback URL.

    POST http://<gateway-IP>/colab/epr/av/callback/{id} HTTP/1.1
    accept: application/json
    authorization: ******
    connection: keep-alive
    content-length: 34
    content-type: application/json
    host: localhost:8066
    user-agent: Java/17.0.4.1

    {"status":"OK|FOUND|ERROR","description":null}

Setting Up the Spring Boot Antivirus Service with Java

These examples are intended to serve as a demonstration and not for production.

We need to configure an endpoint in the controller class in order to implement the processing of incoming queries.

  • Blocking implementation (response status 200)

    @RestController
    public class ExampleRestController
            
            @PostMapping(value = "/upload/{id}", consumes = "multipart/form-data")
            public ResponseEntity<WebHookResult> scan(@RequestPart("file") MultipartFile file, @PathVariable("id") String id) {
            
                    WebHookResult result = doVirusScan(file, id);
            
                    return ResponseEntity.ok(result);
            }
        
            @Data
            public class WebHookResult {
                private String status;
                private String description;
            
            }
    }
  • Non-blocking implementation (response status 202)

    @RestController
    public class ExampleRestController {
        
        @PostMapping(value = "/upload/{id}", consumes = "multipart/form-data")
        public ResponseEntity<?> asyncScan(@RequestPart("file") MultipartFile file, @PathVariable("id") String id) {

            new Thread(() -> {

                WebHookResult result = doVirusScan(file, id);

                OkHttpClient client = new OkHttpClient();
                MediaType JSON = MediaType.parse("application/json; charset=utf-8");
                String json = new ObjectMapper().writeValueAsString(result);
                RequestBody result = RequestBody.create(json, JSON);

                Request request = new Request.Builder()
                        .url("http://<gateway-IP>/colab/epr/av/callback/{id}")
                        .post(result)
                        .build();

                Response response = client.newCall(request).execute();

            }).start();

            return ResponseEntity.accepted().build();
        }
    }

Activating the Antivirus Webhook in coLab

The webhook is activated in enaio® coLab if colab-prod.yml has the following configuration properties:

  • Discoverable mode

    Works within the Service Manager.

    web-hooks:
      registration:
        antivirus:
          url: <service_name>
          discoverable: true
  • Non-discoverable mode

    Works outside the Service Manager.

    web-hooks:
      registration:
        antivirus:
          url: http://<antivirus_service_ip>:8067
          discoverable: false

Set the discoverable property to true and specify the instance name to activate the discoverable mode (works within the OS Service Manager).