mirror of
https://github.com/itplr-kosit/validator.git
synced 2026-05-25 16:55:39 +00:00
get rid of ObjectFactory.java
This commit is contained in:
parent
5b1d0cd467
commit
d0000fc698
20 changed files with 494 additions and 445 deletions
1
.idea/compiler.xml
generated
1
.idea/compiler.xml
generated
|
|
@ -2,6 +2,7 @@
|
|||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
|
|
|
|||
1
.idea/encodings.xml
generated
1
.idea/encodings.xml
generated
|
|
@ -2,6 +2,7 @@
|
|||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/generated/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/model" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.3.0 generiert
|
||||
// Siehe <a href="https://javaee.github.io/jaxb-v2/">https://javaee.github.io/jaxb-v2/</a>
|
||||
// Änderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren.
|
||||
// Generiert: 2020.04.29 um 03:45:08 PM CEST
|
||||
//
|
||||
|
||||
|
||||
package de.kosit.validationtool.model.daemon;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.annotation.XmlElementDecl;
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each
|
||||
* Java content interface and Java element interface
|
||||
* generated in the de.xoev.de.validator.framework._1.daemon package.
|
||||
* <p>An ObjectFactory allows you to programatically
|
||||
* construct new instances of the Java representation
|
||||
* for XML content. The Java representation of XML
|
||||
* content can consist of schema derived interfaces
|
||||
* and classes representing the binding of schema
|
||||
* type definitions, element declarations and model
|
||||
* groups. Factory methods for each of these are
|
||||
* provided in this class.
|
||||
*
|
||||
*/
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
private final static QName _Health_QNAME = new QName("http://www.xoev.de/de/validator/framework/1/daemon", "health");
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: de.xoev.de.validator.framework._1.daemon
|
||||
*
|
||||
*/
|
||||
public ObjectFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link HealthType }
|
||||
*
|
||||
*/
|
||||
public static HealthType createHealthType() {
|
||||
return new HealthType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link ApplicationType }
|
||||
*
|
||||
*/
|
||||
public static ApplicationType createApplicationType() {
|
||||
return new ApplicationType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link MemoryType }
|
||||
*
|
||||
*/
|
||||
public static MemoryType createMemoryType() {
|
||||
return new MemoryType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link HealthType }{@code >}
|
||||
*
|
||||
* @param value
|
||||
* Java instance representing xml element's value.
|
||||
* @return
|
||||
* the new instance of {@link JAXBElement }{@code <}{@link HealthType }{@code >}
|
||||
*/
|
||||
@XmlElementDecl(namespace = "http://www.xoev.de/de/validator/framework/1/daemon", name = "health")
|
||||
public static JAXBElement<HealthType> createHealth(final HealthType value) {
|
||||
return new JAXBElement<HealthType>(_Health_QNAME, HealthType.class, null, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ class ExtractHtmlContentAction implements CheckAction {
|
|||
log.info("Writing report html '{}' to {}", name, file.toAbsolutePath());
|
||||
serializer.serializeNode(node);
|
||||
} catch (final SaxonApiException e) {
|
||||
log.info("Error extracting html content to {}", file.toAbsolutePath(), e);
|
||||
log.error("Error extracting html content to {}", file.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
import static de.kosit.validationtool.impl.DateFactory.createTimestamp;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -12,6 +14,7 @@ import java.util.stream.Collectors;
|
|||
import javax.xml.validation.Schema;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
@ -21,6 +24,10 @@ import de.kosit.validationtool.impl.ContentRepository;
|
|||
import de.kosit.validationtool.impl.ResolvingMode;
|
||||
import de.kosit.validationtool.impl.Scenario;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.model.scenarios.DescriptionType;
|
||||
import de.kosit.validationtool.model.scenarios.NoScenarioReportType;
|
||||
import de.kosit.validationtool.model.scenarios.ObjectFactory;
|
||||
import de.kosit.validationtool.model.scenarios.Scenarios;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
|
||||
|
|
@ -52,6 +59,8 @@ public class ConfigurationBuilder {
|
|||
|
||||
private URI repository;
|
||||
|
||||
private String description;
|
||||
|
||||
public ConfigurationBuilder author(final String authorName) {
|
||||
this.author = authorName;
|
||||
return this;
|
||||
|
|
@ -84,6 +93,11 @@ public class ConfigurationBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ConfigurationBuilder description(final String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fallback scenario configuration.
|
||||
*
|
||||
|
|
@ -182,9 +196,29 @@ public class ConfigurationBuilder {
|
|||
configuration.setDate(this.date);
|
||||
configuration.setName(this.name);
|
||||
configuration.setContentRepository(contentRepository);
|
||||
configuration.getAdditionalParameters().put(Keys.SCENARIO_DEFINITION, createDefinition(configuration));
|
||||
return (configuration);
|
||||
}
|
||||
|
||||
private Scenarios createDefinition(final DefaultConfiguration configuration) {
|
||||
final Scenarios s = new Scenarios();
|
||||
s.setAuthor(configuration.getAuthor());
|
||||
s.setDate(createTimestamp());
|
||||
final DescriptionType d = new DescriptionType();
|
||||
d.getPOrOlOrUl().add(new ObjectFactory().createDescriptionTypeP(StringUtils.defaultIfBlank(this.description, "")));
|
||||
s.setDescription(d);
|
||||
s.setName(configuration.getName());
|
||||
s.getScenario().addAll(configuration.getScenarios().stream().map(Scenario::getConfiguration).collect(Collectors.toList()));
|
||||
s.setNoScenarioReport(createNoScenarioReportType(configuration.getFallbackScenario()));
|
||||
return s;
|
||||
}
|
||||
|
||||
private static NoScenarioReportType createNoScenarioReportType(final Scenario fallbackScenario) {
|
||||
final NoScenarioReportType no = new NoScenarioReportType();
|
||||
no.setResource(fallbackScenario.getConfiguration().getCreateReport().getResource());
|
||||
return no;
|
||||
}
|
||||
|
||||
private Scenario initializeFallback(final ContentRepository contentRepository) {
|
||||
if (this.fallbackBuilder == null) {
|
||||
throw new IllegalStateException("No fallback configuration specified");
|
||||
|
|
|
|||
|
|
@ -129,6 +129,8 @@ public class ConfigurationLoader {
|
|||
configuration.setDate(def.getDate().toString());
|
||||
configuration.setName(def.getName());
|
||||
configuration.setContentRepository(contentRepository);
|
||||
configuration.getAdditionalParameters().put(Keys.SCENARIOS_FILE, this.scenarioDefinition);
|
||||
configuration.getAdditionalParameters().put(Keys.SCENARIO_DEFINITION, def);
|
||||
return (configuration);
|
||||
}
|
||||
|
||||
|
|
|
|||
20
src/main/java/de/kosit/validationtool/config/Keys.java
Normal file
20
src/main/java/de/kosit/validationtool/config/Keys.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package de.kosit.validationtool.config;
|
||||
|
||||
/**
|
||||
* Defines some keys used for supplying additional parameters internally.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class Keys {
|
||||
|
||||
/**
|
||||
* The actual scenarios file location as used with {@link ConfigurationLoader}.
|
||||
*/
|
||||
public static final String SCENARIOS_FILE = "scenarios_file";
|
||||
|
||||
/**
|
||||
* The actual scenarios configuration represented as serializable tree. This either loaded from file or build manually
|
||||
* via {@link ConfigurationBuilder}
|
||||
*/
|
||||
public static final String SCENARIO_DEFINITION = "scenario_definition";
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package de.kosit.validationtool.daemon;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
/**
|
||||
* Simple base implemenation for http handlers. Doing I/O stuff.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public abstract class BaseHandler implements HttpHandler {
|
||||
|
||||
protected static final String APPLICATION_XML = "application/xml";
|
||||
|
||||
protected static void write(final HttpExchange exchange, final byte[] content, final String contentType) throws IOException {
|
||||
final OutputStream os = exchange.getResponseBody();
|
||||
exchange.getResponseHeaders().add("Content-Type", contentType);
|
||||
exchange.sendResponseHeaders(200, content.length);
|
||||
os.write(content);
|
||||
os.close();
|
||||
}
|
||||
|
||||
protected static void error(final HttpExchange httpExchange, final int statusCode, final String message) throws IOException {
|
||||
final byte[] bytes = message.getBytes();
|
||||
httpExchange.sendResponseHeaders(statusCode, bytes.length);
|
||||
final OutputStream os = httpExchange.getResponseBody();
|
||||
os.write(bytes);
|
||||
os.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,32 +1,37 @@
|
|||
package de.kosit.validationtool.daemon;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Check;
|
||||
import de.kosit.validationtool.api.InputFactory;
|
||||
import de.kosit.validationtool.api.Result;
|
||||
import de.kosit.validationtool.impl.input.SourceInput;
|
||||
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.s9api.SaxonApiException;
|
||||
import net.sf.saxon.s9api.Serializer;
|
||||
|
||||
/**
|
||||
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird um hier die Verarbeitung des
|
||||
* POST Request zu realisieren.
|
||||
*/
|
||||
@Slf4j
|
||||
class HttpServerHandler implements HttpHandler {
|
||||
@RequiredArgsConstructor
|
||||
class CheckHandler extends BaseHandler {
|
||||
|
||||
private static final AtomicLong counter = new AtomicLong(0);
|
||||
|
||||
private final Check implemenation;
|
||||
|
||||
HttpServerHandler(final Check check) {
|
||||
this.implemenation = check;
|
||||
}
|
||||
private final Processor processor;
|
||||
|
||||
/**
|
||||
* Methode, die eine gegebene Anforderung verarbeitet und eine entsprechende Antwort generiert
|
||||
|
|
@ -41,20 +46,31 @@ class HttpServerHandler implements HttpHandler {
|
|||
final String requestMethod = httpExchange.getRequestMethod();
|
||||
if (requestMethod.equals("POST")) {
|
||||
final InputStream inputStream = httpExchange.getRequestBody();
|
||||
|
||||
if (inputStream.available() > 0) {
|
||||
final SourceInput serverInput = (SourceInput) InputFactory.read(inputStream, "Prüfling" + counter.incrementAndGet());
|
||||
Daemon.writeOutputstreamArray(httpExchange, this.implemenation.check(serverInput));
|
||||
final SourceInput serverInput = (SourceInput) InputFactory.read(inputStream,
|
||||
"supplied_instance_" + counter.incrementAndGet());
|
||||
final Result result = this.implemenation.checkInput(serverInput);
|
||||
write(httpExchange, serialize(result), APPLICATION_XML);
|
||||
} else {
|
||||
Daemon.writeError(httpExchange, 400, "XML-Inhalt erforderlich!");
|
||||
error(httpExchange, 400, "No content supplied");
|
||||
}
|
||||
|
||||
} else {
|
||||
Daemon.writeError(httpExchange, 405, "Es ist nur die POST-Methode erlaubt!");
|
||||
error(httpExchange, 405, "Method not supported");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
Daemon.writeError(httpExchange, 500, "Interner Fehler bei der Verarbeitung des Requests: " + e.getMessage());
|
||||
log.error("Es ist ein Fehler aufgetreten. Das Dokument kann nicht geprüft werden", e);
|
||||
error(httpExchange, 500, "Internal error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] serialize(final Result result) {
|
||||
try ( final ByteArrayOutputStream out = new ByteArrayOutputStream() ) {
|
||||
final Serializer serializer = this.processor.newSerializer(out);
|
||||
serializer.serializeNode(result.getReport());
|
||||
return out.toByteArray();
|
||||
} catch (final SaxonApiException | IOException e) {
|
||||
log.error("Error serializing result", e);
|
||||
throw new IllegalStateException("Can not serialize result", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package de.kosit.validationtool.daemon;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.config.Keys;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.model.scenarios.Scenarios;
|
||||
|
||||
/**
|
||||
* Handler that returns the actual configuration used for this daemon instance.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ConfigHandler extends BaseHandler {
|
||||
|
||||
private final Configuration configuration;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
@Override
|
||||
public void handle(final HttpExchange exchange) throws IOException {
|
||||
try {
|
||||
final Optional<String> xml = getSource();
|
||||
if (xml.isPresent()) {
|
||||
write(exchange, xml.get().getBytes(), APPLICATION_XML);
|
||||
} else {
|
||||
error(exchange, 404, "No configuration found");
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.error("Error grabbing configuration", e);
|
||||
error(exchange, 500, "Error grabbing configuration: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<String> getSource() {
|
||||
final URI fileUri = (URI) this.configuration.getAdditionalParameters().get(Keys.SCENARIOS_FILE);
|
||||
return fileUri != null ? loadFile(fileUri) : loadFromConfig();
|
||||
}
|
||||
|
||||
private static Optional<String> loadFile(final URI fileUri) {
|
||||
try ( final Reader in = new InputStreamReader(fileUri.toURL().openStream());
|
||||
final StringWriter out = new StringWriter() ) {
|
||||
IOUtils.copy(in, out);
|
||||
return Optional.of(out.toString());
|
||||
} catch (final IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<String> loadFromConfig() {
|
||||
final Optional<String> result;
|
||||
final Scenarios scenarios = (Scenarios) this.configuration.getAdditionalParameters().get(Keys.SCENARIO_DEFINITION);
|
||||
if (scenarios != null) {
|
||||
final String s = this.conversionService.writeXml(scenarios);
|
||||
result = Optional.of(s);
|
||||
} else {
|
||||
result = Optional.empty();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +1,9 @@
|
|||
package de.kosit.validationtool.daemon;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
import lombok.Getter;
|
||||
|
|
@ -22,8 +12,9 @@ import lombok.Setter;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.impl.DefaultCheck;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.model.daemon.HealthType;
|
||||
|
||||
/**
|
||||
* HTTP-Daemon für die Bereitstellung der Prüf-Funktionalität via http.
|
||||
|
|
@ -42,56 +33,6 @@ public class Daemon {
|
|||
|
||||
private final int threadCount;
|
||||
|
||||
/**
|
||||
* Methode, die die Antwort als String-Text schreibt
|
||||
*
|
||||
* @param httpExchange um den Antwort Body zu erhalten
|
||||
* @param rCode der Code-Status
|
||||
* @param response die String antwort, die ich anzeigen möchte
|
||||
*/
|
||||
static void writeError(final HttpExchange httpExchange, final int rCode, final String response) throws IOException {
|
||||
httpExchange.sendResponseHeaders(rCode, response.length());
|
||||
final OutputStream os = httpExchange.getResponseBody();
|
||||
os.write(response.getBytes());
|
||||
os.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode, die die Antwort als String-Text schreibt
|
||||
*
|
||||
* @param httpExchange um den Antwort Body zu erhalten
|
||||
* @param doc der Report
|
||||
*/
|
||||
static void writeOutputstreamArray(final HttpExchange httpExchange, final Document doc)
|
||||
throws IOException, TransformerException {
|
||||
final byte[] bytes = serialize(doc);
|
||||
final OutputStream os = httpExchange.getResponseBody();
|
||||
httpExchange.getResponseHeaders().add("Content-Type", "application/xml");
|
||||
httpExchange.sendResponseHeaders(200, bytes.length);
|
||||
os.write(bytes);
|
||||
os.close();
|
||||
log.debug("Xml File erzeugen ist Fertig ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode zum Serialisieren des Dokuments.
|
||||
*
|
||||
* @param report Vom Typ Dokument, aka Report .
|
||||
*/
|
||||
static byte[] serialize(final Document report) throws TransformerException {
|
||||
|
||||
try ( final ByteArrayOutputStream bArrayOS = new ByteArrayOutputStream() ) {
|
||||
final DOMSource source = new DOMSource(report);
|
||||
final StreamResult streamResult = new StreamResult(bArrayOS);
|
||||
final Transformer transformer = ObjectFactory.createTransformer(true);
|
||||
transformer.transform(source, streamResult);
|
||||
return bArrayOS.toByteArray();
|
||||
} catch (final IOException e) {
|
||||
log.error("Report {}", e.getMessage(), e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode zum Starten des Servers
|
||||
*
|
||||
|
|
@ -100,10 +41,14 @@ public class Daemon {
|
|||
public void startServer(final Configuration config) {
|
||||
HttpServer server = null;
|
||||
try {
|
||||
final ConversionService converter = new ConversionService();
|
||||
converter.initialize(HealthType.class.getPackage());
|
||||
|
||||
server = HttpServer.create(new InetSocketAddress(this.hostName, this.port), 0);
|
||||
final DefaultCheck check = new DefaultCheck(config);
|
||||
server.createContext("/", new HttpServerHandler(check));
|
||||
server.createContext("/health", new HealthHandler(config));
|
||||
server.createContext("/", new CheckHandler(check, config.getContentRepository().getProcessor()));
|
||||
server.createContext("/server/health", new HealthHandler(config, converter));
|
||||
server.createContext("/server/config", new ConfigHandler(config, new ConversionService()));
|
||||
server.setExecutor(Executors.newFixedThreadPool(this.threadCount));
|
||||
server.start();
|
||||
log.info("Server unter Port {} ist erfolgreich gestartet", this.port);
|
||||
|
|
|
|||
|
|
@ -2,140 +2,50 @@ package de.kosit.validationtool.daemon;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import de.kosit.validationtool.api.Configuration;
|
||||
import de.kosit.validationtool.impl.ObjectFactory;
|
||||
import de.kosit.validationtool.impl.ConversionService;
|
||||
import de.kosit.validationtool.model.daemon.HealthType;
|
||||
import de.kosit.validationtool.model.daemon.MemoryType;
|
||||
|
||||
/**
|
||||
* Wir benötigen einen Handler, der zur Verarbeitung von HTTP-Anforderungen aufgerufen wird , und hier für Verarbeitung
|
||||
* das GET Request um Health-Endpunkt zu erstellen. Die Klasse HealthHandler implementiert diese Schnittstelle
|
||||
* Handler that implements a simple health check. Useful for monitoring the service.
|
||||
*
|
||||
* @author Andreas Penski`
|
||||
*/
|
||||
@Slf4j
|
||||
class HealthHandler implements HttpHandler {
|
||||
@RequiredArgsConstructor
|
||||
class HealthHandler extends BaseHandler {
|
||||
|
||||
/**
|
||||
* Klasse zur Erzeugung Health Xml , die optiamle Status.
|
||||
*
|
||||
* @author Roula Antoun
|
||||
*/
|
||||
@Slf4j
|
||||
static class Health {
|
||||
|
||||
private final long freeMemory;
|
||||
|
||||
private final long maxMemory;
|
||||
|
||||
private final long totalMemory;
|
||||
|
||||
private final Configuration config;
|
||||
|
||||
Health(final Configuration config) {
|
||||
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
this.freeMemory = runtime.freeMemory();
|
||||
this.maxMemory = runtime.maxMemory();
|
||||
this.totalMemory = runtime.totalMemory();
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode, die schreibt das Health Xml für optimale Status
|
||||
*
|
||||
*/
|
||||
Document writeHealthXml() {
|
||||
final DocumentBuilder dBuilder = ObjectFactory.createDocumentBuilder(false);
|
||||
final Document doc = dBuilder.newDocument();
|
||||
final Element rootElement = doc.createElementNS("https://localhost:8080/Health", "Health");
|
||||
doc.appendChild(rootElement);
|
||||
rootElement.appendChild(getMemory(doc, this.freeMemory, this.maxMemory, this.totalMemory));
|
||||
rootElement.appendChild(getState(doc));
|
||||
rootElement.appendChild(getScenario(doc, this.config));
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode, die schreibt das System Status Node im Xml File
|
||||
*
|
||||
* @param doc Vom Typ Dokument.
|
||||
*
|
||||
*/
|
||||
private static Node getState(final Document doc) {
|
||||
final Element state = doc.createElement("state");
|
||||
state.setAttribute("indicator", "OK");
|
||||
final Element stateNode = doc.createElement("message");
|
||||
stateNode.appendChild(doc.createTextNode("System is up and running normally"));
|
||||
state.appendChild(stateNode);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode, die schreibt das Scnarios Information Node im Xml File
|
||||
*
|
||||
* @param doc Vom Typ Dokument .
|
||||
* @param config Vom Typ {@link Configuration} das verwendete scenario.
|
||||
*
|
||||
*/
|
||||
private static Node getScenario(final Document doc, final Configuration config) {
|
||||
final Element scenario = doc.createElement("scenario");
|
||||
final Element scenarioNameNode = doc.createElement("name");
|
||||
scenarioNameNode.appendChild(doc.createTextNode(config.getName()));
|
||||
scenario.appendChild(scenarioNameNode);
|
||||
return scenario;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methode, die schreibt das Scnarios Information Node im Xml File
|
||||
*
|
||||
* @param doc Vom Typ Dokument .
|
||||
* @param freeMemory Vom Typ long , der freier Speicher.
|
||||
* @param maxMemory Vom Typ long , der maximaler Speicher
|
||||
* @param totalMemory Vom Typ long , der Gesamte speicher.
|
||||
*
|
||||
*/
|
||||
private static Node getMemory(final Document doc, final long freeMemory, final long maxMemory, final long totalMemory) {
|
||||
final Element memory = doc.createElement("memoryState");
|
||||
final String freeM = Long.toString(freeMemory);
|
||||
final Element freeMNode = doc.createElement("freeMemory");
|
||||
freeMNode.appendChild(doc.createTextNode(freeM));
|
||||
memory.appendChild(freeMNode);
|
||||
final String maxM = Long.toString(maxMemory);
|
||||
final Element maxMNode = doc.createElement("maxMemory");
|
||||
maxMNode.appendChild(doc.createTextNode(maxM));
|
||||
memory.appendChild(maxMNode);
|
||||
final String totalM = Long.toString(totalMemory);
|
||||
final Element totalMNode = doc.createElement("totalMemory");
|
||||
totalMNode.appendChild(doc.createTextNode(totalM));
|
||||
memory.appendChild(totalMNode);
|
||||
return memory;
|
||||
}
|
||||
}
|
||||
|
||||
private final Configuration scenarios;
|
||||
|
||||
HealthHandler(final Configuration config) {
|
||||
this.scenarios = config;
|
||||
}
|
||||
private final ConversionService conversionService;
|
||||
|
||||
@Override
|
||||
public void handle(final HttpExchange httpExchange) throws IOException {
|
||||
final Health health = new Health(this.scenarios);
|
||||
final Document doc = health.writeHealthXml();
|
||||
try {
|
||||
Daemon.writeOutputstreamArray(httpExchange, doc);
|
||||
} catch (final TransformerException e) {
|
||||
Daemon.writeError(httpExchange, 500, e.getMessage());
|
||||
log.error("Fehler beim Erzeugen der Status-Information", e);
|
||||
final HealthType health = createHealth();
|
||||
final String xml = this.conversionService.writeXml(health);
|
||||
write(httpExchange, xml.getBytes(), APPLICATION_XML);
|
||||
|
||||
}
|
||||
|
||||
private static HealthType createHealth() {
|
||||
final HealthType h = new HealthType();
|
||||
h.setMemory(createMemory());
|
||||
return h;
|
||||
}
|
||||
|
||||
private static MemoryType createMemory() {
|
||||
final MemoryType m = new MemoryType();
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
m.setFreeMemory(runtime.freeMemory());
|
||||
m.setMaxMemory(runtime.maxMemory());
|
||||
m.setTotalMemory(runtime.totalMemory());
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
src/main/java/de/kosit/validationtool/impl/DateFactory.java
Normal file
25
src/main/java/de/kosit/validationtool/impl/DateFactory.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package de.kosit.validationtool.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class DateFactory {
|
||||
|
||||
public static XMLGregorianCalendar createTimestamp() {
|
||||
try {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(new Date());
|
||||
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
|
||||
|
||||
} catch (final DatatypeConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create timestamp", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,17 +19,13 @@
|
|||
|
||||
package de.kosit.validationtool.impl;
|
||||
|
||||
import static de.kosit.validationtool.impl.DateFactory.createTimestamp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
@ -103,16 +99,7 @@ public class DefaultCheck implements Check {
|
|||
return type;
|
||||
}
|
||||
|
||||
private static XMLGregorianCalendar createTimestamp() {
|
||||
try {
|
||||
final GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTime(new Date());
|
||||
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
|
||||
|
||||
} catch (final DatatypeConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create timestamp", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result checkInput(final Input input) {
|
||||
|
|
|
|||
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Koordinierungsstelle für IT-Standards (KoSIT) under
|
||||
* one or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. KoSIT licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package de.kosit.validationtool.impl;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.expr.XPathContext;
|
||||
import net.sf.saxon.lib.CollectionFinder;
|
||||
import net.sf.saxon.lib.FeatureKeys;
|
||||
import net.sf.saxon.lib.OutputURIResolver;
|
||||
import net.sf.saxon.lib.ResourceCollection;
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* Eine Factory für häufig verwendete Objekte mit XML. Zentralisiert die XML Security Konfiguration. Die Konfiguration
|
||||
* basiert auf den <a href="https://www.owasp.org/index.php/XML_Security_Cheat_Sheet">OWASP-Empfehlungen</a>.
|
||||
*
|
||||
* Diese Klasse ist stark abhängig von der Verwendung eines Oracle JDK. Alternative JDKs haben u.U. eine andere SAX- /
|
||||
* StAX- / XML-Implementierug und profitieren entsprechend NICHT von den hier getroffenen Einstellungen.
|
||||
*
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
public class ObjectFactory {
|
||||
|
||||
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||
|
||||
public static final String MESSAGE = "Configuration error. Resolving ist not allowed";
|
||||
|
||||
@Override
|
||||
public OutputURIResolver newInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result resolve(final String href, final String base) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(final Result result) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceCollection findCollection(final XPathContext context, final String collectionURI) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
}
|
||||
private static final String ORACLE_XERCES_CLASS = "com.sun.org.apache.xerces.internal.impl.Constants";
|
||||
private static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
private static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
private static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
private static Processor processor;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class.forName(ORACLE_XERCES_CLASS);
|
||||
} catch (final ClassNotFoundException e) {
|
||||
log.warn("No oracle JDK version of XERCES found. Configured security features may not have any effect.");
|
||||
log.warn("Please take care of XML security while checking your xml contents");
|
||||
}
|
||||
}
|
||||
|
||||
ObjectFactory() {
|
||||
// hide, it's a factory
|
||||
}
|
||||
|
||||
private static DocumentBuilderFactory createDocumentBuilderFactory(final boolean validating) {
|
||||
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
dbf.setValidating(validating);
|
||||
dbf.setNamespaceAware(true);
|
||||
|
||||
// explicitly enable secure processing
|
||||
dbf.setFeature(FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
|
||||
dbf.setFeature(DISSALLOW_DOCTYPE_DECL_FEATURE, true);
|
||||
|
||||
// Disable external DTDs as well
|
||||
dbf.setFeature(LOAD_EXTERNAL_DTD_FEATURE, false);
|
||||
|
||||
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
|
||||
dbf.setXIncludeAware(false);
|
||||
dbf.setExpandEntityReferences(false);
|
||||
return dbf;
|
||||
} catch (final ParserConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create DocumentBuilderFactory due to underlying configuration error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformer für die Ausgabe. Nutzt nicht Saxon!
|
||||
*
|
||||
* @param prettyPrint pretty-printing der Ausgabe
|
||||
* @return einen vorkonfigurierten Transformer
|
||||
*/
|
||||
public static Transformer createTransformer(final boolean prettyPrint) {
|
||||
Transformer transformer = null;
|
||||
try {
|
||||
final TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
// transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||
// transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); // Compliant
|
||||
transformer = transformerFactory.newTransformer();
|
||||
if (prettyPrint) {
|
||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
||||
|
||||
}
|
||||
return transformer;
|
||||
} catch (final TransformerConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create Transformer due to underlying configuration error", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static DocumentBuilder createDocumentBuilder(final boolean validating) {
|
||||
try {
|
||||
return createDocumentBuilderFactory(validating).newDocumentBuilder();
|
||||
} catch (final ParserConfigurationException e) {
|
||||
throw new IllegalStateException("Can not create DocumentFactory due to underlying configuration error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String encode(final String input) {
|
||||
try {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Error encoding property while initializing saxon", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Processor createProcessor() {
|
||||
if (processor == null) {
|
||||
processor = new Processor(false);
|
||||
//verhindere global im Prinzip alle resolving strategien
|
||||
final SecureUriResolver resolver = new SecureUriResolver();
|
||||
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
|
||||
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);
|
||||
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
|
||||
|
||||
//grundsätzlich Feature-konfiguration:
|
||||
processor.setConfigurationProperty(FeatureKeys.DTD_VALIDATION, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.ENTITY_RESOLVER_CLASS, "");
|
||||
processor.setConfigurationProperty(FeatureKeys.XINCLUDE, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, false);
|
||||
|
||||
// Konfiguration des zu verwendenden Parsers, wenn Saxon selbst einen erzeugen muss, bspw. beim XSL parsen
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(FEATURE_SECURE_PROCESSING), true);
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(DISSALLOW_DOCTYPE_DECL_FEATURE), true);
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);
|
||||
}
|
||||
return processor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -45,15 +45,18 @@
|
|||
</jaxb:bindings>
|
||||
<jaxb:bindings schemaLocation="../xsd/assertions.xsd">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:package name="de.kosit.validationtool.cmd.assertions"/>
|
||||
<jaxb:package name="de.kosit.validationtool.cmd.assertions" />
|
||||
</jaxb:schemaBindings>
|
||||
</jaxb:bindings>
|
||||
|
||||
<jaxb:bindings schemaLocation="../xsd/svrl-kosit.xsd">
|
||||
|
||||
<jaxb:bindings node="//xs:element[@name='schematron-output']/xs:complexType">
|
||||
<inheritance:extends>de.kosit.validationtool.impl.model.BaseOutput</inheritance:extends>
|
||||
</jaxb:bindings>
|
||||
</jaxb:bindings>
|
||||
<jaxb:bindings schemaLocation="../xsd/daemon.xsd">
|
||||
<jaxb:schemaBindings>
|
||||
<jaxb:package name="de.kosit.validationtool.model.daemon" />
|
||||
</jaxb:schemaBindings>
|
||||
</jaxb:bindings>
|
||||
|
||||
</jaxb:bindings>
|
||||
42
src/main/model/xsd/daemon.xsd
Normal file
42
src/main/model/xsd/daemon.xsd
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schema xmlns:d="http://www.xoev.de/de/validator/framework/1/daemon" targetNamespace="http://www.xoev.de/de/validator/framework/1/daemon"
|
||||
elementFormDefault="qualified"
|
||||
xmlns="http://www.w3.org/2001/XMLSchema" version="1.0.0">
|
||||
|
||||
<element name="health" type="d:HealthType"></element>
|
||||
|
||||
<complexType name="ApplicationType">
|
||||
<sequence>
|
||||
<element name="name" type="string"></element>
|
||||
<element name="version" type="string"></element>
|
||||
<element name="build" type="string"></element>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="HealthType">
|
||||
<sequence>
|
||||
<element name="status">
|
||||
|
||||
<simpleType>
|
||||
<restriction base="string">
|
||||
<enumeration value="UP"></enumeration>
|
||||
<enumeration value="DOWN"></enumeration>
|
||||
<enumeration value="WARN"></enumeration>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
</element>
|
||||
<element name="application" type="d:ApplicationType"></element>
|
||||
|
||||
<element name="memory" type="d:MemoryType"></element>
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
|
||||
<complexType name="MemoryType">
|
||||
<sequence>
|
||||
<element name="freeMemory" type="long"></element>
|
||||
<element name="maxMemory" type="long"></element>
|
||||
<element name="totalMemory" type="long"></element>
|
||||
</sequence>
|
||||
</complexType>
|
||||
</schema>
|
||||
|
|
@ -28,23 +28,17 @@ import java.net.URISyntaxException;
|
|||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import de.kosit.validationtool.api.Input;
|
||||
import de.kosit.validationtool.api.ResolvingConfigurationStrategy;
|
||||
import de.kosit.validationtool.impl.model.Result;
|
||||
import de.kosit.validationtool.impl.tasks.DocumentParseAction;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
|
||||
import net.sf.saxon.dom.NodeOverNodeInfo;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.s9api.SaxonApiException;
|
||||
import net.sf.saxon.s9api.Serializer;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
|
||||
/**
|
||||
|
|
@ -148,20 +142,17 @@ public class Helper {
|
|||
new File("src/test/resources/examples/repository").toURI());
|
||||
}
|
||||
|
||||
public static String serialize(final Document doc) {
|
||||
public static String serialize(final XdmNode node) {
|
||||
try ( final StringWriter writer = new StringWriter() ) {
|
||||
final Transformer transformer = TestObjectFactory.createTransformer(true);
|
||||
transformer.transform(new DOMSource(doc), new StreamResult(writer));
|
||||
final Processor processor = Helper.getTestProcessor();
|
||||
final Serializer serializer = processor.newSerializer(writer);
|
||||
serializer.serializeNode(node);
|
||||
return writer.toString();
|
||||
} catch (final IOException | TransformerException e) {
|
||||
} catch (final SaxonApiException | IOException e) {
|
||||
throw new IllegalStateException("Can not serialize document", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String serialize(final XdmNode node) {
|
||||
return serialize((Document) NodeOverNodeInfo.wrap(node.getUnderlyingNode()));
|
||||
}
|
||||
|
||||
public static Result<XdmNode, XMLSyntaxError> parseDocument(final Processor processor, final Input input) {
|
||||
return new DocumentParseAction(processor).parseDocument(input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,11 @@ import java.io.IOException;
|
|||
import java.net.URL;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
@ -41,9 +40,9 @@ import de.kosit.validationtool.impl.model.Result;
|
|||
import de.kosit.validationtool.impl.xml.RelativeUriResolver;
|
||||
import de.kosit.validationtool.model.reportInput.XMLSyntaxError;
|
||||
|
||||
import net.sf.saxon.s9api.DOMDestination;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.s9api.SaxonApiException;
|
||||
import net.sf.saxon.s9api.XdmDestination;
|
||||
import net.sf.saxon.s9api.XdmNode;
|
||||
import net.sf.saxon.s9api.XsltCompiler;
|
||||
import net.sf.saxon.s9api.XsltExecutable;
|
||||
|
|
@ -67,19 +66,18 @@ public class SaxonSecurityTest {
|
|||
final XsltCompiler compiler = p.newXsltCompiler();
|
||||
final RelativeUriResolver resolver = new RelativeUriResolver(Simple.REPOSITORY_URI);
|
||||
compiler.setURIResolver(resolver);
|
||||
final XsltExecutable exetuable = compiler.compile(new StreamSource(resource.openStream()));
|
||||
final XsltTransformer transformer = exetuable.load();
|
||||
final Document document = TestObjectFactory.createDocumentBuilder(false).newDocument();
|
||||
document.createElement("root");
|
||||
final Document result = TestObjectFactory.createDocumentBuilder(false).newDocument();
|
||||
final XsltExecutable executable = compiler.compile(new StreamSource(resource.openStream()));
|
||||
final XsltTransformer transformer = executable.load();
|
||||
final Source document = InputFactory.read("<root/>".getBytes(), "dummy").getSource();
|
||||
// transformer.getUnderlyingController().setUnparsedTextURIResolver(resolver);
|
||||
transformer.setURIResolver(resolver);
|
||||
transformer.setSource(new DOMSource(document));
|
||||
transformer.setDestination(new DOMDestination(result));
|
||||
transformer.setSource(document);
|
||||
final XdmDestination result = new XdmDestination();
|
||||
transformer.setDestination(result);
|
||||
transformer.transform();
|
||||
|
||||
// wenn der Punkt erreicht wird, sollte wenigstens, das Element evil nicht mit 'bösen' Inhalten gefüllt sein!
|
||||
if (StringUtils.isNotBlank(result.getDocumentElement().getTextContent())) {
|
||||
if (StringUtils.isNotBlank(result.getXdmNode().getStringValue())) {
|
||||
fail(String.format("Saxon configuration should prevent expansion within %s", resource));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,95 @@
|
|||
package de.kosit.validationtool.impl;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import net.sf.saxon.Configuration;
|
||||
import net.sf.saxon.expr.XPathContext;
|
||||
import net.sf.saxon.lib.CollectionFinder;
|
||||
import net.sf.saxon.lib.FeatureKeys;
|
||||
import net.sf.saxon.lib.OutputURIResolver;
|
||||
import net.sf.saxon.lib.ResourceCollection;
|
||||
import net.sf.saxon.lib.UnparsedTextURIResolver;
|
||||
import net.sf.saxon.s9api.Processor;
|
||||
import net.sf.saxon.trans.XPathException;
|
||||
|
||||
/**
|
||||
* @author Andreas Penski
|
||||
*/
|
||||
public class TestObjectFactory extends ObjectFactory {
|
||||
public class TestObjectFactory {
|
||||
|
||||
private static class SecureUriResolver implements CollectionFinder, OutputURIResolver, UnparsedTextURIResolver {
|
||||
|
||||
public static final String MESSAGE = "Configuration error. Resolving ist not allowed";
|
||||
|
||||
@Override
|
||||
public OutputURIResolver newInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result resolve(final String href, final String base) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(final Result result) throws TransformerException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader resolve(final URI absoluteURI, final String encoding, final Configuration config) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceCollection findCollection(final XPathContext context, final String collectionURI) throws XPathException {
|
||||
throw new IllegalStateException(MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DISSALLOW_DOCTYPE_DECL_FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
|
||||
private static final String LOAD_EXTERNAL_DTD_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
|
||||
private static final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
|
||||
private static Processor processor;
|
||||
|
||||
private static String encode(final String input) {
|
||||
try {
|
||||
return URLEncoder.encode(input, StandardCharsets.UTF_8.name());
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException("Error encoding property while initializing saxon", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Processor createProcessor() {
|
||||
if (processor == null) {
|
||||
processor = new Processor(false);
|
||||
// verhindere global im Prinzip alle resolving strategien
|
||||
final SecureUriResolver resolver = new SecureUriResolver();
|
||||
processor.getUnderlyingConfiguration().setCollectionFinder(resolver);
|
||||
processor.getUnderlyingConfiguration().setOutputURIResolver(resolver);
|
||||
processor.getUnderlyingConfiguration().setUnparsedTextURIResolver(resolver);
|
||||
|
||||
// grundsätzlich Feature-konfiguration:
|
||||
processor.setConfigurationProperty(FeatureKeys.DTD_VALIDATION, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.ENTITY_RESOLVER_CLASS, "");
|
||||
processor.setConfigurationProperty(FeatureKeys.XINCLUDE, false);
|
||||
processor.setConfigurationProperty(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, false);
|
||||
|
||||
// Konfiguration des zu verwendenden Parsers, wenn Saxon selbst einen erzeugen muss, bspw. beim XSL parsen
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(FEATURE_SECURE_PROCESSING), true);
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(DISSALLOW_DOCTYPE_DECL_FEATURE), true);
|
||||
processor.setConfigurationProperty(FeatureKeys.XML_PARSER_FEATURE + encode(LOAD_EXTERNAL_DTD_FEATURE), false);
|
||||
}
|
||||
return processor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue