Tutorial: Durchsuchen von Dateianlagen mit einem Antivirenprogramm

[AEM Forms]{class="badge positive" title="Gilt für AEM Forms"}

Die Funktion „File Attachment Virus Scanner / Validator“ ist im Early-Adopter-Programm enthalten. Sie können von Ihrer offiziellen E-Mail-Adresse aus an aem-forms-ea@adobe.com schreiben, um dem Early-Adopter-Programm beizutreten und den Zugriff auf diese Funktion zu beantragen.

Dieses Tutorial führt Sie durch den gesamten Prozess. Sie führen die ClamAV-Antiviren-Engine aus, fügen einen benutzerdefinierten Validator zu AEM hinzu, erstellen ein Beispiel für ein adaptives Formular mit einem Feld zum Hochladen von Dateien, verbinden den Validator und bestätigen, dass infizierte Dateien beim Senden zurückgewiesen werden. Es ist so geschrieben, dass es befolgt wird, auch wenn Sie neu in AEM sind. Alle Befehle, Bildschirmpfade und Werte, die Sie benötigen, werden angegeben.

Die Konzepte hinter dem Validator und die Schnittstellenreferenz finden Sie im Begleitartikel Scannen von Dateianlagen in adaptivem Forms mit einem benutzerdefinierten Validator. Sie müssen es nicht zuerst lesen, um dieses Tutorial abzuschließen, aber es erklärt, warum jedes Stück existiert.

Was Sie erstellen werden what-you-will-build

Am Ende haben Sie:

  • Ein laufender ClamAV-Daemon (clamd), der Dateien auf Anfrage scannt.
  • Ein benutzerdefinierter AEM-Dienst (der ClamAV-Scanner), der jede hochgeladene Datei an clamd sendet und infizierte Dateien zurückweist.
  • Ein Beispiel für ein adaptives Formular mit dem Namen File Attachment Scanner mit einem Feld „Datei-Upload“ und einer Schaltfläche „Senden“.
  • Funktionstest: Eine normale Datei wird erfolgreich gesendet, und eine bekannte Testvirusdatei wird blockiert.

Bevor Sie beginnen: Annahmen und Voraussetzungen assumptions

In diesem Tutorial wird von der folgenden Einrichtung ausgegangen. Wenn ein Element fehlt, installieren oder beziehen Sie es, bevor Sie beginnen. Zu jedem Element gehört, wie es überprüft wird.

#
Annahme
Vorgehensweise bei der Verifizierung
Anmerkungen
1
Eine lokale AEM-Autoreninstanz wird ausgeführt und ist unter http://localhost:4502 erreichbar.
Öffnen Sie http://localhost:4502 in einem Browser. Der AEM-Anmelde- oder Startbildschirm sollte angezeigt werden.
In diesem Tutorial wird der lokale Schnellstart für AEM as a Cloud Service SDK verwendet.
2
Sie können sich bei AEM als Admin anmelden
Melden Sie sich bei http://localhost:4502 mit einem Administratorkonto an (die standardmäßigen lokalen Anmeldeinformationen sind admin/admin)
Administratorrechte sind erforderlich, um Code bereitzustellen, die OSGi-Konfiguration zu ändern und Formulare zu erstellen.
3
Ihre AEM-Umgebung hat Anspruch auf die Funktion Early Access File-Attachment Validator , wobei der Umschalter für Funktionen FT_FORMS-23497 ist
Mit Ihrem Early-Adopter-Programm-Kontakt bestätigen
Dieser Umschalter erfasst die zugrunde liegende FileAttachmentValidatorManager. Das Feld der Registerkarte „Übermittlung“ selbst wird in diesem Tutorial in Schritt 7 hinzugefügt. So oder so ist es nicht vorkonfiguriert.
4
Sie haben im ui.apps-Modul Ihres Projekts einen Container Proxy Komponente) für adaptive Formulare oder können ihn erstellen
Siehe Schritt 7
Dies ist das Standardmuster für die Erweiterung einer AEM-Kernkomponente. Schritt 7 erstellt die Dialogfelderweiterung dafür.
5
Java JDK ist installiert und entspricht der erforderlichen Version von AEM SDK
java -version in einem Terminal ausführen
Verwenden Sie die Java-Version, die für Ihre AEM SDK erforderlich ist (für aktuelle SDKs ist dies Java 11 oder Java 21).
6
Apache Maven 3.x ist installiert
Führen Sie mvn -version aus.
Wird zum Erstellen und Bereitstellen des benutzerdefinierten Codes verwendet.
7
Docker ist installiert (empfohlener Pfad für die Ausführung von ClamAV)
Führen Sie docker --version aus.
Wenn Sie Docker nicht verwenden können, lesen Sie den Hinweis zur nativen Installation in Schritt 1.
8
Sie haben ein AEM Maven-Projekt oder können es erstellen, um benutzerdefinierten Code zu speichern
Siehe Schritt 2
In Schritt 2 wird eine erstellt, wenn Sie diese noch nicht haben.
9
Sie haben den neuesten verfügbaren Build des AEM Forms-Add-ons SDK heruntergeladen, das die Abhängigkeit vom frühzeitigen Zugriff enthält, die die com.adobe.forms.common.service bereitstellt
aem-forms-addon-sdk-<version>.zip vom Adobe Software Distribution-Portal herunterladen (Early-Adopter-Programmberechtigung erforderlich)
Erforderlich. Diese Abhängigkeit wird nicht in einem öffentlichen Maven-Repository veröffentlicht, sondern aus dem SDK-Download extrahiert. Frühere Builds enthalten sie möglicherweise nicht. Siehe Schritt 3.

Zu ersetzende Werte substitute-values

Wo immer Sie diese Platzhalter sehen, ersetzen Sie sie durch Ihre eigenen Werte:

  • <PROJECT_ROOT>: Der Ordner Ihres AEM Maven-Projekts.
  • <APP_ID>: Die Anwendungs-ID oder der Bundle-Modulname Ihres Projekts (z. B. mysite).
  • <SDK_DEPENDENCY_VERSION>: Die in der heruntergeladenen SDK gebündelte adobe-xfaforms-common (Gruppen-ID und Artefakt-ID sind fest; siehe Schritt 3).
NOTE
Alle Terminalbefehle werden für macOS und Linux angezeigt. Führen Sie sie unter Windows in PowerShell oder WSL aus. Die Docker- und Maven-Befehle sind identisch.

Fahrplan roadmap

Sie führen diese Schritte in der folgenden Reihenfolge aus:

  1. Starten Sie einen ClamAV-Daemon (clamd).
  2. Einrichten eines AEM Maven-Projekts (überspringen Sie diesen Schritt, wenn Sie bereits über eines verfügen).
  3. Fügen Sie die Early Access-Abhängigkeit hinzu.
  4. Fügen Sie die Klasse ClamAV-Validator hinzu.
  5. Erstellen und Bereitstellen für AEM.
  6. Konfigurieren Sie die clamd in AEM.
  7. Fügen Sie das Feld Validator zum Dialogfeld Formular hinzu.
  8. Erstellen Sie das Beispiel für ein adaptives Formular.
  9. Verbinden Sie den ClamAV-Scanner mit dem Formular.
  10. Testen Sie mit einer sauberen Datei und einer Testvirusdatei.

Schritt 1: ClamAV-Daemon starten step-1-clamd

ClamAV wird als Hintergrund-Service namens clamd ausgeführt. Der von Ihnen erstellte Validator streamt jede hochgeladene Datei an clamd, der OK auf eine bereinigte Datei antwortet oder den Namen der Bedrohung meldet, wenn er eine entdeckt.

Der schnellste Weg, clamd zum Laufen zu bringen, ist Docker.

  1. ClamAV starten:

    code language-none
    docker run -d --name clamav -p 3310:3310 clamav/clamav:latest
    
    note
    NOTE
    Auf Apple-Chip-Macs (arm64) verfügt dieses Image über keinen nativen arm64-Build und der obige Befehl schlägt mit no matching manifest for linux/arm64/v8 fehl. Fügen Sie --platform linux/amd64 hinzu, um sie stattdessen unter Emulation auszuführen:
    code language-none
    docker run -d --name clamav --platform linux/amd64 -p 3310:3310 clamav/clamav:latest
    
  2. Warte, bis er fertig ist. Beim ersten Start lädt es die Virendatenbank herunter, was einige Minuten dauern kann. Überwachen Sie die Protokolle, bis die Datenbank geladen wurde und clamd abhört:

    code language-none
    docker logs -f clamav
    

    Drücken Sie Ctrl+C, um die Verfolgung der Protokolle zu stoppen, sobald sie bereit ist.

  3. Stellen Sie sicher, dass clamd über Port 3310 erreichbar ist:

    code language-none
    printf 'PING\n' | nc localhost 3310
    

    Erwartetes Ergebnis: Die Antwort ist PONG.

NOTE
Wenn Sie Docker nicht verwenden können, installieren Sie ClamAV nativ von clamav.net, aktivieren Sie den clamd-Daemon und den TCP-Socket auf Port 3310 in clamd.conf, aktualisieren Sie die Datenbank mit freshclam und starten Sie clamd. Führen Sie dann die Überprüfung in Schritt 3 oben durch.
IMPORTANT
clamd wird als eigener Prozess ausgeführt, der von AEM getrennt ist. Dieses lokale Setup dient der Entwicklung. Auf AEM as a Cloud Service können Sie clamd nicht auf dem AEM-Host ausführen. Daher führen Sie es in realen Umgebungen als gemeinsamen oder externen Service aus und verweisen Sie den Validator darauf. Eine gemeinsame Instanz in derselben Region sollte bevorzugt werden, um Dateiinhalte in Ihrer Umgebung für die Datenresidenz und die Einhaltung von Vorschriften zu speichern.

Schritt 2: Einrichten eines AEM Maven-Projekts step-2-project

Benutzerdefinierter Java-Code wird in AEM als Bundle bereitgestellt, das von einem Maven-Projekt erstellt wurde. Wenn Sie bereits über ein AEM-Projekt verfügen, fahren Sie mit Schritt 3 fort und verwenden Sie das Bundle-Modul (häufig mit dem Namen core).

Wenn Sie noch kein solches Projekt haben, erstellen Sie ein Projekt mit dem AEM-Projektarchetyp:

  1. Wechseln Sie in einem Terminal in den Ordner, in dem Sie Code speichern, und führen Sie den Archetyp aus. Ersetzen Sie <APP_ID> durch einen kurzen Namen in Kleinbuchstaben, z. B. mysite:

    code language-none
    mvn -B org.apache.maven.plugins:maven-archetype-plugin:generate -D archetypeGroupId=com.adobe.aem -D archetypeArtifactId=aem-project-archetype -D archetypeVersion=LATEST -D appId=<APP_ID> -D appTitle="<APP_ID>" -D name="<APP_ID>" -D groupId=com.example -D artifactId=<APP_ID> -D aemVersion=cloud
    

    Erwartetes Ergebnis: ein neues <APP_ID> (dies ist Ihr <PROJECT_ROOT>), das Module wie core, ui.apps und all enthält.

  2. Der Java-Code, den Sie später hinzufügen, wird im core-Modul unter folgendem Pfad eingefügt:

    code language-none
    <PROJECT_ROOT>/core/src/main/java/
    
NOTE
Verwenden Sie die aktuelle Archetypversion. Siehe die Dokumentation zum AEM-Projektarchetyp. Der Archetyp generiert viele Dateien, aber für dieses Tutorial bearbeiten Sie nur das core.

Schritt 3: Frühzeitige Zugriffs-Abhängigkeit hinzufügen step-3-dependency

Der Code wird anhand der FileAttachmentValidator-Schnittstelle kompiliert, die von com.adobe.forms.foundation:adobe-xfaforms-common stammt (#9). Diese Abhängigkeit wird nicht in einem öffentlichen Maven-Repository veröffentlicht. Sie wird gebündelt im AEM Forms-Add-on SDK ausgeliefert, sodass Sie sie von dort extrahieren und in Ihr lokales Maven-Repository installieren können.

  1. Laden Sie den neuesten verfügbaren Build von aem-forms-addon-sdk-<version>.zip vom Adobe Software Distribution-Portal (Berechtigung für Early-Adopter-Programm erforderlich) herunter. Verwenden Sie immer den neuesten Build. Frühere Builds enthalten diese Abhängigkeit möglicherweise noch nicht.

  2. Extrahieren Sie die Abhängigkeits-JAR-Datei. Die SDK-ZIP-Datei enthält ein Funktionsarchiv (.far), und das JAR ist darin gebündelt:

    code language-none
    unzip -p aem-forms-addon-sdk-<version>.zip aem-forms-addon-<version>.far > addon.far
    unzip -l addon.far | grep adobe-xfaforms-common
    

    Der zweite Befehl zeigt den genauen JAR-Pfad und die Version an, die im Download enthalten sind, z. B. com/adobe/forms/foundation/adobe-xfaforms-common/<version>/adobe-xfaforms-common-<version>.jar. Verwenden Sie diesen Pfad und diese Version im nächsten Schritt.

    code language-none
    unzip -p addon.far "com/adobe/forms/foundation/adobe-xfaforms-common/<version>/adobe-xfaforms-common-<version>.jar" > adobe-xfaforms-common.jar
    
  3. Installieren Sie die extrahierte JAR-Datei in Ihrem lokalen Maven-Repository, damit pom.xml sie beheben können. -DgeneratePom=true einschließen: In JAR wird ein eigenes internes Adobe-Build-POM mit einem übergeordneten Verweis eingebettet, den Ihr Projekt nicht auflösen kann. Dieses Flag ersetzt es durch ein sauberes, in sich abgeschlossenes:

    code language-none
    mvn install:install-file -Dfile=adobe-xfaforms-common.jar -DgroupId=com.adobe.forms.foundation -DartifactId=adobe-xfaforms-common -Dversion=<version> -Dpackaging=jar -DgeneratePom=true
    
  4. Öffnen Sie <PROJECT_ROOT>/core/pom.xml.

  5. Fügen Sie im Abschnitt <dependencies> die Abhängigkeit mit derselben Version hinzu, die Sie gerade installiert haben. Verwenden Sie provided Bereich, da die Schnittstelle zur Laufzeit von AEM bereitgestellt wird:

    code language-xml
    <dependency>
        <groupId>com.adobe.forms.foundation</groupId>
        <artifactId>adobe-xfaforms-common</artifactId>
        <version><SDK_DEPENDENCY_VERSION></version>
        <scope>provided</scope>
    </dependency>
    
  6. Speichern Sie die Datei.

IMPORTANT
Wenn Sie noch keinen Zugriff auf das Software Distribution-Portal haben, fordern Sie die Early-Adopter-Programmberechtigung von Ihrem Adobe-Ansprechpartner an. Ohne diese Abhängigkeit wird das Projekt nicht kompiliert.

Schritt 4: Hinzufügen der ClamAV-Validatorklasse step-4-class

  1. Erstellen Sie eine neue Datei unter:

    code language-none
    <PROJECT_ROOT>/core/src/main/java/com/example/forms/security/ClamAVFileAttachmentValidator.java
    

    Erstellen Sie die forms/security Ordner, falls sie noch nicht vorhanden sind. Sie können Ihren eigenen Paketnamen verwenden. Ändern Sie in diesem Fall die package entsprechend.

  2. Fügen Sie den folgenden Code ein:

    code language-java
    package com.example.forms.security;
    
    import com.adobe.forms.common.service.FileAttachmentValidator;
    import com.adobe.forms.common.service.FileAttachmentValidationResult;
    import com.adobe.forms.common.service.FileAttachmentWrapper;
    import org.osgi.service.component.annotations.Activate;
    import org.osgi.service.component.annotations.Component;
    import org.osgi.service.metatype.annotations.AttributeDefinition;
    import org.osgi.service.metatype.annotations.Designate;
    import org.osgi.service.metatype.annotations.ObjectClassDefinition;
    
    import java.io.ByteArrayOutputStream;
    import java.io.DataOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.nio.charset.StandardCharsets;
    
    @Component(service = FileAttachmentValidator.class)
    @Designate(ocd = ClamAVFileAttachmentValidator.Config.class)
    public class ClamAVFileAttachmentValidator implements FileAttachmentValidator {
    
        @ObjectClassDefinition(name = "ClamAV File Attachment Scanner")
        public @interface Config {
            @AttributeDefinition(name = "clamd Host")
            String clamd_host() default "localhost";
    
            @AttributeDefinition(name = "clamd Port")
            int clamd_port() default 3310;
    
            @AttributeDefinition(name = "Scan Timeout (ms)")
            int clamd_timeout() default 30000;
        }
    
        private static final String VALIDATOR_NAME = "ClamAV Scanner";
        private static final int CHUNK_SIZE = 8192;
    
        private String host;
        private int port;
        private int timeout;
    
        @Activate
        protected void activate(Config config) {
            this.host = config.clamd_host();
            this.port = config.clamd_port();
            this.timeout = config.clamd_timeout();
        }
    
        @Override
        public FileAttachmentValidationResult validateFileAttachment(FileAttachmentWrapper wrapper) {
    
            if (wrapper == null) {
                return new FileAttachmentValidationResult(false, "No attachment was received.", wrapper);
            }
    
            byte[] content = wrapper.getValue();
            if (content == null || content.length == 0) {
                return new FileAttachmentValidationResult(false, "The attached file is empty.", wrapper);
            }
    
            try {
                String response = scan(content);
    
                if (response.endsWith("OK")) {
                    return new FileAttachmentValidationResult(true, "File passed the virus scan.", wrapper);
                }
                if (response.contains("FOUND")) {
                    return new FileAttachmentValidationResult(false,
                            "A virus was detected in the attached file. Upload was rejected.", wrapper);
                }
                return new FileAttachmentValidationResult(false,
                        "The file could not be scanned. Please try again later.", wrapper);
    
            } catch (Exception e) {
                // Fail closed: reject when clamd is unreachable rather than accept an unscanned file.
                return new FileAttachmentValidationResult(false,
                        "The virus scanner is unavailable. Please try again later.", wrapper);
            }
        }
    
        /**
         * Streams the file to clamd using the INSTREAM command and returns the daemon's response.
         */
        private String scan(byte[] data) throws Exception {
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress(host, port), timeout);
                socket.setSoTimeout(timeout);
    
                try (OutputStream raw = socket.getOutputStream();
                     DataOutputStream out = new DataOutputStream(raw);
                     InputStream in = socket.getInputStream()) {
    
                    out.writeBytes("zINSTREAM\0");
    
                    for (int offset = 0; offset < data.length; offset += CHUNK_SIZE) {
                        int len = Math.min(CHUNK_SIZE, data.length - offset);
                        out.writeInt(len);
                        out.write(data, offset, len);
                    }
    
                    out.writeInt(0); // zero-length chunk signals end of stream
                    out.flush();
    
                    ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream();
                    byte[] buffer = new byte[512];
                    int read;
                    while ((read = in.read(buffer)) != -1) {
                        responseBuffer.write(buffer, 0, read);
                    }
                    return responseBuffer.toString(StandardCharsets.US_ASCII.name()).trim();
                }
            }
        }
    
        @Override
        public String getFileAttachmentValidatorName() {
            return VALIDATOR_NAME;
        }
    }
    
  3. Speichern Sie die Datei.

Schritt 5: Erstellen und Bereitstellen in AEM step-5-deploy

  1. Wenn AEM ausgeführt wird (#1), erstellen Sie und stellen Sie über Ihren Projektstamm bereit. Mit diesem Befehl wird das Bundle in der lokalen Autoreninstanz installiert:

    code language-none
    cd <PROJECT_ROOT>
    mvn clean install -PautoInstallBundle
    

    Erwartetes Ergebnis: Build endet mit BUILD SUCCESS.

  2. Bestätigen Sie, dass der Dienst ausgeführt wird. Öffnen Sie die Komponentenkonsole:

    code language-none
    http://localhost:4502/system/console/components
    

    Diese Seite verfügt über kein integriertes Suchfeld: Verwenden Sie bei mehr als 5.000 aufgelisteten Komponenten die eigene Suchseite Ihres Browsers (Befehl+F oder Strg+F) und suchen Sie nach ClamAVFileAttachmentValidator.

    Erwartetes Ergebnis: die Komponente aufgeführt wird und ihr Status "" (oder ""). Wenn er nicht zufrieden ist, lesen Sie Fehlerbehebung.

    Komponentenkonsole, in der ClamAVFileAttachmentValidator und FileAttachmentValidatorDataSourceServlet als aktiv angezeigt werden

Schritt 6: Clad-Verbindung konfigurieren step-6-config

Teilen Sie dem Validator mit, wo clamd ist. Für die lokale Entwicklung stimmen die Standardwerte (localhost:3310) bereits mit Schritt 1 überein, sodass dieser Schritt nur erforderlich ist, wenn sich Ihre Werte unterscheiden. Einmal durchführen, um zu bestätigen, dass die Einstellungen existieren.

  1. Öffnen Sie die Konfigurationskonsole:

    code language-none
    http://localhost:4502/system/console/configMgr
    
  2. Diese Seite verfügt auch über kein integriertes Suchfeld: Verwenden Sie die Suchseite Ihres Browsers (Befehl+F oder Strg+F) für ClamAV File Attachment Scanner und öffnen Sie sie.

  3. Bestätigen oder festlegen:

    table 0-row-2 1-row-2 2-row-2 3-row-2
    Einstellung Wert für dieses Tutorial
    klamme Wirt localhost
    Klammerauslass 3310
    Scan-Zeitüberschreitung (ms) 30000

    Dialogfeld „ClamAV-Dateianhang-Scanner-Konfiguration“ in der OSGi-Konfigurationskonsole

  4. Wählen Sie Speichern aus.

NOTE
Stellen Sie in realen Umgebungen diese Werte als OSGi-Repository-Konfiguration in Ihrem Projekt bereit (eine .cfg.json-Datei pro Umgebung), damit sie mit jeder Bereitstellung übertragen werden, anstatt von Hand festgelegt zu werden.

Schritt 7: Hinzufügen des Validierungsfelds zum Dialogfeld „Formular“ step-7-dialog-field

Das Feld Dateianhang-Virenscanner/) ist im vorkonfigurierten Dialogfeld Container für adaptive Formulare nicht vorhanden. Bei auf Kernkomponenten basierenden Formularen fügen Sie sie einmal in Ihrem eigenen Projekt hinzu. Dies ist ein einmaliger Schritt. Sie wiederholen ihn nicht, wenn Sie später weitere Validatoren hinzufügen.

  1. Wenn Ihre formcontainer-Proxy-Komponente noch nicht vorhanden ist, erstellen Sie sie unter:

    code language-none
    <PROJECT_ROOT>/ui.apps/src/main/content/jcr_root/apps/<APP_ID>/components/adaptiveForm/formcontainer/.content.xml
    
    code language-xml
    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Form Container"
        sling:resourceSuperType="core/fd/components/form/container/v2/container"/>
    

    Wenn Sie diese Komponente bereits haben (die meisten Projekte, die aus dem Kernkomponenten-Archetyp erstellt wurden, tun dies), fahren Sie mit dem nächsten Schritt fort.

  2. Erstellen Sie eine Dialogfelderweiterung unter:

    code language-none
    <PROJECT_ROOT>/ui.apps/src/main/content/jcr_root/apps/<APP_ID>/components/adaptiveForm/formcontainer/_cq_dialog/.content.xml
    
    code language-xml
    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
        jcr:primaryType="nt:unstructured">
      <content jcr:primaryType="nt:unstructured">
        <items jcr:primaryType="nt:unstructured">
          <tabs jcr:primaryType="nt:unstructured">
            <items jcr:primaryType="nt:unstructured">
              <submitActions jcr:primaryType="nt:unstructured">
                <items jcr:primaryType="nt:unstructured">
                  <columns jcr:primaryType="nt:unstructured">
                    <items jcr:primaryType="nt:unstructured">
                      <fileAttachmentValidator
                          jcr:primaryType="nt:unstructured"
                          sling:resourceType="granite/ui/components/coral/foundation/form/select"
                          fieldLabel="File Attachment Virus Scanner/Validator"
                          fieldDescription="Select a registered validator configuration to scan submitted file attachments. Select None to disable validation for this form."
                          emptyText="None"
                          name="./fileAttachmentValidator">
                        <datasource
                            jcr:primaryType="nt:unstructured"
                            sling:resourceType="<APP_ID>/datasources/fileattachmentvalidators"/>
                      </fileAttachmentValidator>
                    </items>
                  </columns>
                </items>
              </submitActions>
            </items>
          </tabs>
        </items>
      </content>
    </jcr:root>
    

    Dadurch wird nur das eine neue Feld definiert, wobei die Knotennamen des echten Dialogfelds bis zur Einfügemarke gespiegelt werden. Die vorhandenen Felder der Registerkarte „Übermittlung“ werden nicht neu definiert oder ersetzt. Warum ​ funktioniert, erfahren Sie im Begleitartikel ​ Dialogfeld „Hinzufügen des Validierungsfelds zum Formular“.

  3. Fügen Sie das Datenquellen-Servlet hinzu, das Ihre registrierten Validatoren auflistet. Er ist unabhängig davon, welche Validator-Engine Sie verwenden. Siehe Hinzufügen des Validator-Felds zum Formular-Dialogfeld im Begleitartikel, um zu erfahren, was und warum er tut. Erstellen Sie sie unter:

    code language-none
    <PROJECT_ROOT>/core/src/main/java/com/example/forms/security/FileAttachmentValidatorDataSourceServlet.java
    
    code language-java
    package com.example.forms.security;
    
    import com.adobe.forms.common.service.FileAttachmentValidator;
    import com.adobe.forms.common.service.FileAttachmentValidatorManager;
    import com.adobe.granite.ui.components.ds.DataSource;
    import com.adobe.granite.ui.components.ds.SimpleDataSource;
    import com.adobe.granite.ui.components.ds.ValueMapResource;
    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.api.SlingHttpServletResponse;
    import org.apache.sling.api.resource.Resource;
    import org.apache.sling.api.resource.ResourceMetadata;
    import org.apache.sling.api.servlets.HttpConstants;
    import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
    import org.apache.sling.api.wrappers.ValueMapDecorator;
    import org.apache.sling.servlets.annotations.SlingServletResourceTypes;
    import org.osgi.service.component.annotations.Component;
    import org.osgi.service.component.annotations.Reference;
    import org.osgi.service.component.annotations.ReferenceCardinality;
    import org.osgi.service.component.annotations.ReferencePolicy;
    
    import javax.servlet.Servlet;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Component(service = { Servlet.class })
    @SlingServletResourceTypes(
            resourceTypes = "<APP_ID>/datasources/fileattachmentvalidators",
            methods = HttpConstants.METHOD_GET)
    public class FileAttachmentValidatorDataSourceServlet extends SlingSafeMethodsServlet {
    
        @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
        private volatile FileAttachmentValidatorManager fileAttachmentValidatorManager;
    
        @Override
        protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
            List<Resource> options = new ArrayList<>();
    
            FileAttachmentValidatorManager manager = fileAttachmentValidatorManager;
            if (manager != null) {
                List<FileAttachmentValidator> validators = manager.getValidators();
                if (validators != null) {
                    for (FileAttachmentValidator validator : validators) {
                        String name = validator.getFileAttachmentValidatorName();
                        if (name != null && !name.isEmpty()) {
                            options.add(createOption(request, name));
                        }
                    }
                }
            }
    
            DataSource dataSource = new SimpleDataSource(options.iterator());
            request.setAttribute(DataSource.class.getName(), dataSource);
        }
    
        private Resource createOption(SlingHttpServletRequest request, String name) {
            Map<String, Object> props = new HashMap<>();
            props.put("value", name);
            props.put("text", name);
            return new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(),
                    "nt:unstructured", new ValueMapDecorator(props));
        }
    }
    

    Ersetzen Sie <APP_ID> sowohl im XML-Dialogfeld als auch im resourceTypes des Servlets mit der tatsächlichen Anwendungs-ID Ihres Projekts (übereinstimmender #4) und passen Sie den Paketnamen an, wenn sich Ihre Angaben von Schritt 4 unterscheiden.

  4. Erstellen und stellen Sie beide Änderungen bereit. Sie haben Inhalt (das Dialogfeld) und Code (das Servlet) geändert. Verwenden Sie daher beide Profile gemeinsam: autoInstallPackage allein stellt nur den Inhalt bereit und lässt das Paket des Servlets nicht erneut bereitgestellt.

    code language-none
    cd <PROJECT_ROOT>
    mvn clean install -PautoInstallPackage,autoInstallBundle
    

    Erwartetes Ergebnis: Der Build endet mit BUILD SUCCESS, und das ui.apps Inhaltspaket (einschließlich dieser Dialogfeldänderung) und das core-Bundle (einschließlich des neuen Servlets) sind beide installiert.

NOTE
Sie können im Laufe der Zeit mehr als einen Validator registrieren, z. B. einen pro Antiviren-Engine oder mehrere unterschiedlich konfigurierte Instanzen derselben Engine. Hier muss sich nichts ändern: Jedes registrierte FileAttachmentValidator wird automatisch in der Dropdown-Liste angezeigt, da jedes über eine eigene getFileAttachmentValidatorName() verfügt, und emptyText="None" behält „Kein Validator“ als Standard bei, sodass vorhandene Formulare nicht betroffen sind, bis Sie eines explizit auswählen.

Schritt 8: Adaptives Beispielformular erstellen step-8-form

Erstellen Sie jetzt ein einfaches Formular mit einem Feld „Datei-Upload“.

  1. Öffnen von Forms und Dokumenten:

    code language-none
    http://localhost:4502/aem/forms.html/content/dam/formsanddocuments
    
  2. Wählen Erstellen (oben rechts) und dann Adaptives Formular aus.

  3. Wählen Sie eine Vorlage aus der Galerie aus. Die Grundlage ist keine separate Frage: Sie ist Teil der von Ihnen ausgewählten Vorlage und wird als kleiner Untertitel unter dem Namen jeder Vorlage angezeigt (z. B. adaptives Formular (Kernkomponenten).

    note important
    IMPORTANT
    Mehrere Vorlagen werden alle als leeres Formular bezeichnet: eine für Kernkomponenten, eine für Foundation-Komponenten, eine für Edge Delivery Services. Das Auswählen des falschen ist leicht zu übersehen und schlägt leise fehl: Der Rest dieses Tutorials scheint weiterhin zu funktionieren, aber das Feld Dateianhang-Virenscanner / -Validator wird nie aufgerufen, da diese Pipeline nur für Kernkomponenten-basierte Formulare vorhanden ist. Bestätigen Sie, dass der Untertitel Adaptives Formular (Kernkomponenten)) lautet bevor Sie fortfahren.
  4. Legen in „Eigenschaften Folgendes fest:

    • Titel: File Attachment Scanner Demo
    • Design Wählen Sie ein verfügbares Design aus (z. B. Arbeitsfläche).

    Wählen Sie dann Erstellen aus.

  5. Wählen Sie im Bestätigungsdialog die Option Öffnen aus, um das Formular im Editor zu öffnen.

    Erwartetes Ergebnis: Der Editor für adaptive Formulare wird mit einem leeren Formular geöffnet.

  6. Feld für Datei-Upload hinzufügen:

    • Öffnen Sie den Komponenten-Browser (über das Symbol „Komponenten“ in der linken Leiste oder wählen Sie den leeren Formularbereich aus und wählen Sie die Option „Komponente einfügen„).
    • Suchen Sie die Komponente Dateianhang und ziehen Sie sie auf das Formular.
  7. Schaltfläche „Senden“ hinzufügen:

    • Ziehen Sie im selben Komponenten-Browser eine Schaltfläche Adaptives Formular auf das Formular, und zwar unter dem Dateifeld.
    • Wählen Sie die Schaltfläche aus, öffnen Sie ihre Eigenschaften (das Schraubenschlüsselsymbol), legen Sie ihren Schaltflächentyp auf Senden fest und bestätigen Sie den Vorgang.
  8. Speichern Sie das Formular. Der Editor speichert automatisch, Sie können es jedoch erzwingen, indem Sie den Editor verlassen.

    Erwartetes Ergebnis: Das Formular verfügt jetzt über ein Dateianhang-Feld und eine Senden-Schaltfläche.

Schritt 9: Verbinden des ClamAV-Scanners mit dem Formular step-9-connect

  1. Wählen Sie im Formular-Editor den Guide-Container (der äußerste Container) aus, um die Eigenschaften Container für adaptive Formulare zu öffnen. Verwenden Sie das Symbol Eigenschaften (Schraubenschlüssel) .

  2. Öffnen Sie die Registerkarte Übermittlung.

  3. Suchen Sie die Dropdown Liste „File Attachment Virus Scanner / Validator und wählen Sie ClamAV Scanner.

    Dieses Feld und die Liste der Optionen stammen aus Schritt 7: der Dialogfelderweiterung und dem Datenquellen-Servlet, die Sie in Ihrem eigenen Projekt bereitgestellt haben. Der Eintrag ist der Name, der von getFileAttachmentValidatorName() in Ihrem Code zurückgegeben wird. Wenn Sie VALIDATOR_NAME geändert haben, wählen Sie stattdessen diesen Namen aus.

    note important
    IMPORTANT
    Wenn dieses Feld vollständig fehlt, haben Sie Schritt 7 nicht abgeschlossen oder das ui.apps-Paket aus Schritt 7 wurde nicht bereitgestellt. Dieses Feld ist nie vorkonfiguriert für Formulare, die auf Kernkomponenten basieren.
  4. Wählen Sie Fertig und speichern Sie dann das Formular.

Registerkarte „Übermittlung“ im Dialogfeld „Container für adaptive Formulare“ mit ausgewähltem ClamAV-Scanner im Feld „Virenscanner/Validator für Dateianhänge“

Schritt 10: Testen der Integration step-10-test

Testen Sie beide Ergebnisse.

Test A: Eine saubere Datei wird akzeptiert test-clean

  1. Öffnen Sie die Vorschau des Formulars:

    code language-none
    http://localhost:4502/content/dam/formsanddocuments/file-attachment-scanner-demo/jcr:content?wcmmode=disabled
    

    Wenn sich der Pfad Ihres Formulars unterscheidet, öffnen Sie es in Forms und in Dokumenten und wählen Sie Vorschau.

  2. Hängen Sie eine normale PDF oder ein normales Bild an und klicken Sie dann auf Senden.

    Erwartetes Ergebnis: Das Formular wurde erfolgreich gesendet.

Test B: Ein Testvirus ist blockiert test-virus

  1. Erstellen Sie eine Nur-Text-Datei mit dem Namen eicar.txt, deren Inhalt nur die standardmäßige EICAR-Antiviren-Testzeichenfolge ist. Dies ist eine harmlose Datei, die jede Antiviren-Engine absichtlich erkennt:

    code language-none
    X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
    

    Sie können es auch von eicar.org herunterladen.

  2. Fügen Sie im Formular eicar.txt an und wählen Sie Senden.

    Erwartetes Ergebnis: Die Übermittlung ist blockiert. Wie die Zurückweisung angezeigt wird, hängt von der konfigurierten Übermittlungsaktion ab: Ein standardmäßiger Dankeseiten-Seitenfluss zeigt in der Regel einen Inline-Fehler im Dateifeld an, während An REST-Endpunkt übermitteln (im Beispielformular dieses Tutorials wird dies verwendet) in der Regel eine generische Meldung anzeigt, bei der die Übermittlung fehlgeschlagen ist, anstatt einer Meldung auf Feldebene. In beiden Fällen wird das Formular nicht übermittelt.

  3. Bestätigen Sie, dass der Validator tatsächlich ausgeführt und die Datei abgelehnt hat. Überprüfen Sie das AEM-Fehlerprotokoll. Dies ist die zuverlässige Methode, um zu sehen, was passiert ist, unabhängig davon, wie der Fehler im Browser angezeigt wurde:

    code language-none
    <AEM_SDK_FOLDER>/crx-quickstart/logs/error.log
    

    Suchen Sie nach der Ablehnungsmeldung von Ihrem Validator (z. B. A virus was detected in the attached file).

Fehlerbehebung troubleshooting

docker runschlägt mit no matching manifest for linux/arm64/v8 fehl. Sie befinden sich auf einem Apple Silicon Mac; das clamav/clamav-Image hat keinen nativen arm64-Build. Fügen Sie dem Befehl in Schritt 1 --platform linux/amd64 hinzu.

PONGin Schritt 1 nicht zurückgegeben. clamd ist nicht bereit oder der Port ist nicht veröffentlicht. Überprüfen Sie docker logs clamav auf den Abschluss des Datenbank-Ladevorgangs und bestätigen Sie, dass der Container dem Port 3310 (docker ps) zugeordnet ist.

Der Archetyp-Befehl von Schritt 2 schlägt mit Unsupported class file major version... fehl. Ihr standardmäßiges java/mvn wird auf einem neueren JDK ausgeführt als #5 Annahme zulässt: Das Post-Generation-Skript des Archetyps kann Klassendateien aus Java-Versionen neuer als 21 nicht analysieren. Verweisen Sie JAVA_HOME auf eine Java 11- oder Java 21-Installation und führen Sie den Befehl erneut aus. Wenn beim ersten Versuch bereits teilweise ein Projekt generiert wurde (nicht übereinstimmende Modulordner, fehlende Dateien), löschen Sie dieses Ausgabeverzeichnis, bevor Sie es erneut versuchen, anstatt es an Ort und Stelle erneut auszuführen.

Projekt wird nicht kompiliert (FileAttachmentValidator kann nicht gefunden werden). Die Early-Access-Abhängigkeit (Schritt 3) fehlt, wurde nicht in Ihrem lokalen Maven-Repository installiert oder die Version von pom.xml stimmt nicht mit der installierten JAR-Datei überein. Überprüfen Sie die Version mit unzip -l addon.far | grep adobe-xfaforms-common erneut.

Komponente ist in Schritt 5 nicht erfüllt. Öffnen Sie http://localhost:4502/system/console/components, suchen Sie ClamAVFileAttachmentValidator und lesen Sie den Grund. Eine fehlende Schnittstelle bedeutet normalerweise, dass die Abhängigkeit zur Laufzeit nicht vorhanden ist. Vergewissern Sie sich, dass Ihre AEM-Umgebung über die Early-Access-Funktion verfügt.

Das Feld Virenscanner/Validator für Dateianhänge wird auf der Registerkarte Übermittlung überhaupt nicht angezeigt (Schritt 9). Bestätigen Sie, dass das Paket Schritt 7 ui.apps (die Dialogfelderweiterung und das Datenquellen-Servlet) tatsächlich bereitgestellt wurde. Überprüfen Sie http://localhost:4502/system/console/components auf FileAttachmentValidatorDataSourceServlet. Bestätigen Sie außerdem, dass der Umschalter FT_FORMS-23497-Funktion für Ihr Programm aktiviert ist. Dadurch wird die zugrunde liegende FileAttachmentValidatorManager-Funktion geprüft, von der die Datenquelle abhängt.

Das Feld wird angezeigt, aber ClamAV Scanner ist nicht in der Dropdown-Liste (Schritt 9). Vergewissern Sie sich, dass die ClamAVFileAttachmentValidator aktiv ist, dass getFileAttachmentValidatorName() einen eindeutigen, nicht leeren Wert zurückgibt, und laden Sie den Formular-Editor nach der Bereitstellung neu.

Jede Datei wird abgelehnt, auch saubere. Der Validator kann nicht geschlossen werden, was in der Regel bedeutet, dass er clamd nicht erreichen kann. Überprüfen Sie Schritt 1 erneut (läuft clamd und kehrt PONG zurück?) und Schritt 6 (Host, Port, Zeitüberschreitung). Suchen Sie in error.log nach Verbindungsfehlern oder ERROR.

Scannt Zeitüberschreitung oder INSTREAM size limit exceeded. Die Datei ist zu groß für die Zeitüberschreitung oder die StreamMaxLength von clamd. Erhöhen Sie die maximale Wartezeit in Schritt 6, erhöhen Sie die StreamMaxLength in clamd.conf und legen Sie eine maximale Dateigröße für die Komponente Dateianhang fest, damit übergroße Dateien früher gestoppt werden.

Bei der EICAR-Übermittlung wird eine allgemeine Fehlermeldung und keine Inline-Feldmeldung angezeigt (Schritt 10). Dies ist bei einer Übermittlungsaktion An REST-Endpunkt übermitteln zu erwarten; es ändert nichts daran, ob die Datei tatsächlich abgelehnt wurde. Überprüfen Sie error.log zur Bestätigung der Zurückweisungsmeldung des Validators.

Häufig gestellte Fragen faq

Kann AEM Forms Uploads mit ClamAV scannen?
Ja. Sie implementieren die FileAttachmentValidator mit einem Service, der jede hochgeladene Datei bei der Übermittlung an einen ClamAV-Daemon (clamd) streamt und die Datei ablehnt, wenn ClamAV eine Bedrohung meldet.

Muss ich ClamAV auf dem AEM-Server installieren?
Anzahl clamd wird als separater Prozess ausgeführt. Ihr Validator stellt eine Verbindung dazu über TCP her. Führen Sie sie lokal für die Entwicklung und als gemeinsamen oder externen Service in realen Umgebungen aus.

Welchen Port verwendet Clamd?
Standardmäßig ist TCP-Port 3310. Der Beispiel-Validator verwendet diesen Port und lässt Sie über die OSGi-Konfiguration ändern.

Wie kann ich testen, ob die Virensuche funktioniert?
Übermitteln Sie eine gewöhnliche Datei, um zu bestätigen, dass sie akzeptiert wird, und übermitteln Sie dann die EICAR-Testdatei (eine harmlose, dem Industriestandard entsprechende Testzeichenfolge), um zu bestätigen, dass sie erkannt und blockiert wird.

Warum werden alle meine Dateien abgelehnt?
Der Beispielvalidator schlägt fehl und führt aufgrund eines Verbindungsproblems mit clamd dazu, dass jede Datei abgelehnt wird. Überprüfen Sie, ob clamd ausgeführt und erreichbar ist, und überprüfen Sie die Host-, Port- und Zeitüberschreitungseinstellungen.

Kann ich ClamAV mit AEM as a Cloud Service verwenden?
Ja, aber Sie können clamd nicht auf dem AEM-Host ausführen. Führen Sie es als gemeinsam verwendeten oder externen Service aus und lassen Sie den Validator darauf verweisen, idealerweise in derselben Region, um Dateiinhalte in Ihrer Umgebung zu speichern.

Kann ich die Prüfung vor der Übermittlung ausführen, sobald die Datei angehängt ist?
Ja. Der Validator dieses Tutorials wird bei der Übermittlung ausgeführt. Um zu überprüfen, sobald ein Benutzer eine Datei angehängt hat, bevor er sie sendet, verwenden Sie den Vorgang Service aufrufen im Regeleditor für adaptive Forms, um einen Scan-Service für das Änderungsereignis des Dateifelds aufzurufen. Siehe Aufrufen von Service-Verbesserungen im Regeleditor.

recommendation-more-help
experience-manager-cloud-service-help-main-toc