diff --git a/checkstyle-filter.xml b/checkstyle-filter.xml index 51488db3..686f51a6 100644 --- a/checkstyle-filter.xml +++ b/checkstyle-filter.xml @@ -199,4 +199,7 @@ + + diff --git a/com.io7m.idstore.documentation/src/main/resources/com/io7m/idstore/documentation/configuration.xml b/com.io7m.idstore.documentation/src/main/resources/com/io7m/idstore/documentation/configuration.xml index 531ec781..fe3439ed 100644 --- a/com.io7m.idstore.documentation/src/main/resources/com/io7m/idstore/documentation/configuration.xml +++ b/com.io7m.idstore.documentation/src/main/resources/com/io7m/idstore/documentation/configuration.xml @@ -30,42 +30,60 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + ]]> @@ -131,11 +149,7 @@ The ListenAddress and ListenPort attributes specify the address and port to which to the HTTP - service will bind. It is recommended that the service be bound to - localhost - and a reverse proxy such as nginx be used to - provide TLS - . + service will bind. The ExternalAddress attribute specifies the external address that clients will @@ -145,6 +159,15 @@ By convention, the Admin API should listen on TCP port 51000. + + The HTTPServiceAdminAPI element must contain either a + TLSEnabled or TLSDisabled element specifying + whether TLS should be enabled or disabled, respectively. The TLSEnabled + element describes the key store and trust store. The idstore server + automatically reloads certificates periodically in order to work well in environments using the + ACME protocol to + issue certificates. + @@ -153,11 +176,7 @@ The ListenAddress and ListenPort attributes specify the address and port to which to the HTTP - service will bind. It is recommended that the service be bound to - localhost - and a reverse proxy such as nginx be used to - provide TLS - . + service will bind. The ExternalAddress attribute specifies the external address that clients will @@ -167,6 +186,15 @@ By convention, the User API should listen on TCP port 50000. + + The HTTPServiceUserAPI element must contain either a + TLSEnabled or TLSDisabled element specifying + whether TLS should be enabled or disabled, respectively. The TLSEnabled + element describes the key store and trust store. The idstore server + automatically reloads certificates periodically in order to work well in environments using the + ACME protocol to + issue certificates. + @@ -175,11 +203,7 @@ The ListenAddress and ListenPort attributes specify the address and port to which to the HTTP - service will bind. It is recommended that the service be bound to - localhost - and a reverse proxy such as nginx be used to - provide TLS - . + service will bind. The ExternalAddress attribute specifies the external address that clients will @@ -189,6 +213,15 @@ By convention, the User API should listen on TCP port 50001. + + The HTTPServiceUserView element must contain either a + TLSEnabled or TLSDisabled element specifying + whether TLS should be enabled or disabled, respectively. The TLSEnabled + element describes the key store and trust store. The idstore server + automatically reloads certificates periodically in order to work well in environments using the + ACME protocol to + issue certificates. + @@ -199,13 +232,28 @@ + ExternalURI="http://localhost:51000/"> + + + + + + ExternalURI="http://localhost:50000/"> + + + ExternalURI="http://localhost:50001/"> + + ]]> @@ -646,21 +694,18 @@ The XSD schema for the configuration file is as follows: - + - + + + + + - - Note: It is extremely important that any reverse proxy used provides the correct - RFC 7239 - headers in order to tell the idstore server that a reverse proxy is present. - Otherwise, the idstore server will apply - rate-limiting decisions to the address of the proxy - as opposed to the address of the user connecting through the proxy, as intended. - - diff --git a/com.io7m.idstore.main/pom.xml b/com.io7m.idstore.main/pom.xml index 6e8ee745..6e4378fc 100644 --- a/com.io7m.idstore.main/pom.xml +++ b/com.io7m.idstore.main/pom.xml @@ -75,6 +75,14 @@ ch.qos.logback logback-classic + + com.io7m.anethum + com.io7m.anethum.slf4j + + + com.io7m.anethum + com.io7m.anethum.api + org.osgi diff --git a/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdInitialAdmin.java b/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdInitialAdmin.java index 5d2138ac..2ee376cf 100644 --- a/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdInitialAdmin.java +++ b/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdInitialAdmin.java @@ -16,12 +16,13 @@ package com.io7m.idstore.main.internal; +import com.io7m.anethum.slf4j.ParseStatusLogging; import com.io7m.idstore.model.IdEmail; import com.io7m.idstore.model.IdName; import com.io7m.idstore.model.IdRealName; import com.io7m.idstore.server.api.IdServerConfigurations; import com.io7m.idstore.server.api.IdServerFactoryType; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.quarrel.core.QCommandContextType; import com.io7m.quarrel.core.QCommandMetadata; import com.io7m.quarrel.core.QCommandStatus; @@ -30,6 +31,8 @@ import com.io7m.quarrel.core.QParameterNamedType; import com.io7m.quarrel.core.QStringType.QConstant; import com.io7m.quarrel.ext.logback.QLogback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import java.nio.file.Path; @@ -49,6 +52,9 @@ public final class IdMCmdInitialAdmin implements QCommandType { + private static final Logger LOG = + LoggerFactory.getLogger(IdMCmdInitialAdmin.class); + private static final QParameterNamed1 CONFIGURATION_FILE = new QParameterNamed1<>( "--configuration", @@ -157,9 +163,13 @@ public QCommandStatus onExecute( final var configurationFile = context.parameterValue(CONFIGURATION_FILE); + final var parsers = + new IdServerConfigurationParsers(); final var configFile = - new IdServerConfigurationFiles() - .parse(configurationFile); + parsers.parseFile( + configurationFile, + status -> ParseStatusLogging.logWithAll(LOG, status) + ); final var configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdServer.java b/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdServer.java index eb6e5d0e..bcf6f45f 100644 --- a/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdServer.java +++ b/com.io7m.idstore.main/src/main/java/com/io7m/idstore/main/internal/IdMCmdServer.java @@ -16,9 +16,10 @@ package com.io7m.idstore.main.internal; +import com.io7m.anethum.slf4j.ParseStatusLogging; import com.io7m.idstore.server.api.IdServerConfigurations; import com.io7m.idstore.server.api.IdServerFactoryType; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.quarrel.core.QCommandContextType; import com.io7m.quarrel.core.QCommandMetadata; import com.io7m.quarrel.core.QCommandStatus; @@ -27,6 +28,8 @@ import com.io7m.quarrel.core.QParameterNamedType; import com.io7m.quarrel.core.QStringType; import com.io7m.quarrel.ext.logback.QLogback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.slf4j.bridge.SLF4JBridgeHandler; import java.nio.file.Path; @@ -45,6 +48,9 @@ public final class IdMCmdServer implements QCommandType { + private static final Logger LOG = + LoggerFactory.getLogger(IdMCmdServer.class); + private static final QParameterNamed1 CONFIGURATION_FILE = new QParameterNamed1<>( "--configuration", @@ -98,9 +104,16 @@ public QCommandStatus onExecute( QLogback.configure(context); + final var configurationFile = + context.parameterValue(CONFIGURATION_FILE); + + final var parsers = + new IdServerConfigurationParsers(); final var configFile = - new IdServerConfigurationFiles() - .parse(context.parameterValue(CONFIGURATION_FILE)); + parsers.parseFile( + configurationFile, + status -> ParseStatusLogging.logWithAll(LOG, status) + ); final var configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.main/src/main/java/module-info.java b/com.io7m.idstore.main/src/main/java/module-info.java index 059182bb..1358f21f 100644 --- a/com.io7m.idstore.main/src/main/java/module-info.java +++ b/com.io7m.idstore.main/src/main/java/module-info.java @@ -56,6 +56,8 @@ requires com.io7m.idstore.shell.admin; requires com.io7m.idstore.strings; + requires com.io7m.anethum.api; + requires com.io7m.anethum.slf4j; requires com.io7m.quarrel.core; requires com.io7m.quarrel.ext.logback; requires com.io7m.repetoir.core; diff --git a/com.io7m.idstore.server.admin_v1/pom.xml b/com.io7m.idstore.server.admin_v1/pom.xml index 22b2f2f8..27606727 100644 --- a/com.io7m.idstore.server.admin_v1/pom.xml +++ b/com.io7m.idstore.server.admin_v1/pom.xml @@ -86,6 +86,11 @@ com.io7m.idstore.server.service.health ${project.version} + + ${project.groupId} + com.io7m.idstore.server.service.tls + ${project.version} + ${project.groupId} com.io7m.idstore.model @@ -111,6 +116,11 @@ com.io7m.idstore.strings ${project.version} + + ${project.groupId} + com.io7m.idstore.tls + ${project.version} + com.io7m.jxtrand @@ -136,6 +146,10 @@ io.helidon.common helidon-common-parameters + + io.helidon.common + helidon-common-tls + org.slf4j slf4j-api diff --git a/com.io7m.idstore.server.admin_v1/src/main/java/com/io7m/idstore/server/admin_v1/IdA1Server.java b/com.io7m.idstore.server.admin_v1/src/main/java/com/io7m/idstore/server/admin_v1/IdA1Server.java index 9e25c1f7..fd383889 100644 --- a/com.io7m.idstore.server.admin_v1/src/main/java/com/io7m/idstore/server/admin_v1/IdA1Server.java +++ b/com.io7m.idstore.server.admin_v1/src/main/java/com/io7m/idstore/server/admin_v1/IdA1Server.java @@ -22,7 +22,10 @@ import com.io7m.idstore.server.service.clock.IdServerClock; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.telemetry.api.IdMetricsServiceType; +import com.io7m.idstore.server.service.tls.IdTLSContextServiceType; +import com.io7m.idstore.tls.IdTLSEnabled; import com.io7m.repetoir.core.RPServiceDirectoryType; +import io.helidon.common.tls.TlsConfig; import io.helidon.webserver.WebServer; import io.helidon.webserver.WebServerConfig; import io.helidon.webserver.http.HttpRouting; @@ -67,6 +70,8 @@ public static WebServer createAdminAPIServer( { final var configurationService = services.requireService(IdServerConfigurationService.class); + final var tlsService = + services.requireService(IdTLSContextServiceType.class); final var configuration = configurationService.configuration(); final var httpConfig = @@ -94,8 +99,27 @@ public static WebServer createAdminAPIServer( new IdA1HandlerHealth(services)) .build(); + final var webServerBuilder = + WebServerConfig.builder(); + + if (httpConfig.tlsConfiguration() instanceof final IdTLSEnabled enabled) { + final var tlsContext = + tlsService.create( + "UserAPI", + enabled.keyStore(), + enabled.trustStore() + ); + + webServerBuilder.tls( + TlsConfig.builder() + .enabled(true) + .sslContext(tlsContext.context()) + .build() + ); + } + final var webServer = - WebServerConfig.builder() + webServerBuilder .port(httpConfig.listenPort()) .address(InetAddress.getByName(httpConfig.listenAddress())) .routing(routing) diff --git a/com.io7m.idstore.server.admin_v1/src/main/java/module-info.java b/com.io7m.idstore.server.admin_v1/src/main/java/module-info.java index 6d3b140f..5af7f05e 100644 --- a/com.io7m.idstore.server.admin_v1/src/main/java/module-info.java +++ b/com.io7m.idstore.server.admin_v1/src/main/java/module-info.java @@ -39,8 +39,10 @@ requires com.io7m.idstore.server.service.reqlimit; requires com.io7m.idstore.server.service.sessions; requires com.io7m.idstore.server.service.telemetry.api; + requires com.io7m.idstore.server.service.tls; requires com.io7m.idstore.server.service.verdant; requires com.io7m.idstore.strings; + requires com.io7m.idstore.tls; requires com.io7m.verdant.core; requires io.helidon.webserver; diff --git a/com.io7m.idstore.server.api/pom.xml b/com.io7m.idstore.server.api/pom.xml index 797e0118..570a4d85 100644 --- a/com.io7m.idstore.server.api/pom.xml +++ b/com.io7m.idstore.server.api/pom.xml @@ -39,6 +39,11 @@ com.io7m.idstore.strings ${project.version} + + ${project.groupId} + com.io7m.idstore.tls + ${project.version} + com.io7m.cxbutton diff --git a/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdColor.java b/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdColor.java index fb5794ed..53bfa0e9 100644 --- a/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdColor.java +++ b/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdColor.java @@ -64,6 +64,25 @@ public String toString() ); } + @Override + public boolean equals(final Object o) + { + if (this == o) { + return true; + } + if (o == null || !this.getClass().equals(o.getClass())) { + return false; + } + final IdColor idColor = (IdColor) o; + return this.toString().equals(idColor.toString()); + } + + @Override + public int hashCode() + { + return this.toString().hashCode(); + } + /** * Scale this color by the given factor. Factors less than 1.0 make the color * darker. Factors greater than 1.0 make the color lighter. diff --git a/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdServerHTTPServiceConfiguration.java b/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdServerHTTPServiceConfiguration.java index 09d98001..52990969 100644 --- a/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdServerHTTPServiceConfiguration.java +++ b/com.io7m.idstore.server.api/src/main/java/com/io7m/idstore/server/api/IdServerHTTPServiceConfiguration.java @@ -16,34 +16,40 @@ package com.io7m.idstore.server.api; +import com.io7m.idstore.tls.IdTLSConfigurationType; + import java.net.URI; import java.util.Objects; /** * Configuration for individual HTTP services. * - * @param listenAddress The listen address - * @param listenPort The listen port - * @param externalAddress The externally visible address + * @param listenAddress The listen address + * @param listenPort The listen port + * @param externalAddress The externally visible address + * @param tlsConfiguration The TLS configuration */ public record IdServerHTTPServiceConfiguration( String listenAddress, int listenPort, - URI externalAddress) + URI externalAddress, + IdTLSConfigurationType tlsConfiguration) implements IdServerJSONConfigurationElementType { /** * Configuration for the part of the server that serves over HTTP. * - * @param listenAddress The listen address - * @param listenPort The listen port - * @param externalAddress The externally visible address + * @param listenAddress The listen address + * @param listenPort The listen port + * @param externalAddress The externally visible address + * @param tlsConfiguration The TLS configuration */ public IdServerHTTPServiceConfiguration { Objects.requireNonNull(listenAddress, "listenAddress"); Objects.requireNonNull(externalAddress, "externalAddress"); + Objects.requireNonNull(tlsConfiguration, "tlsConfiguration"); } } diff --git a/com.io7m.idstore.server.api/src/main/java/module-info.java b/com.io7m.idstore.server.api/src/main/java/module-info.java index a5243cd9..9e5a9728 100644 --- a/com.io7m.idstore.server.api/src/main/java/module-info.java +++ b/com.io7m.idstore.server.api/src/main/java/module-info.java @@ -24,8 +24,9 @@ requires static org.osgi.annotation.versioning; requires com.io7m.idstore.database.api; - requires com.io7m.idstore.strings; requires com.io7m.idstore.model; + requires com.io7m.idstore.strings; + requires com.io7m.idstore.tls; requires com.io7m.cxbutton.core; diff --git a/com.io7m.idstore.server.service.configuration/pom.xml b/com.io7m.idstore.server.service.configuration/pom.xml index b2960c00..1b80ec28 100644 --- a/com.io7m.idstore.server.service.configuration/pom.xml +++ b/com.io7m.idstore.server.service.configuration/pom.xml @@ -31,31 +31,42 @@ ${project.groupId} - com.io7m.idstore.database.api + com.io7m.idstore.server.service.telemetry.api ${project.version} ${project.groupId} - com.io7m.idstore.server.service.telemetry.api + com.io7m.idstore.tls ${project.version} - com.io7m.repetoir - com.io7m.repetoir.core + com.io7m.jxe + com.io7m.jxe.core - com.io7m.cxbutton - com.io7m.cxbutton.core + com.io7m.jlexing + com.io7m.jlexing.core - - jakarta.xml.bind - jakarta.xml.bind-api + com.io7m.anethum + com.io7m.anethum.api - com.sun.xml.bind - jaxb-impl + com.io7m.blackthorne + com.io7m.blackthorne.core + + + com.io7m.blackthorne + com.io7m.blackthorne.jxe + + + com.io7m.repetoir + com.io7m.repetoir.core + + + com.io7m.cxbutton + com.io7m.cxbutton.core @@ -70,40 +81,4 @@ - - - - - org.apache.maven.plugins - maven-dependency-plugin - - true - - com.sun.xml.bind:jaxb-impl:* - - - - - - org.codehaus.mojo - jaxb2-maven-plugin - - - generate-java - generate-sources - - xjc - - - com.io7m.idstore.server.service.configuration.jaxb - - src/main/resources/com/io7m/idstore/server/service/configuration/configuration.xsd - - - - - - - - diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationFiles.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationFiles.java deleted file mode 100644 index 9a813b3a..00000000 --- a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationFiles.java +++ /dev/null @@ -1,976 +0,0 @@ -/* - * Copyright © 2023 Mark Raynsford https://www.io7m.com - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR - * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -package com.io7m.idstore.server.service.configuration; - -import com.io7m.cxbutton.core.CxButtonColors; -import com.io7m.cxbutton.core.CxButtonStateColors; -import com.io7m.cxbutton.core.CxColor; -import com.io7m.idstore.database.api.IdDatabaseConfiguration; -import com.io7m.idstore.database.api.IdDatabaseCreate; -import com.io7m.idstore.database.api.IdDatabaseUpgrade; -import com.io7m.idstore.server.api.IdColor; -import com.io7m.idstore.server.api.IdServerBrandingConfiguration; -import com.io7m.idstore.server.api.IdServerColorScheme; -import com.io7m.idstore.server.api.IdServerConfiguration; -import com.io7m.idstore.server.api.IdServerConfigurationFile; -import com.io7m.idstore.server.api.IdServerDatabaseConfiguration; -import com.io7m.idstore.server.api.IdServerDatabaseKind; -import com.io7m.idstore.server.api.IdServerHTTPConfiguration; -import com.io7m.idstore.server.api.IdServerHTTPServiceConfiguration; -import com.io7m.idstore.server.api.IdServerHistoryConfiguration; -import com.io7m.idstore.server.api.IdServerMailAuthenticationConfiguration; -import com.io7m.idstore.server.api.IdServerMailConfiguration; -import com.io7m.idstore.server.api.IdServerMailTransportConfigurationType; -import com.io7m.idstore.server.api.IdServerMailTransportSMTP; -import com.io7m.idstore.server.api.IdServerMailTransportSMTPS; -import com.io7m.idstore.server.api.IdServerMailTransportSMTP_TLS; -import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration; -import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdLogs; -import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdMetrics; -import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdOTLPProtocol; -import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdTraces; -import com.io7m.idstore.server.api.IdServerPasswordExpirationConfiguration; -import com.io7m.idstore.server.api.IdServerRateLimitConfiguration; -import com.io7m.idstore.server.api.IdServerSessionConfiguration; -import com.io7m.idstore.server.service.configuration.jaxb.Branding; -import com.io7m.idstore.server.service.configuration.jaxb.ButtonColors; -import com.io7m.idstore.server.service.configuration.jaxb.ButtonStateColors; -import com.io7m.idstore.server.service.configuration.jaxb.ColorScheme; -import com.io7m.idstore.server.service.configuration.jaxb.ColorType; -import com.io7m.idstore.server.service.configuration.jaxb.Configuration; -import com.io7m.idstore.server.service.configuration.jaxb.Database; -import com.io7m.idstore.server.service.configuration.jaxb.HTTPServiceType; -import com.io7m.idstore.server.service.configuration.jaxb.HTTPServices; -import com.io7m.idstore.server.service.configuration.jaxb.History; -import com.io7m.idstore.server.service.configuration.jaxb.Logs; -import com.io7m.idstore.server.service.configuration.jaxb.Mail; -import com.io7m.idstore.server.service.configuration.jaxb.MailAuthentication; -import com.io7m.idstore.server.service.configuration.jaxb.Metrics; -import com.io7m.idstore.server.service.configuration.jaxb.OpenTelemetry; -import com.io7m.idstore.server.service.configuration.jaxb.OpenTelemetryProtocol; -import com.io7m.idstore.server.service.configuration.jaxb.PasswordExpiration; -import com.io7m.idstore.server.service.configuration.jaxb.RateLimiting; -import com.io7m.idstore.server.service.configuration.jaxb.SMTPSType; -import com.io7m.idstore.server.service.configuration.jaxb.SMTPTLSType; -import com.io7m.idstore.server.service.configuration.jaxb.SMTPType; -import com.io7m.idstore.server.service.configuration.jaxb.Sessions; -import com.io7m.idstore.server.service.configuration.jaxb.Traces; -import com.io7m.repetoir.core.RPServiceType; -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.JAXBException; -import org.xml.sax.SAXException; - -import javax.xml.XMLConstants; -import javax.xml.datatype.DatatypeFactory; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; - -import static com.io7m.idstore.server.api.IdServerDatabaseKind.POSTGRESQL; - -/** - * The configuration file parser. - */ - -public final class IdServerConfigurationFiles - implements RPServiceType -{ - /** - * The Public API v1 message protocol. - */ - - public IdServerConfigurationFiles() - { - - } - - /** - * Parse a configuration file. - * - * @param source The source URI - * @param stream The input stream - * - * @return The file - * - * @throws IOException On errors - */ - - public IdServerConfigurationFile parse( - final URI source, - final InputStream stream) - throws IOException - { - Objects.requireNonNull(source, "source"); - Objects.requireNonNull(stream, "stream"); - - try { - final Schema schema = - createSchema(); - final var context = - JAXBContext.newInstance( - "com.io7m.idstore.server.service.configuration.jaxb"); - final var unmarshaller = - context.createUnmarshaller(); - - unmarshaller.setSchema(schema); - - final var streamSource = - new StreamSource(stream, source.toString()); - - return parseConfiguration( - (Configuration) unmarshaller.unmarshal(streamSource) - ); - } catch (final SAXException | JAXBException | URISyntaxException e) { - throw new IOException(e); - } - } - - private static Schema createSchema() - throws SAXException - { - final var schemas = - SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - return schemas.newSchema( - IdServerConfigurationFiles.class.getResource( - "/com/io7m/idstore/server/service/configuration/configuration.xsd") - ); - } - - /** - * Serialize a configuration file. - * - * @param output The output stream - * @param configuration The configuration - * - * @throws IOException On errors - */ - - public void serialize( - final OutputStream output, - final IdServerConfiguration configuration) - throws IOException - { - Objects.requireNonNull(output, "output"); - Objects.requireNonNull(configuration, "configuration"); - - try { - final Schema schema = - createSchema(); - - final var context = - JAXBContext.newInstance( - "com.io7m.idstore.server.service.configuration.jaxb"); - final var marshaller = - context.createMarshaller(); - final var types = - DatatypeFactory.newInstance(); - - marshaller.setSchema(schema); - marshaller.marshal(serializeConfiguration(types, configuration), output); - } catch (final Exception e) { - throw new IOException(e); - } - } - - private static Configuration serializeConfiguration( - final DatatypeFactory types, - final IdServerConfiguration configuration) - { - final var c = new Configuration(); - c.setBranding( - serializeBranding(configuration.branding())); - c.setMail( - serializeMail(types, configuration.mailConfiguration())); - c.setHTTPServices( - serializeHTTP( - configuration.adminApiAddress(), - configuration.userApiAddress(), - configuration.userViewAddress()) - ); - c.setDatabase( - serializeDatabase(configuration.databaseConfiguration())); - c.setHistory( - serializeHistory(configuration.history())); - c.setSessions( - serializeSessions(types, configuration.sessions())); - c.setRateLimiting( - serializeRateLimiting(types, configuration.rateLimit())); - c.setPasswordExpiration( - serializePasswordExpiration(types, configuration.passwordExpiration())); - c.setOpenTelemetry( - serializeOpenTelemetry(configuration.openTelemetry())); - return c; - } - - private static OpenTelemetry serializeOpenTelemetry( - final Optional c) - { - if (c.isEmpty()) { - return null; - } - - final var cc = c.get(); - final var r = new OpenTelemetry(); - - r.setTraces( - cc.traces() - .map(IdServerConfigurationFiles::serializeOpenTelemetryTraces) - .orElse(null) - ); - r.setMetrics( - cc.metrics() - .map(IdServerConfigurationFiles::serializeOpenTelemetryMetrics) - .orElse(null) - ); - r.setLogs( - cc.logs() - .map(IdServerConfigurationFiles::serializeOpenTelemetryLogs) - .orElse(null) - ); - r.setLogicalServiceName(cc.logicalServiceName()); - return r; - } - - private static Logs serializeOpenTelemetryLogs( - final IdLogs c) - { - final var r = new Logs(); - r.setEndpoint(c.endpoint().toString()); - r.setProtocol(serializeOTProtocol(c.protocol())); - return r; - } - - private static Metrics serializeOpenTelemetryMetrics( - final IdMetrics c) - { - final var r = new Metrics(); - r.setEndpoint(c.endpoint().toString()); - r.setProtocol(serializeOTProtocol(c.protocol())); - return r; - } - - private static Traces serializeOpenTelemetryTraces( - final IdTraces c) - { - final var r = new Traces(); - r.setEndpoint(c.endpoint().toString()); - r.setProtocol(serializeOTProtocol(c.protocol())); - return r; - } - - private static OpenTelemetryProtocol serializeOTProtocol( - final IdOTLPProtocol protocol) - { - return switch (protocol) { - case GRPC -> OpenTelemetryProtocol.GRPC; - case HTTP -> OpenTelemetryProtocol.HTTP; - }; - } - - private static PasswordExpiration serializePasswordExpiration( - final DatatypeFactory types, - final IdServerPasswordExpirationConfiguration c) - { - final var r = new PasswordExpiration(); - r.setAdminPasswordValidityDuration( - c.adminPasswordValidityDuration() - .map(d -> serializeDuration(types, d)) - .orElse(null) - ); - r.setUserPasswordValidityDuration( - c.userPasswordValidityDuration() - .map(d -> serializeDuration(types, d)) - .orElse(null) - ); - return r; - } - - private static RateLimiting serializeRateLimiting( - final DatatypeFactory types, - final IdServerRateLimitConfiguration c) - { - final var r = new RateLimiting(); - r.setAdminLoginDelay( - serializeDuration(types, c.adminLoginDelay())); - r.setAdminLoginRateLimit( - serializeDuration(types, c.adminLoginRateLimit())); - r.setEmailVerificationRateLimit( - serializeDuration(types, c.emailVerificationRateLimit())); - r.setPasswordResetRateLimit( - serializeDuration(types, c.passwordResetRateLimit())); - r.setUserLoginRateLimit( - serializeDuration(types, c.userLoginRateLimit())); - r.setUserLoginDelay( - serializeDuration(types, c.userLoginDelay())); - return r; - } - - private static Sessions serializeSessions( - final DatatypeFactory types, - final IdServerSessionConfiguration s) - { - final var r = new Sessions(); - r.setAdminSessionExpiration( - serializeDuration(types, s.adminSessionExpiration())); - r.setUserSessionExpiration( - serializeDuration(types, s.userSessionExpiration())); - return r; - } - - private static History serializeHistory( - final IdServerHistoryConfiguration history) - { - final var r = new History(); - r.setAdminLoginHistoryLimit(history.adminLoginHistoryLimit()); - r.setUserLoginHistoryLimit(history.userLoginHistoryLimit()); - return r; - } - - private static Database serializeDatabase( - final IdDatabaseConfiguration c) - { - final var r = new Database(); - r.setAddress(c.address()); - r.setCreate(c.create() == IdDatabaseCreate.CREATE_DATABASE); - r.setKind("POSTGRESQL"); - r.setName(c.databaseName()); - r.setOwnerRoleName(c.ownerRoleName()); - r.setOwnerRolePassword(c.ownerRolePassword()); - r.setPort(c.port()); - r.setReaderRolePassword(c.readerRolePassword().orElse(null)); - r.setUpgrade(c.upgrade() == IdDatabaseUpgrade.UPGRADE_DATABASE); - r.setWorkerRolePassword(c.workerRolePassword()); - return r; - } - - private static HTTPServices serializeHTTP( - final IdServerHTTPServiceConfiguration adminAPI, - final IdServerHTTPServiceConfiguration userAPI, - final IdServerHTTPServiceConfiguration userView) - { - final var r = new HTTPServices(); - r.setHTTPServiceAdminAPI(serializeHTTPService(adminAPI)); - r.setHTTPServiceUserAPI(serializeHTTPService(userAPI)); - r.setHTTPServiceUserView(serializeHTTPService(userView)); - return r; - } - - private static HTTPServiceType serializeHTTPService( - final IdServerHTTPServiceConfiguration s) - { - final var r = new HTTPServiceType(); - r.setExternalURI(s.externalAddress().toString()); - r.setListenAddress(s.listenAddress()); - r.setListenPort(s.listenPort()); - return r; - } - - private static Mail serializeMail( - final DatatypeFactory types, - final IdServerMailConfiguration c) - { - final var m = new Mail(); - - final var t = c.transportConfiguration(); - if (t instanceof final IdServerMailTransportSMTP ts) { - m.setSMTP(serializeMailSMTP(ts)); - } else if (t instanceof final IdServerMailTransportSMTPS ts) { - m.setSMTPS(serializeMailSMTPS(ts)); - } else if (t instanceof final IdServerMailTransportSMTP_TLS ts) { - m.setSMTPTLS(serializeMailSMTPTLS(ts)); - } - m.setSenderAddress( - c.senderAddress()); - m.setVerificationExpiration( - serializeDuration(types, c.verificationExpiration())); - m.setMailAuthentication( - serializeMailAuthentication(c.authenticationConfiguration())); - - return m; - } - - private static MailAuthentication serializeMailAuthentication( - final Optional auth) - { - if (auth.isEmpty()) { - return null; - } - - final var a = auth.get(); - final var r = new MailAuthentication(); - r.setUsername(a.userName()); - r.setPassword(a.password()); - return r; - } - - private static javax.xml.datatype.Duration serializeDuration( - final DatatypeFactory types, - final Duration duration) - { - return types.newDuration(duration.toString()); - } - - private static SMTPType serializeMailSMTP( - final IdServerMailTransportSMTP ts) - { - final var s = new SMTPType(); - s.setHost(ts.host()); - s.setPort(ts.port()); - return s; - } - - private static SMTPSType serializeMailSMTPS( - final IdServerMailTransportSMTPS ts) - { - final var s = new SMTPSType(); - s.setHost(ts.host()); - s.setPort(ts.port()); - return s; - } - - private static SMTPTLSType serializeMailSMTPTLS( - final IdServerMailTransportSMTP_TLS ts) - { - final var s = new SMTPTLSType(); - s.setHost(ts.host()); - s.setPort(ts.port()); - return s; - } - - private static Branding serializeBranding( - final IdServerBrandingConfiguration branding) - { - final var b = new Branding(); - b.setColorScheme( - serializeBrandingColorScheme(branding.scheme())); - b.setLogo( - serializeBrandingLogo(branding.logo())); - b.setLoginExtra( - serializeBrandingLoginExtra(branding.loginExtra())); - b.setProductTitle( - serializeBrandingProductTitle(branding.productTitle())); - return b; - } - - private static ColorScheme serializeBrandingColorScheme( - final Optional scheme) - { - if (scheme.isEmpty()) { - return null; - } - - final var s = scheme.get(); - final var c = new ColorScheme(); - c.setButtonColors( - serializeBrandingButtonColors(s.buttonColors())); - c.setErrorBorderColor( - serializeColorType(s.errorBorderColor())); - - c.setHeaderBackgroundColor( - serializeColorType(s.headerBackgroundColor())); - c.setHeaderLinkColor( - serializeColorType(s.headerLinkColor())); - c.setHeaderBackgroundColor( - serializeColorType(s.headerBackgroundColor())); - c.setHeaderTextColor( - serializeColorType(s.headerTextColor())); - - c.setMainBackgroundColor( - serializeColorType(s.mainBackgroundColor())); - c.setMainLinkColor( - serializeColorType(s.mainLinkColor())); - c.setMainBackgroundColor( - serializeColorType(s.mainBackgroundColor())); - c.setMainTextColor( - serializeColorType(s.mainTextColor())); - c.setMainTableBorderColor( - serializeColorType(s.mainTableBorderColor())); - c.setMainMessageBorderColor( - serializeColorType(s.mainMessageBorderColor())); - - return c; - } - - private static ButtonColors serializeBrandingButtonColors( - final CxButtonColors cxButtonColors) - { - final var c = new ButtonColors(); - - c.setDisabled( - serializeBrandingButtonStateColors(cxButtonColors.disabled())); - c.setEnabled( - serializeBrandingButtonStateColors(cxButtonColors.enabled())); - c.setHover( - serializeBrandingButtonStateColors(cxButtonColors.hover())); - c.setPressed( - serializeBrandingButtonStateColors(cxButtonColors.pressed())); - - return c; - } - - private static ButtonStateColors serializeBrandingButtonStateColors( - final CxButtonStateColors s) - { - final var c = new ButtonStateColors(); - c.setBodyColor(serializeCxColorType(s.bodyColor())); - c.setBorderColor(serializeCxColorType(s.borderColor())); - c.setEmbossEColor(serializeCxColorType(s.embossEColor())); - c.setEmbossNColor(serializeCxColorType(s.embossNColor())); - c.setEmbossWColor(serializeCxColorType(s.embossWColor())); - c.setEmbossSColor(serializeCxColorType(s.embossSColor())); - c.setTextColor(serializeCxColorType(s.textColor())); - return c; - } - - private static ColorType serializeCxColorType( - final CxColor cxColor) - { - final var c = new ColorType(); - c.setRed(cxColor.red()); - c.setGreen(cxColor.green()); - c.setBlue(cxColor.blue()); - return c; - } - - private static ColorType serializeColorType( - final IdColor idColor) - { - final var c = new ColorType(); - c.setRed(idColor.red()); - c.setGreen(idColor.green()); - c.setBlue(idColor.blue()); - return c; - } - - private static String serializeBrandingLogo( - final Optional logo) - { - return logo.map(Path::toString).orElse(null); - } - - private static String serializeBrandingLoginExtra( - final Optional path) - { - return path.map(Path::toString).orElse(null); - } - - private static String serializeBrandingProductTitle( - final String s) - { - return s; - } - - private static IdServerConfigurationFile parseConfiguration( - final Configuration input) - throws URISyntaxException - { - return new IdServerConfigurationFile( - parseBranding(input.getBranding()), - parseMail(input.getMail()), - parseHTTP(input.getHTTPServices()), - parseDatabase(input.getDatabase()), - parseHistory(input.getHistory()), - parseSessions(input.getSessions()), - parseRateLimit(input.getRateLimiting()), - parsePasswordExpiration(input.getPasswordExpiration()), - parseOpenTelemetry(input.getOpenTelemetry()) - ); - } - - private static IdServerPasswordExpirationConfiguration parsePasswordExpiration( - final PasswordExpiration passwordExpiration) - { - if (passwordExpiration == null) { - return new IdServerPasswordExpirationConfiguration( - Optional.empty(), - Optional.empty() - ); - } - - return new IdServerPasswordExpirationConfiguration( - Optional.ofNullable(passwordExpiration.getUserPasswordValidityDuration()) - .map(IdServerConfigurationFiles::parseDuration), - Optional.ofNullable(passwordExpiration.getAdminPasswordValidityDuration()) - .map(IdServerConfigurationFiles::parseDuration) - ); - } - - private static Optional parseOpenTelemetry( - final OpenTelemetry openTelemetry) - { - if (openTelemetry == null) { - return Optional.empty(); - } - - final var metrics = - Optional.ofNullable(openTelemetry.getMetrics()) - .map(m -> new IdMetrics( - URI.create(m.getEndpoint()), - parseProtocol(m.getProtocol()) - )); - - final var traces = - Optional.ofNullable(openTelemetry.getTraces()) - .map(m -> new IdTraces( - URI.create(m.getEndpoint()), - parseProtocol(m.getProtocol()) - )); - - final var logs = - Optional.ofNullable(openTelemetry.getLogs()) - .map(m -> new IdLogs( - URI.create(m.getEndpoint()), - parseProtocol(m.getProtocol()) - )); - - return Optional.of( - new IdServerOpenTelemetryConfiguration( - openTelemetry.getLogicalServiceName(), - logs, - metrics, - traces - ) - ); - } - - private static IdOTLPProtocol parseProtocol( - final OpenTelemetryProtocol protocol) - { - return switch (protocol) { - case GRPC -> IdOTLPProtocol.GRPC; - case HTTP -> IdOTLPProtocol.HTTP; - }; - } - - private static IdServerRateLimitConfiguration parseRateLimit( - final RateLimiting rateLimiting) - { - return new IdServerRateLimitConfiguration( - parseDuration( - rateLimiting.getEmailVerificationRateLimit()), - parseDuration( - rateLimiting.getPasswordResetRateLimit()), - parseDurationOrDefault( - rateLimiting.getUserLoginRateLimit(), - Duration.ofSeconds(5L) - ), - parseDurationOrDefault( - rateLimiting.getUserLoginDelay(), - Duration.ofSeconds(1L) - ), - parseDurationOrDefault( - rateLimiting.getAdminLoginRateLimit(), - Duration.ofSeconds(5L) - ), - parseDurationOrDefault( - rateLimiting.getAdminLoginDelay(), - Duration.ofSeconds(1L) - ) - ); - } - - private static Duration parseDuration( - final javax.xml.datatype.Duration duration) - { - return Duration.parse(duration.toString()); - } - - private static Duration parseDurationOrDefault( - final javax.xml.datatype.Duration duration, - final Duration defaultValue) - { - if (duration == null) { - return defaultValue; - } - - return Duration.parse(duration.toString()); - } - - private static IdServerSessionConfiguration parseSessions( - final Sessions sessions) - { - return new IdServerSessionConfiguration( - parseDuration(sessions.getUserSessionExpiration()), - parseDuration(sessions.getAdminSessionExpiration()) - ); - } - - private static IdServerHistoryConfiguration parseHistory( - final History history) - { - return new IdServerHistoryConfiguration( - Math.toIntExact(history.getUserLoginHistoryLimit()), - Math.toIntExact(history.getAdminLoginHistoryLimit()) - ); - } - - private static IdServerDatabaseConfiguration parseDatabase( - final Database database) - { - return new IdServerDatabaseConfiguration( - parseDatabaseKind(database.getKind()), - database.getOwnerRoleName(), - database.getOwnerRolePassword(), - database.getWorkerRolePassword(), - Optional.ofNullable(database.getReaderRolePassword()), - database.getAddress(), - Math.toIntExact(database.getPort()), - database.getName(), - database.isCreate(), - database.isUpgrade() - ); - } - - private static IdServerDatabaseKind parseDatabaseKind( - final String kind) - { - return switch (kind.toLowerCase(Locale.ROOT)) { - case "postgresql" -> POSTGRESQL; - default -> { - throw new IllegalArgumentException( - "Unrecognized database kind: %s (must be one of %s)" - .formatted(kind, List.of(IdServerDatabaseKind.values())) - ); - } - }; - } - - private static IdServerHTTPConfiguration parseHTTP( - final HTTPServices httpServices) - throws URISyntaxException - { - return new IdServerHTTPConfiguration( - parseHTTPService(httpServices.getHTTPServiceAdminAPI()), - parseHTTPService(httpServices.getHTTPServiceUserAPI()), - parseHTTPService(httpServices.getHTTPServiceUserView()) - ); - } - - private static IdServerHTTPServiceConfiguration parseHTTPService( - final HTTPServiceType service) - throws URISyntaxException - { - return new IdServerHTTPServiceConfiguration( - service.getListenAddress(), - Math.toIntExact(service.getListenPort()), - new URI(service.getExternalURI()) - ); - } - - private static IdServerMailConfiguration parseMail( - final Mail mail) - { - final IdServerMailTransportConfigurationType transport; - if (mail.getSMTP() != null) { - transport = parseSMTP(mail.getSMTP()); - } else if (mail.getSMTPS() != null) { - transport = parseSMTPS(mail.getSMTPS()); - } else if (mail.getSMTPTLS() != null) { - transport = parseSMTPTLS(mail.getSMTPTLS()); - } else { - throw new IllegalStateException(); - } - - return new IdServerMailConfiguration( - transport, - parseMailAuth(mail.getMailAuthentication()), - mail.getSenderAddress(), - parseDuration(mail.getVerificationExpiration()) - ); - } - - private static IdServerMailTransportConfigurationType parseSMTP( - final SMTPType smtp) - { - return new IdServerMailTransportSMTP( - smtp.getHost(), - Math.toIntExact(smtp.getPort()) - ); - } - - private static IdServerMailTransportConfigurationType parseSMTPS( - final SMTPSType smtp) - { - return new IdServerMailTransportSMTPS( - smtp.getHost(), - Math.toIntExact(smtp.getPort()) - ); - } - - private static IdServerMailTransportConfigurationType parseSMTPTLS( - final SMTPTLSType smtp) - { - return new IdServerMailTransportSMTP_TLS( - smtp.getHost(), - Math.toIntExact(smtp.getPort()) - ); - } - - private static Optional parseMailAuth( - final MailAuthentication mailAuthentication) - { - if (mailAuthentication == null) { - return Optional.empty(); - } - - return Optional.of( - new IdServerMailAuthenticationConfiguration( - mailAuthentication.getUsername(), - mailAuthentication.getPassword() - ) - ); - } - - private static IdServerBrandingConfiguration parseBranding( - final Branding branding) - { - return new IdServerBrandingConfiguration( - branding.getProductTitle(), - parseLogo(branding.getLogo()), - parseLoginExtra(branding.getLoginExtra()), - parseColorScheme(branding.getColorScheme()) - ); - } - - private static Optional parseColorScheme( - final ColorScheme colorScheme) - { - if (colorScheme == null) { - return Optional.empty(); - } - - return Optional.of( - new IdServerColorScheme( - parseButtonColors(colorScheme.getButtonColors()), - parseColor(colorScheme.getErrorBorderColor()), - parseColor(colorScheme.getHeaderBackgroundColor()), - parseColor(colorScheme.getHeaderLinkColor()), - parseColor(colorScheme.getHeaderTextColor()), - parseColor(colorScheme.getMainBackgroundColor()), - parseColor(colorScheme.getMainLinkColor()), - parseColor(colorScheme.getMainMessageBorderColor()), - parseColor(colorScheme.getMainTableBorderColor()), - parseColor(colorScheme.getMainTextColor()) - ) - ); - } - - private static CxButtonColors parseButtonColors( - final ButtonColors buttonColors) - { - return new CxButtonColors( - parseButtonStateColors(buttonColors.getEnabled()), - parseButtonStateColors(buttonColors.getDisabled()), - parseButtonStateColors(buttonColors.getPressed()), - parseButtonStateColors(buttonColors.getHover()) - ); - } - - private static CxButtonStateColors parseButtonStateColors( - final ButtonStateColors state) - { - return new CxButtonStateColors( - parseCxColor(state.getTextColor()), - parseCxColor(state.getBodyColor()), - parseCxColor(state.getBorderColor()), - parseCxColor(state.getEmbossEColor()), - parseCxColor(state.getEmbossNColor()), - parseCxColor(state.getEmbossSColor()), - parseCxColor(state.getEmbossWColor()) - ); - } - - private static CxColor parseCxColor( - final ColorType color) - { - return new CxColor(color.getRed(), color.getGreen(), color.getBlue()); - } - - private static IdColor parseColor( - final ColorType color) - { - return new IdColor( - color.getRed(), - color.getGreen(), - color.getBlue() - ); - } - - private static Optional parseLoginExtra( - final String loginExtra) - { - if (loginExtra == null) { - return Optional.empty(); - } - - return Optional.of(Path.of(loginExtra)); - } - - private static Optional parseLogo( - final String logo) - { - if (logo == null) { - return Optional.empty(); - } - - return Optional.of(Path.of(logo)); - } - - /** - * Parse a configuration file. - * - * @param file The input file - * - * @return The file - * - * @throws IOException On errors - */ - - public IdServerConfigurationFile parse( - final Path file) - throws IOException - { - try (var stream = Files.newInputStream(file)) { - return this.parse(file.toUri(), stream); - } - } - - @Override - public String description() - { - return "Server configuration elements."; - } - - @Override - public String toString() - { - return "[IdServerConfigurationFiles 0x%s]" - .formatted(Long.toUnsignedString(this.hashCode(), 16)); - } -} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParser.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParser.java new file mode 100644 index 00000000..a7080cc1 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParser.java @@ -0,0 +1,129 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.ParseSeverity; +import com.io7m.anethum.api.ParseStatus; +import com.io7m.anethum.api.ParsingException; +import com.io7m.blackthorne.core.BTException; +import com.io7m.blackthorne.core.BTParseError; +import com.io7m.blackthorne.core.BTPreserveLexical; +import com.io7m.blackthorne.jxe.BlackthorneJXE; +import com.io7m.idstore.server.api.IdServerConfigurationFile; +import com.io7m.idstore.server.service.configuration.v1.IdC1Configuration; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; + +import static com.io7m.blackthorne.core.BTPreserveLexical.PRESERVE_LEXICAL_INFORMATION; +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdServerConfigurationParser + implements IdServerConfigurationParserType +{ + private final BTPreserveLexical context; + private final URI source; + private final InputStream stream; + private final Consumer statusConsumer; + + IdServerConfigurationParser( + final BTPreserveLexical inContext, + final URI inSource, + final InputStream inStream, + final Consumer inStatusConsumer) + { + this.context = + Objects.requireNonNullElse(inContext, PRESERVE_LEXICAL_INFORMATION); + this.source = + Objects.requireNonNull(inSource, "source"); + this.stream = + Objects.requireNonNull(inStream, "stream"); + this.statusConsumer = + Objects.requireNonNull(inStatusConsumer, "statusConsumer"); + } + + @Override + public String toString() + { + return "[IdServerConfigurationParser 0x%x]" + .formatted(Integer.valueOf(this.hashCode())); + } + + @Override + public IdServerConfigurationFile execute() + throws ParsingException + { + try { + return BlackthorneJXE.parse( + this.source, + this.stream, + Map.ofEntries( + entry(qName("Configuration"), IdC1Configuration::new) + ), + IdServerConfigurationSchemas.schemas(), + this.context + ); + } catch (final BTException e) { + final var statuses = + e.errors() + .stream() + .map(IdServerConfigurationParser::mapParseError) + .toList(); + + for (final var status : statuses) { + this.statusConsumer.accept(status); + } + + final var ex = + new ParsingException(e.getMessage(), List.copyOf(statuses)); + ex.addSuppressed(e); + throw ex; + } + } + + @Override + public void close() + throws IOException + { + this.stream.close(); + } + + private static ParseStatus mapParseError( + final BTParseError error) + { + return ParseStatus.builder("parse-error", error.message()) + .withSeverity(mapSeverity(error.severity())) + .withLexical(error.lexical()) + .build(); + } + + private static ParseSeverity mapSeverity( + final BTParseError.Severity severity) + { + return switch (severity) { + case ERROR -> ParseSeverity.PARSE_ERROR; + case WARNING -> ParseSeverity.PARSE_WARNING; + }; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserFactoryType.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserFactoryType.java new file mode 100644 index 00000000..bf192bb2 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserFactoryType.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.ParserFactoryType; +import com.io7m.blackthorne.core.BTPreserveLexical; +import com.io7m.idstore.server.api.IdServerConfigurationFile; + +/** + * A factory of configuration file parsers. + */ + +public interface IdServerConfigurationParserFactoryType + extends ParserFactoryType< + BTPreserveLexical, + IdServerConfigurationFile, + IdServerConfigurationParserType> +{ + +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserType.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserType.java new file mode 100644 index 00000000..2a55836b --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParserType.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.ParserType; +import com.io7m.idstore.server.api.IdServerConfigurationFile; + +/** + * A configuration file parser. + */ + +public interface IdServerConfigurationParserType + extends ParserType +{ + +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParsers.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParsers.java new file mode 100644 index 00000000..dd9b7512 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationParsers.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.ParseStatus; +import com.io7m.blackthorne.core.BTPreserveLexical; + +import java.io.InputStream; +import java.net.URI; +import java.util.function.Consumer; + +/** + * A factory of configuration file parsers. + */ + +public final class IdServerConfigurationParsers + implements IdServerConfigurationParserFactoryType +{ + /** + * A factory of configuration file parsers. + */ + + public IdServerConfigurationParsers() + { + + } + + @Override + public IdServerConfigurationParserType createParserWithContext( + final BTPreserveLexical context, + final URI source, + final InputStream stream, + final Consumer statusConsumer) + { + return new IdServerConfigurationParser(context, source, stream, statusConsumer); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSchemas.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSchemas.java new file mode 100644 index 00000000..68c970ed --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSchemas.java @@ -0,0 +1,84 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.jxe.core.JXESchemaDefinition; +import com.io7m.jxe.core.JXESchemaResolutionMappings; + +import java.net.URI; + +/** + * Configuration XML schemas. + */ + +public final class IdServerConfigurationSchemas +{ + private static final JXESchemaDefinition SCHEMA_1 = + JXESchemaDefinition.builder() + .setFileIdentifier("configuration-1.xsd") + .setLocation(IdServerConfigurationSchemas.class.getResource( + "/com/io7m/idstore/server/service/configuration/configuration-1.xsd")) + .setNamespace(URI.create("urn:com.io7m.idstore:configuration:1")) + .build(); + + private static final JXESchemaDefinition TLS_1 = + JXESchemaDefinition.builder() + .setFileIdentifier("tls-1.xsd") + .setLocation(IdServerConfigurationSchemas.class.getResource( + "/com/io7m/idstore/server/service/configuration/tls-1.xsd")) + .setNamespace(URI.create("urn:com.io7m.idstore.tls:1")) + .build(); + + private static final JXESchemaResolutionMappings SCHEMA_MAPPINGS = + JXESchemaResolutionMappings.builder() + .putMappings(SCHEMA_1.namespace(), SCHEMA_1) + .putMappings(TLS_1.namespace(), TLS_1) + .build(); + + /** + * @return The v1 schema + */ + + public static JXESchemaDefinition schema1() + { + return SCHEMA_1; + } + + /** + * @return The TLS v1 schema + */ + + public static JXESchemaDefinition tls1() + { + return TLS_1; + } + + /** + * @return The set of supported schemas. + */ + + public static JXESchemaResolutionMappings schemas() + { + return SCHEMA_MAPPINGS; + } + + private IdServerConfigurationSchemas() + { + + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializer.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializer.java new file mode 100644 index 00000000..0ed24a2d --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializer.java @@ -0,0 +1,625 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.SerializationException; +import com.io7m.cxbutton.core.CxButtonColors; +import com.io7m.cxbutton.core.CxButtonStateColors; +import com.io7m.cxbutton.core.CxColor; +import com.io7m.idstore.server.api.IdColor; +import com.io7m.idstore.server.api.IdServerBrandingConfiguration; +import com.io7m.idstore.server.api.IdServerColorScheme; +import com.io7m.idstore.server.api.IdServerConfigurationFile; +import com.io7m.idstore.server.api.IdServerDatabaseConfiguration; +import com.io7m.idstore.server.api.IdServerHTTPConfiguration; +import com.io7m.idstore.server.api.IdServerHTTPServiceConfiguration; +import com.io7m.idstore.server.api.IdServerHistoryConfiguration; +import com.io7m.idstore.server.api.IdServerMailAuthenticationConfiguration; +import com.io7m.idstore.server.api.IdServerMailConfiguration; +import com.io7m.idstore.server.api.IdServerMailTransportSMTP; +import com.io7m.idstore.server.api.IdServerMailTransportSMTPS; +import com.io7m.idstore.server.api.IdServerMailTransportSMTP_TLS; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration; +import com.io7m.idstore.server.api.IdServerPasswordExpirationConfiguration; +import com.io7m.idstore.server.api.IdServerRateLimitConfiguration; +import com.io7m.idstore.server.api.IdServerSessionConfiguration; +import com.io7m.idstore.tls.IdTLSConfigurationType; +import com.io7m.idstore.tls.IdTLSDisabled; +import com.io7m.idstore.tls.IdTLSEnabled; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.util.Objects; +import java.util.Optional; + +import static java.lang.Integer.toUnsignedString; + +final class IdServerConfigurationSerializer + implements IdServerConfigurationSerializerType +{ + private final OutputStream stream; + private final XMLStreamWriter output; + + IdServerConfigurationSerializer( + final URI inTarget, + final OutputStream inStream) + { + Objects.requireNonNull(inTarget, "target"); + + this.stream = + Objects.requireNonNull(inStream, "stream"); + + try { + this.output = + XMLOutputFactory.newFactory() + .createXMLStreamWriter(this.stream, "UTF-8"); + } catch (final XMLStreamException e) { + throw new IllegalStateException(e); + } + } + + private static String findNS() + { + return IdServerConfigurationSchemas.schema1().namespace().toString(); + } + + @Override + public String toString() + { + return "[IdServerConfigurationSerializer 0x%x]" + .formatted(Integer.valueOf(this.hashCode())); + } + + @Override + public void execute( + final IdServerConfigurationFile value) + throws SerializationException + { + try { + this.output.writeStartDocument("UTF-8", "1.0"); + this.serializeFile(value); + this.output.writeEndDocument(); + } catch (final XMLStreamException e) { + throw new SerializationException(e.getMessage(), e); + } + } + + private void serializeFile( + final IdServerConfigurationFile value) + throws XMLStreamException + { + this.output.writeStartElement("Configuration"); + this.output.writeDefaultNamespace(findNS()); + this.output.writeNamespace("tls", findTLSNS()); + + this.serializeBranding(value.brandingConfiguration()); + this.serializeDatabase(value.databaseConfiguration()); + this.serializeHTTP(value.httpConfiguration()); + this.serializeHistory(value.historyConfiguration()); + this.serializeMail(value.mailConfiguration()); + this.serializeOpenTelemetryOpt(value.openTelemetry()); + this.serializePasswordExpiration(value.passwordExpiration()); + this.serializeRateLimit(value.rateLimit()); + this.serializeSessions(value.sessionConfiguration()); + + this.output.writeEndElement(); + } + + private void serializeHTTP( + final IdServerHTTPConfiguration http) + throws XMLStreamException + { + this.output.writeStartElement("HTTPServices"); + + this.serializeHTTPAdminAPI(http.adminAPIService()); + this.serializeHTTPUserAPI(http.userAPIService()); + this.serializeHTTPUserView(http.userViewService()); + + this.output.writeEndElement(); + } + + private void serializeHTTPUserView( + final IdServerHTTPServiceConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("HTTPServiceUserView"); + this.output.writeAttribute("ListenAddress", c.listenAddress()); + this.output.writeAttribute("ListenPort", toUnsignedString(c.listenPort())); + this.output.writeAttribute("ExternalURI", c.externalAddress().toString()); + this.serializeTLS(c.tlsConfiguration()); + this.output.writeEndElement(); + } + + private void serializeTLS( + final IdTLSConfigurationType c) + throws XMLStreamException + { + final var tlsNs = findTLSNS(); + + switch (c) { + case final IdTLSDisabled ignored -> { + this.output.writeStartElement("tls", "TLSDisabled", tlsNs); + this.output.writeEndElement(); + } + case final IdTLSEnabled e -> { + this.output.writeStartElement("tls", "TLSEnabled", tlsNs); + + final var ks = e.keyStore(); + this.output.writeStartElement("tls", "KeyStore", tlsNs); + this.output.writeAttribute("Type", ks.storeType()); + this.output.writeAttribute("Provider", ks.storeProvider()); + this.output.writeAttribute("Password", ks.storePassword()); + this.output.writeAttribute("File", ks.storePath().toString()); + this.output.writeEndElement(); + + final var ts = e.trustStore(); + this.output.writeStartElement("tls", "TrustStore", tlsNs); + this.output.writeAttribute("Type", ts.storeType()); + this.output.writeAttribute("Provider", ts.storeProvider()); + this.output.writeAttribute("Password", ts.storePassword()); + this.output.writeAttribute("File", ts.storePath().toString()); + this.output.writeEndElement(); + + this.output.writeEndElement(); + } + } + } + + private static String findTLSNS() + { + return IdServerConfigurationSchemas.tls1().namespace().toString(); + } + + private void serializeHTTPUserAPI( + final IdServerHTTPServiceConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("HTTPServiceUserAPI"); + this.output.writeAttribute("ListenAddress", c.listenAddress()); + this.output.writeAttribute("ListenPort", toUnsignedString(c.listenPort())); + this.output.writeAttribute("ExternalURI", c.externalAddress().toString()); + this.serializeTLS(c.tlsConfiguration()); + this.output.writeEndElement(); + } + + private void serializeHTTPAdminAPI( + final IdServerHTTPServiceConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("HTTPServiceAdminAPI"); + this.output.writeAttribute("ListenAddress", c.listenAddress()); + this.output.writeAttribute("ListenPort", toUnsignedString(c.listenPort())); + this.output.writeAttribute("ExternalURI", c.externalAddress().toString()); + this.serializeTLS(c.tlsConfiguration()); + this.output.writeEndElement(); + } + + private void serializeMail( + final IdServerMailConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("Mail"); + this.output.writeAttribute( + "SenderAddress", + c.senderAddress() + ); + this.output.writeAttribute( + "VerificationExpiration", + c.verificationExpiration().toString() + ); + + switch (c.transportConfiguration()) { + case final IdServerMailTransportSMTP s -> { + this.output.writeStartElement("SMTP"); + this.output.writeAttribute("Host", s.host()); + this.output.writeAttribute("Port", toUnsignedString(s.port())); + this.output.writeEndElement(); + } + case final IdServerMailTransportSMTPS s -> { + this.output.writeStartElement("SMTPS"); + this.output.writeAttribute("Host", s.host()); + this.output.writeAttribute("Port", toUnsignedString(s.port())); + this.output.writeEndElement(); + } + case final IdServerMailTransportSMTP_TLS s -> { + this.output.writeStartElement("SMTPTLS"); + this.output.writeAttribute("Host", s.host()); + this.output.writeAttribute("Port", toUnsignedString(s.port())); + this.output.writeEndElement(); + } + } + + if (c.authenticationConfiguration().isPresent()) { + this.serializeMailAuthentication(c.authenticationConfiguration().get()); + } + + this.output.writeEndElement(); + } + + private void serializeMailAuthentication( + final IdServerMailAuthenticationConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("MailAuthentication"); + this.output.writeAttribute("Username", c.userName()); + this.output.writeAttribute("Password", c.password()); + this.output.writeEndElement(); + } + + private void serializeOpenTelemetryOpt( + final Optional c) + throws XMLStreamException + { + if (c.isPresent()) { + this.serializeOpenTelemetry(c.get()); + } + } + + private void serializeOpenTelemetry( + final IdServerOpenTelemetryConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("OpenTelemetry"); + this.output.writeAttribute("LogicalServiceName", c.logicalServiceName()); + + if (c.logs().isPresent()) { + final var e = c.logs().get(); + this.output.writeStartElement("Logs"); + this.output.writeAttribute("Endpoint", e.endpoint().toString()); + this.output.writeAttribute("Protocol", e.protocol().toString()); + this.output.writeEndElement(); + } + + if (c.metrics().isPresent()) { + final var e = c.metrics().get(); + this.output.writeStartElement("Metrics"); + this.output.writeAttribute("Endpoint", e.endpoint().toString()); + this.output.writeAttribute("Protocol", e.protocol().toString()); + this.output.writeEndElement(); + } + + if (c.traces().isPresent()) { + final var e = c.traces().get(); + this.output.writeStartElement("Traces"); + this.output.writeAttribute("Endpoint", e.endpoint().toString()); + this.output.writeAttribute("Protocol", e.protocol().toString()); + this.output.writeEndElement(); + } + + this.output.writeEndElement(); + } + + private void serializeSessions( + final IdServerSessionConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("Sessions"); + this.output.writeAttribute( + "UserSessionExpiration", + c.userSessionExpiration().toString() + ); + this.output.writeAttribute( + "AdminSessionExpiration", + c.adminSessionExpiration().toString() + ); + this.output.writeEndElement(); + } + + private void serializePasswordExpiration( + final IdServerPasswordExpirationConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("PasswordExpiration"); + + if (c.userPasswordValidityDuration().isPresent()) { + this.output.writeAttribute( + "UserPasswordValidityDuration", + c.userPasswordValidityDuration().get().toString() + ); + } + + if (c.adminPasswordValidityDuration().isPresent()) { + this.output.writeAttribute( + "AdminPasswordValidityDuration", + c.adminPasswordValidityDuration().get().toString() + ); + } + + this.output.writeEndElement(); + } + + private void serializeRateLimit( + final IdServerRateLimitConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("RateLimiting"); + this.output.writeAttribute( + "UserLoginDelay", + c.userLoginDelay().toString() + ); + this.output.writeAttribute( + "UserLoginRateLimit", + c.userLoginRateLimit().toString() + ); + this.output.writeAttribute( + "AdminLoginDelay", + c.adminLoginDelay().toString() + ); + this.output.writeAttribute( + "AdminLoginRateLimit", + c.adminLoginRateLimit().toString() + ); + this.output.writeAttribute( + "EmailVerificationRateLimit", + c.emailVerificationRateLimit().toString() + ); + this.output.writeAttribute( + "PasswordResetRateLimit", + c.passwordResetRateLimit().toString() + ); + this.output.writeEndElement(); + } + + private void serializeHistory( + final IdServerHistoryConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("History"); + this.output.writeAttribute( + "UserLoginHistoryLimit", + toUnsignedString(c.userLoginHistoryLimit()) + ); + this.output.writeAttribute( + "AdminLoginHistoryLimit", + toUnsignedString(c.adminLoginHistoryLimit()) + ); + this.output.writeEndElement(); + } + + private void serializeDatabase( + final IdServerDatabaseConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("Database"); + this.output.writeAttribute( + "OwnerRoleName", + c.ownerRoleName() + ); + this.output.writeAttribute( + "OwnerRolePassword", + c.ownerRolePassword() + ); + this.output.writeAttribute( + "WorkerRolePassword", + c.workerRolePassword() + ); + + if (c.readerRolePassword().isPresent()) { + final var r = c.readerRolePassword().get(); + this.output.writeAttribute("ReaderRolePassword", r); + } + + this.output.writeAttribute( + "Kind", + c.kind().name() + ); + this.output.writeAttribute( + "Name", + c.databaseName() + ); + this.output.writeAttribute( + "Address", + c.address() + ); + this.output.writeAttribute( + "Port", + toUnsignedString(c.port()) + ); + this.output.writeAttribute( + "Create", + Boolean.toString(c.create()) + ); + this.output.writeAttribute( + "Upgrade", + Boolean.toString(c.upgrade()) + ); + this.output.writeEndElement(); + } + + private void serializeBranding( + final IdServerBrandingConfiguration c) + throws XMLStreamException + { + this.output.writeStartElement("Branding"); + this.output.writeAttribute("ProductTitle", c.productTitle()); + + final var logoOpt = c.logo(); + if (logoOpt.isPresent()) { + final var logo = logoOpt.get(); + this.output.writeAttribute("Logo", logo.toString()); + } + + final var loginExtraOpt = c.loginExtra(); + if (loginExtraOpt.isPresent()) { + final var loginExtra = loginExtraOpt.get(); + this.output.writeAttribute("LoginExtra", loginExtra.toString()); + } + + final var schemeOpt = c.scheme(); + if (schemeOpt.isPresent()) { + final var scheme = schemeOpt.get(); + this.serializeScheme(scheme); + } + + this.output.writeEndElement(); + } + + private void serializeScheme( + final IdServerColorScheme scheme) + throws XMLStreamException + { + this.output.writeStartElement("ColorScheme"); + this.serializeButtonColors(scheme.buttonColors()); + this.serializeColor( + "ErrorBorderColor", + scheme.errorBorderColor() + ); + this.serializeColor( + "HeaderBackgroundColor", + scheme.headerBackgroundColor() + ); + this.serializeColor( + "HeaderLinkColor", + scheme.headerLinkColor() + ); + this.serializeColor( + "HeaderTextColor", + scheme.headerTextColor() + ); + this.serializeColor( + "MainBackgroundColor", + scheme.mainBackgroundColor() + ); + this.serializeColor( + "MainLinkColor", + scheme.mainLinkColor() + ); + this.serializeColor( + "MainMessageBorderColor", + scheme.mainMessageBorderColor() + ); + this.serializeColor( + "MainTableBorderColor", + scheme.mainTableBorderColor() + ); + this.serializeColor( + "MainTextColor", + scheme.mainTextColor() + ); + this.output.writeEndElement(); + } + + private void serializeColor( + final String name, + final IdColor idColor) + throws XMLStreamException + { + this.output.writeStartElement(name); + this.output.writeAttribute( + "Red", + String.format("%.03f", Double.valueOf(idColor.red())) + ); + this.output.writeAttribute( + "Green", + String.format("%.03f", Double.valueOf(idColor.green())) + ); + this.output.writeAttribute( + "Blue", + String.format("%.03f", Double.valueOf(idColor.blue())) + ); + this.output.writeEndElement(); + } + + private void serializeButtonColors( + final CxButtonColors colors) + throws XMLStreamException + { + this.output.writeStartElement("ButtonColors"); + this.serializeButtonColorsDisabled(colors.disabled()); + this.serializeButtonColorsEnabled(colors.enabled()); + this.serializeButtonColorsHover(colors.hover()); + this.serializeButtonColorsPressed(colors.pressed()); + this.output.writeEndElement(); + } + + private void serializeButtonColorsPressed( + final CxButtonStateColors c) + throws XMLStreamException + { + this.serializeButtonStateColors("Pressed", c); + } + + private void serializeButtonColorsHover( + final CxButtonStateColors c) + throws XMLStreamException + { + this.serializeButtonStateColors("Hover", c); + } + + private void serializeButtonColorsEnabled( + final CxButtonStateColors c) + throws XMLStreamException + { + this.serializeButtonStateColors("Enabled", c); + } + + private void serializeButtonColorsDisabled( + final CxButtonStateColors c) + throws XMLStreamException + { + this.serializeButtonStateColors("Disabled", c); + } + + private void serializeButtonStateColors( + final String name, + final CxButtonStateColors c) + throws XMLStreamException + { + this.output.writeStartElement(name); + this.serializeCxColor("BodyColor", c.bodyColor()); + this.serializeCxColor("BorderColor", c.borderColor()); + this.serializeCxColor("EmbossEColor", c.embossEColor()); + this.serializeCxColor("EmbossNColor", c.embossNColor()); + this.serializeCxColor("EmbossSColor", c.embossSColor()); + this.serializeCxColor("EmbossWColor", c.embossWColor()); + this.serializeCxColor("TextColor", c.textColor()); + this.output.writeEndElement(); + } + + private void serializeCxColor( + final String name, + final CxColor c) + throws XMLStreamException + { + this.output.writeStartElement(name); + this.output.writeAttribute( + "Red", + String.format("%.03f", Double.valueOf(c.red())) + ); + this.output.writeAttribute( + "Green", + String.format("%.03f", Double.valueOf(c.green())) + ); + this.output.writeAttribute( + "Blue", + String.format("%.03f", Double.valueOf(c.blue())) + ); + this.output.writeEndElement(); + } + + @Override + public void close() + throws IOException + { + this.stream.close(); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerFactoryType.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerFactoryType.java new file mode 100644 index 00000000..cd51e698 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerFactoryType.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.SerializerFactoryType; +import com.io7m.idstore.server.api.IdServerConfigurationFile; + +/** + * A factory of configuration file serializers. + */ + +public interface IdServerConfigurationSerializerFactoryType + extends SerializerFactoryType< + Void, + IdServerConfigurationFile, + IdServerConfigurationSerializerType> +{ + +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerType.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerType.java new file mode 100644 index 00000000..0a044b46 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializerType.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import com.io7m.anethum.api.SerializerType; +import com.io7m.idstore.server.api.IdServerConfigurationFile; + +/** + * A configuration file serializer. + */ + +public interface IdServerConfigurationSerializerType + extends SerializerType +{ + +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializers.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializers.java new file mode 100644 index 00000000..e034cf93 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/IdServerConfigurationSerializers.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration; + +import java.io.OutputStream; +import java.net.URI; + +/** + * A factory of configuration file serializers. + */ + +public final class IdServerConfigurationSerializers + implements IdServerConfigurationSerializerFactoryType +{ + /** + * A factory of configuration file serializers. + */ + + public IdServerConfigurationSerializers() + { + + } + + @Override + public IdServerConfigurationSerializerType createSerializerWithContext( + final Void context, + final URI target, + final OutputStream stream) + { + return new IdServerConfigurationSerializer(target, stream); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractButtonStateColors.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractButtonStateColors.java new file mode 100644 index 00000000..0ecf3e84 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractButtonStateColors.java @@ -0,0 +1,132 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.cxbutton.core.CxButtonStateColors; +import com.io7m.cxbutton.core.CxColor; + +import java.util.Map; +import java.util.Objects; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +abstract class IdC1AbstractButtonStateColors + implements BTElementHandlerType +{ + private final String semantic; + private IdC1Color bodyColor; + private IdC1Color borderColor; + private IdC1Color embossEColor; + private IdC1Color embossWColor; + private IdC1Color embossSColor; + private IdC1Color embossNColor; + private IdC1Color textColor; + + IdC1AbstractButtonStateColors( + final String inSemantic, + final BTElementParsingContextType context) + { + this.semantic = + Objects.requireNonNull(inSemantic, "semantic"); + } + + @Override + public final Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("BodyColor"), IdC1BodyColor::new), + entry(qName("BorderColor"), IdC1BorderColor::new), + entry(qName("EmbossEColor"), IdC1EmbossEColor::new), + entry(qName("EmbossWColor"), IdC1EmbossWColor::new), + entry(qName("EmbossSColor"), IdC1EmbossSColor::new), + entry(qName("EmbossNColor"), IdC1EmbossNColor::new), + entry(qName("TextColor"), IdC1TextColor::new) + ); + } + + @Override + public final void onChildValueProduced( + final BTElementParsingContextType context, + final IdC1Color color) + { + switch (color.semantic()) { + case "BodyColor" -> { + this.bodyColor = color; + } + case "BorderColor" -> { + this.borderColor = color; + } + case "EmbossEColor" -> { + this.embossEColor = color; + } + case "EmbossWColor" -> { + this.embossWColor = color; + } + case "EmbossSColor" -> { + this.embossSColor = color; + } + case "EmbossNColor" -> { + this.embossNColor = color; + } + case "TextColor" -> { + this.textColor = color; + } + default -> { + throw new IllegalArgumentException( + "Unrecognized color semantic: %s".formatted(color.semantic()) + ); + } + } + } + + @Override + public final IdC1ButtonStateColors onElementFinished( + final BTElementParsingContextType context) + { + return new IdC1ButtonStateColors( + this.semantic, + new CxButtonStateColors( + cx(this.textColor), + cx(this.bodyColor), + cx(this.borderColor), + cx(this.embossEColor), + cx(this.embossNColor), + cx(this.embossSColor), + cx(this.embossWColor) + ) + ); + } + + private static CxColor cx( + final IdC1Color c) + { + final var cc = c.color(); + return new CxColor( + cc.red(), + cc.green(), + cc.blue() + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractColor.java new file mode 100644 index 00000000..532b36bc --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractColor.java @@ -0,0 +1,63 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdColor; +import org.xml.sax.Attributes; + +import java.util.Objects; + +abstract class IdC1AbstractColor + implements BTElementHandlerType +{ + private final String semantic; + private IdC1Color result; + + IdC1AbstractColor( + final String inSemantic, + final BTElementParsingContextType context) + { + this.semantic = + Objects.requireNonNull(inSemantic, "semantic"); + } + + @Override + public final void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = + new IdC1Color( + this.semantic, + new IdColor( + Double.parseDouble(attributes.getValue("Red")), + Double.parseDouble(attributes.getValue("Green")), + Double.parseDouble(attributes.getValue("Blue")) + ) + ); + } + + @Override + public final IdC1Color onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractHTTPService.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractHTTPService.java new file mode 100644 index 00000000..0848e957 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractHTTPService.java @@ -0,0 +1,115 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerHTTPServiceConfiguration; +import com.io7m.idstore.tls.IdTLSConfigurationType; +import com.io7m.idstore.tls.IdTLSDisabled; +import com.io7m.idstore.tls.IdTLSEnabled; +import org.xml.sax.Attributes; + +import java.net.URI; +import java.util.Map; +import java.util.Objects; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.tlsQName; +import static java.util.Map.entry; + +abstract class IdC1AbstractHTTPService + implements BTElementHandlerType +{ + private final String semantic; + private String listenAddress; + private int listenPort; + private URI externalAddress; + private IdTLSConfigurationType tls; + + IdC1AbstractHTTPService( + final String inSemantic, + final BTElementParsingContextType context) + { + this.semantic = + Objects.requireNonNull(inSemantic, "semantic"); + } + + @Override + public final Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(tlsQName("TLSEnabled"), IdC1TLSEnabled::new), + entry(tlsQName("TLSDisabled"), IdC1TLSDisabled::new) + ); + } + + @Override + public final void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + throws Exception + { + switch (result) { + case final IdTLSEnabled s -> { + this.tls = s; + } + case final IdTLSDisabled s -> { + this.tls = s; + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public final void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.listenAddress = + attributes.getValue("ListenAddress"); + this.listenPort = + Integer.parseUnsignedInt(attributes.getValue("ListenPort")); + this.externalAddress = + URI.create(attributes.getValue("ExternalURI")); + } + + @Override + public final IdC1HTTPServiceConfiguration onElementFinished( + final BTElementParsingContextType context) + throws Exception + { + return new IdC1HTTPServiceConfiguration( + this.semantic, + new IdServerHTTPServiceConfiguration( + this.listenAddress, + this.listenPort, + this.externalAddress, + this.tls + ) + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractTLSStore.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractTLSStore.java new file mode 100644 index 00000000..6a5a3c34 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1AbstractTLSStore.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.tls.IdTLSStoreConfiguration; +import org.xml.sax.Attributes; + +import java.nio.file.Path; +import java.util.Objects; + +abstract class IdC1AbstractTLSStore + implements BTElementHandlerType +{ + private final String semantic; + private IdTLSStoreConfiguration result; + + IdC1AbstractTLSStore( + final String inSemantic, + final BTElementParsingContextType context) + { + this.semantic = + Objects.requireNonNull(inSemantic, "semantic"); + } + + @Override + public final void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = + new IdTLSStoreConfiguration( + attributes.getValue("Type"), + attributes.getValue("Provider"), + attributes.getValue("Password"), + Path.of(attributes.getValue("File")) + ); + } + + @Override + public final IdC1StoreConfiguration onElementFinished( + final BTElementParsingContextType context) + throws Exception + { + return new IdC1StoreConfiguration(this.semantic, this.result); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BodyColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BodyColor.java new file mode 100644 index 00000000..1ea82e35 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BodyColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1BodyColor + extends IdC1AbstractColor +{ + IdC1BodyColor( + final BTElementParsingContextType context) + { + super("BodyColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BorderColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BorderColor.java new file mode 100644 index 00000000..e8a4ed9b --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1BorderColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1BorderColor + extends IdC1AbstractColor +{ + IdC1BorderColor( + final BTElementParsingContextType context) + { + super("BorderColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Branding.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Branding.java new file mode 100644 index 00000000..bf9ecc01 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Branding.java @@ -0,0 +1,102 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerBrandingConfiguration; +import com.io7m.idstore.server.api.IdServerColorScheme; +import org.xml.sax.Attributes; + +import java.nio.file.Path; +import java.util.Map; +import java.util.Optional; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdC1Branding + implements BTElementHandlerType +{ + private Optional scheme; + private String title; + private Optional logo; + private Optional loginExtra; + + IdC1Branding( + final BTElementParsingContextType context) + { + this.scheme = Optional.empty(); + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("ColorScheme"), IdC1ColorScheme::new) + ); + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.title = + attributes.getValue("ProductTitle"); + this.logo = + Optional.ofNullable(attributes.getValue("Logo")) + .map(Path::of); + this.loginExtra = + Optional.ofNullable(attributes.getValue("LoginExtra")) + .map(Path::of); + } + + @Override + public IdServerBrandingConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerBrandingConfiguration( + this.title, + this.logo, + this.loginExtra, + this.scheme + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdServerColorScheme s -> { + this.scheme = Optional.of(s); + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColors.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColors.java new file mode 100644 index 00000000..9b25c984 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColors.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.cxbutton.core.CxButtonColors; +import com.io7m.cxbutton.core.CxButtonStateColors; + +import java.util.Map; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdC1ButtonColors + implements BTElementHandlerType +{ + private CxButtonStateColors disabled; + private CxButtonStateColors enabled; + private CxButtonStateColors hover; + private CxButtonStateColors pressed; + + IdC1ButtonColors( + final BTElementParsingContextType context) + { + + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("Disabled"), IdC1ButtonColorsDisabled::new), + entry(qName("Enabled"), IdC1ButtonColorsEnabled::new), + entry(qName("Hover"), IdC1ButtonColorsHover::new), + entry(qName("Pressed"), IdC1ButtonColorsPressed::new) + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdC1ButtonStateColors c -> { + switch (c.semantic()) { + case "Disabled" -> { + this.disabled = c.colors(); + } + case "Enabled" -> { + this.enabled = c.colors(); + } + case "Pressed" -> { + this.pressed = c.colors(); + } + case "Hover" -> { + this.hover = c.colors(); + } + default -> { + throw new IllegalArgumentException( + "Unrecognized semantic: %s".formatted(c.semantic()) + ); + } + } + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public CxButtonColors onElementFinished( + final BTElementParsingContextType context) + { + return new CxButtonColors( + this.enabled, + this.disabled, + this.pressed, + this.hover + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsDisabled.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsDisabled.java new file mode 100644 index 00000000..be8845d1 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsDisabled.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1ButtonColorsDisabled + extends IdC1AbstractButtonStateColors +{ + IdC1ButtonColorsDisabled( + final BTElementParsingContextType context) + { + super("Disabled", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsEnabled.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsEnabled.java new file mode 100644 index 00000000..b5b5696e --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsEnabled.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1ButtonColorsEnabled + extends IdC1AbstractButtonStateColors +{ + IdC1ButtonColorsEnabled( + final BTElementParsingContextType context) + { + super("Enabled", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsHover.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsHover.java new file mode 100644 index 00000000..931712fa --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsHover.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1ButtonColorsHover + extends IdC1AbstractButtonStateColors +{ + IdC1ButtonColorsHover( + final BTElementParsingContextType context) + { + super("Hover", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsPressed.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsPressed.java new file mode 100644 index 00000000..a5942443 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonColorsPressed.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1ButtonColorsPressed + extends IdC1AbstractButtonStateColors +{ + IdC1ButtonColorsPressed( + final BTElementParsingContextType context) + { + super("Pressed", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonStateColors.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonStateColors.java new file mode 100644 index 00000000..964d9897 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ButtonStateColors.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.cxbutton.core.CxButtonStateColors; + +import java.util.Objects; + +record IdC1ButtonStateColors( + String semantic, + CxButtonStateColors colors) +{ + IdC1ButtonStateColors + { + Objects.requireNonNull(semantic, "semantic"); + Objects.requireNonNull(colors, "colors"); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Color.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Color.java new file mode 100644 index 00000000..0cc3dcbd --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Color.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.idstore.server.api.IdColor; + +import java.util.Objects; + +record IdC1Color( + String semantic, + IdColor color) +{ + IdC1Color + { + Objects.requireNonNull(semantic, "semantic"); + Objects.requireNonNull(color, "color"); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ColorScheme.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ColorScheme.java new file mode 100644 index 00000000..b9fbe3b5 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ColorScheme.java @@ -0,0 +1,144 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.cxbutton.core.CxButtonColors; +import com.io7m.idstore.server.api.IdServerColorScheme; + +import java.util.Map; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdC1ColorScheme + implements BTElementHandlerType +{ + private IdC1Color errorBorderColor; + private IdC1Color headerBackgroundColor; + private IdC1Color headerLinkColor; + private IdC1Color headerTextColor; + private IdC1Color mainBackgroundColor; + private IdC1Color mainLinkColor; + private IdC1Color mainMessageBorderColor; + private IdC1Color mainTableBorderColor; + private IdC1Color mainTextColor; + private CxButtonColors buttonColors; + + IdC1ColorScheme( + final BTElementParsingContextType context) + { + + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("ButtonColors"), IdC1ButtonColors::new), + entry(qName("ErrorBorderColor"), IdC1ErrorBorderColor::new), + entry(qName("HeaderBackgroundColor"), IdC1HeaderBackgroundColor::new), + entry(qName("HeaderLinkColor"), IdC1HeaderLinkColor::new), + entry(qName("HeaderTextColor"), IdC1HeaderTextColor::new), + entry(qName("MainBackgroundColor"), IdC1MainBackgroundColor::new), + entry(qName("MainLinkColor"), IdC1MainLinkColor::new), + entry(qName("MainMessageBorderColor"), IdC1MainMessageBorderColor::new), + entry(qName("MainTableBorderColor"), IdC1MainTableBorderColor::new), + entry(qName("MainTextColor"), IdC1MainTextColor::new) + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + throws Exception + { + switch (result) { + case final CxButtonColors colors -> { + this.buttonColors = colors; + } + + case final IdC1Color color -> { + switch (color.semantic()) { + case "ErrorBorderColor" -> { + this.errorBorderColor = color; + } + case "HeaderBackgroundColor" -> { + this.headerBackgroundColor = color; + } + case "HeaderLinkColor" -> { + this.headerLinkColor = color; + } + case "HeaderTextColor" -> { + this.headerTextColor = color; + } + case "MainBackgroundColor" -> { + this.mainBackgroundColor = color; + } + case "MainLinkColor" -> { + this.mainLinkColor = color; + } + case "MainMessageBorderColor" -> { + this.mainMessageBorderColor = color; + } + case "MainTableBorderColor" -> { + this.mainTableBorderColor = color; + } + case "MainTextColor" -> { + this.mainTextColor = color; + } + default -> { + throw new IllegalArgumentException( + "Unrecognized color semantic: %s".formatted(color.semantic()) + ); + } + } + } + + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public IdServerColorScheme onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerColorScheme( + this.buttonColors, + this.errorBorderColor.color(), + this.headerBackgroundColor.color(), + this.headerLinkColor.color(), + this.headerTextColor.color(), + this.mainBackgroundColor.color(), + this.mainLinkColor.color(), + this.mainMessageBorderColor.color(), + this.mainTableBorderColor.color(), + this.mainTextColor.color() + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Configuration.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Configuration.java new file mode 100644 index 00000000..cb705b60 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Configuration.java @@ -0,0 +1,145 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerBrandingConfiguration; +import com.io7m.idstore.server.api.IdServerConfigurationFile; +import com.io7m.idstore.server.api.IdServerDatabaseConfiguration; +import com.io7m.idstore.server.api.IdServerHTTPConfiguration; +import com.io7m.idstore.server.api.IdServerHistoryConfiguration; +import com.io7m.idstore.server.api.IdServerMailConfiguration; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration; +import com.io7m.idstore.server.api.IdServerPasswordExpirationConfiguration; +import com.io7m.idstore.server.api.IdServerRateLimitConfiguration; +import com.io7m.idstore.server.api.IdServerSessionConfiguration; + +import java.util.Map; +import java.util.Optional; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +/** + * The root configuration parser. + */ + +public final class IdC1Configuration + implements BTElementHandlerType +{ + private IdServerBrandingConfiguration branding; + private IdServerDatabaseConfiguration database; + private IdServerHTTPConfiguration http; + private IdServerHistoryConfiguration history; + private IdServerMailConfiguration mail; + private IdServerPasswordExpirationConfiguration passwords; + private IdServerRateLimitConfiguration rateLimit; + private IdServerSessionConfiguration sessions; + private Optional telemetry; + + /** + * The root configuration parser. + * + * @param context The context + */ + + public IdC1Configuration( + final BTElementParsingContextType context) + { + this.telemetry = Optional.empty(); + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("Branding"), IdC1Branding::new), + entry(qName("Database"), IdC1Database::new), + entry(qName("HTTPServices"), IdC1HTTPServices::new), + entry(qName("History"), IdC1History::new), + entry(qName("Mail"), IdC1Mail::new), + entry(qName("OpenTelemetry"), IdC1Telemetry::new), + entry(qName("PasswordExpiration"), IdC1PasswordExpiration::new), + entry(qName("RateLimiting"), IdC1RateLimit::new), + entry(qName("Sessions"), IdC1Sessions::new) + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdServerBrandingConfiguration c -> { + this.branding = c; + } + case final IdServerMailConfiguration c -> { + this.mail = c; + } + case final IdServerHTTPConfiguration c -> { + this.http = c; + } + case final IdServerDatabaseConfiguration c -> { + this.database = c; + } + case final IdServerHistoryConfiguration c -> { + this.history = c; + } + case final IdServerSessionConfiguration c -> { + this.sessions = c; + } + case final IdServerRateLimitConfiguration c -> { + this.rateLimit = c; + } + case final IdServerPasswordExpirationConfiguration c -> { + this.passwords = c; + } + case final IdServerOpenTelemetryConfiguration c -> { + this.telemetry = Optional.of(c); + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public IdServerConfigurationFile onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerConfigurationFile( + this.branding, + this.mail, + this.http, + this.database, + this.history, + this.sessions, + this.rateLimit, + this.passwords, + this.telemetry + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Database.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Database.java new file mode 100644 index 00000000..91cafbfa --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Database.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerDatabaseConfiguration; +import com.io7m.idstore.server.api.IdServerDatabaseKind; +import org.xml.sax.Attributes; + +import java.util.Optional; + +final class IdC1Database + implements BTElementHandlerType +{ + private IdServerDatabaseConfiguration result; + + IdC1Database( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = + new IdServerDatabaseConfiguration( + IdServerDatabaseKind.valueOf(attributes.getValue("Kind")), + attributes.getValue("OwnerRoleName"), + attributes.getValue("OwnerRolePassword"), + attributes.getValue("WorkerRolePassword"), + Optional.ofNullable(attributes.getValue("ReaderRolePassword")), + attributes.getValue("Address"), + Integer.valueOf(attributes.getValue("Port")).intValue(), + attributes.getValue("Name"), + Boolean.parseBoolean(attributes.getValue("Create")), + Boolean.parseBoolean(attributes.getValue("Upgrade")) + ); + } + + @Override + public IdServerDatabaseConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Durations.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Durations.java new file mode 100644 index 00000000..d548ec99 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Durations.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import javax.xml.datatype.DatatypeFactory; +import java.time.Duration; +import java.util.Calendar; + +final class IdC1Durations +{ + private static final DatatypeFactory DATATYPES = + DatatypeFactory.newDefaultInstance(); + + private IdC1Durations() + { + + } + + static Duration parse( + final String text) + { + final var millis = + DATATYPES.newDuration(text) + .getTimeInMillis(Calendar.getInstance()); + + return Duration.ofMillis(millis); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossEColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossEColor.java new file mode 100644 index 00000000..72d17994 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossEColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1EmbossEColor + extends IdC1AbstractColor +{ + IdC1EmbossEColor( + final BTElementParsingContextType context) + { + super("EmbossEColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossNColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossNColor.java new file mode 100644 index 00000000..b05648c9 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossNColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1EmbossNColor + extends IdC1AbstractColor +{ + IdC1EmbossNColor( + final BTElementParsingContextType context) + { + super("EmbossNColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossSColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossSColor.java new file mode 100644 index 00000000..60a47b36 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossSColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1EmbossSColor + extends IdC1AbstractColor +{ + IdC1EmbossSColor( + final BTElementParsingContextType context) + { + super("EmbossSColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossWColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossWColor.java new file mode 100644 index 00000000..aa560b50 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1EmbossWColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1EmbossWColor + extends IdC1AbstractColor +{ + IdC1EmbossWColor( + final BTElementParsingContextType context) + { + super("EmbossWColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ErrorBorderColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ErrorBorderColor.java new file mode 100644 index 00000000..590c218d --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1ErrorBorderColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1ErrorBorderColor + extends IdC1AbstractColor +{ + IdC1ErrorBorderColor( + final BTElementParsingContextType context) + { + super("ErrorBorderColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPService.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPService.java new file mode 100644 index 00000000..91fea439 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPService.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerHTTPConfiguration; + +final class IdC1HTTPService + implements BTElementHandlerType +{ + private IdServerHTTPConfiguration result; + + IdC1HTTPService( + final BTElementParsingContextType context) + { + + } + + @Override + public IdServerHTTPConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceAdminAPI.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceAdminAPI.java new file mode 100644 index 00000000..d11d25f4 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceAdminAPI.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HTTPServiceAdminAPI + extends IdC1AbstractHTTPService +{ + IdC1HTTPServiceAdminAPI( + final BTElementParsingContextType context) + { + super("AdminAPI", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceConfiguration.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceConfiguration.java new file mode 100644 index 00000000..289b4c6b --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceConfiguration.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.idstore.server.api.IdServerHTTPServiceConfiguration; + +import java.util.Objects; + +record IdC1HTTPServiceConfiguration( + String semantic, + IdServerHTTPServiceConfiguration configuration) +{ + IdC1HTTPServiceConfiguration + { + Objects.requireNonNull(semantic, "semantic"); + Objects.requireNonNull(configuration, "configuration"); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserAPI.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserAPI.java new file mode 100644 index 00000000..8f502e07 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserAPI.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HTTPServiceUserAPI + extends IdC1AbstractHTTPService +{ + IdC1HTTPServiceUserAPI( + final BTElementParsingContextType context) + { + super("UserAPI", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserView.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserView.java new file mode 100644 index 00000000..0b788c26 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServiceUserView.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HTTPServiceUserView + extends IdC1AbstractHTTPService +{ + IdC1HTTPServiceUserView( + final BTElementParsingContextType context) + { + super("UserView", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServices.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServices.java new file mode 100644 index 00000000..ff1b15d7 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HTTPServices.java @@ -0,0 +1,98 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerHTTPConfiguration; + +import java.util.Map; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdC1HTTPServices + implements BTElementHandlerType +{ + private IdC1HTTPServiceConfiguration userAPI; + private IdC1HTTPServiceConfiguration userView; + private IdC1HTTPServiceConfiguration adminAPI; + + IdC1HTTPServices( + final BTElementParsingContextType context) + { + + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("HTTPServiceAdminAPI"), IdC1HTTPServiceAdminAPI::new), + entry(qName("HTTPServiceUserAPI"), IdC1HTTPServiceUserAPI::new), + entry(qName("HTTPServiceUserView"), IdC1HTTPServiceUserView::new) + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdC1HTTPServiceConfiguration s -> { + switch (s.semantic()) { + case "UserAPI" -> { + this.userAPI = s; + } + case "UserView" -> { + this.userView = s; + } + case "AdminAPI" -> { + this.adminAPI = s; + } + default -> { + throw new IllegalArgumentException( + "Unrecognized semantic: %s".formatted(s.semantic()) + ); + } + } + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public IdServerHTTPConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerHTTPConfiguration( + this.adminAPI.configuration(), + this.userAPI.configuration(), + this.userView.configuration() + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderBackgroundColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderBackgroundColor.java new file mode 100644 index 00000000..30c27d27 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderBackgroundColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HeaderBackgroundColor + extends IdC1AbstractColor +{ + IdC1HeaderBackgroundColor( + final BTElementParsingContextType context) + { + super("HeaderBackgroundColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderLinkColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderLinkColor.java new file mode 100644 index 00000000..a0bf4cf2 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderLinkColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HeaderLinkColor + extends IdC1AbstractColor +{ + IdC1HeaderLinkColor( + final BTElementParsingContextType context) + { + super("HeaderLinkColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderTextColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderTextColor.java new file mode 100644 index 00000000..f7297bea --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1HeaderTextColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1HeaderTextColor + extends IdC1AbstractColor +{ + IdC1HeaderTextColor( + final BTElementParsingContextType context) + { + super("HeaderTextColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1History.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1History.java new file mode 100644 index 00000000..5deb6297 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1History.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerHistoryConfiguration; +import org.xml.sax.Attributes; + +final class IdC1History + implements BTElementHandlerType +{ + private IdServerHistoryConfiguration result; + + IdC1History( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = + new IdServerHistoryConfiguration( + Integer.parseUnsignedInt( + attributes.getValue("UserLoginHistoryLimit")), + Integer.parseUnsignedInt( + attributes.getValue("AdminLoginHistoryLimit")) + ); + } + + @Override + public IdServerHistoryConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Mail.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Mail.java new file mode 100644 index 00000000..ef434ee9 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Mail.java @@ -0,0 +1,105 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerMailAuthenticationConfiguration; +import com.io7m.idstore.server.api.IdServerMailConfiguration; +import com.io7m.idstore.server.api.IdServerMailTransportConfigurationType; +import org.xml.sax.Attributes; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; + +final class IdC1Mail + implements BTElementHandlerType +{ + private IdServerMailTransportConfigurationType transport; + private Optional authentication; + private String senderAddress; + private Duration verificationExpiration; + + IdC1Mail( + final BTElementParsingContextType context) + { + this.authentication = Optional.empty(); + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + Map.entry(qName("SMTP"), IdC1SMTP::new), + Map.entry(qName("SMTPTLS"), IdC1SMTPTLS::new), + Map.entry(qName("SMTPS"), IdC1SMTPS::new), + Map.entry(qName("MailAuthentication"), IdC1MailAuthentication::new) + ); + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.senderAddress = + attributes.getValue("SenderAddress"); + this.verificationExpiration = + IdC1Durations.parse(attributes.getValue("VerificationExpiration")); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdServerMailTransportConfigurationType c -> { + this.transport = c; + } + case final IdServerMailAuthenticationConfiguration c -> { + this.authentication = Optional.of(c); + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public IdServerMailConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerMailConfiguration( + this.transport, + this.authentication, + this.senderAddress, + this.verificationExpiration + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MailAuthentication.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MailAuthentication.java new file mode 100644 index 00000000..1d5e9f9d --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MailAuthentication.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerMailAuthenticationConfiguration; +import org.xml.sax.Attributes; + +final class IdC1MailAuthentication + implements BTElementHandlerType +{ + private IdServerMailAuthenticationConfiguration result; + + IdC1MailAuthentication( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = + new IdServerMailAuthenticationConfiguration( + attributes.getValue("Username"), + attributes.getValue("Password") + ); + } + + @Override + public IdServerMailAuthenticationConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainBackgroundColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainBackgroundColor.java new file mode 100644 index 00000000..cf5cbffa --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainBackgroundColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1MainBackgroundColor + extends IdC1AbstractColor +{ + IdC1MainBackgroundColor( + final BTElementParsingContextType context) + { + super("MainBackgroundColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainLinkColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainLinkColor.java new file mode 100644 index 00000000..9eb1a307 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainLinkColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1MainLinkColor + extends IdC1AbstractColor +{ + IdC1MainLinkColor( + final BTElementParsingContextType context) + { + super("MainLinkColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainMessageBorderColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainMessageBorderColor.java new file mode 100644 index 00000000..896c617f --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainMessageBorderColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1MainMessageBorderColor + extends IdC1AbstractColor +{ + IdC1MainMessageBorderColor( + final BTElementParsingContextType context) + { + super("MainMessageBorderColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTableBorderColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTableBorderColor.java new file mode 100644 index 00000000..d46688f3 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTableBorderColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1MainTableBorderColor + extends IdC1AbstractColor +{ + IdC1MainTableBorderColor( + final BTElementParsingContextType context) + { + super("MainTableBorderColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTextColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTextColor.java new file mode 100644 index 00000000..bbe70f0e --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1MainTextColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1MainTextColor + extends IdC1AbstractColor +{ + IdC1MainTextColor( + final BTElementParsingContextType context) + { + super("MainTextColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Names.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Names.java new file mode 100644 index 00000000..aeee6250 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Names.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTQualifiedName; + +/** + * Qualified names. + */ + +public final class IdC1Names +{ + private IdC1Names() + { + + } + + /** + * @param name The local name + * + * @return A qualified name in the configuration 1 namespace + */ + + public static BTQualifiedName qName( + final String name) + { + return BTQualifiedName.of( + "urn:com.io7m.idstore:configuration:1", + name + ); + } + + /** + * @param name The local name + * + * @return A qualified name in the TLS 1 namespace + */ + + public static BTQualifiedName tlsQName( + final String name) + { + return BTQualifiedName.of( + "urn:com.io7m.idstore.tls:1", + name + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1PasswordExpiration.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1PasswordExpiration.java new file mode 100644 index 00000000..edf95850 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1PasswordExpiration.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerPasswordExpirationConfiguration; +import org.xml.sax.Attributes; + +import java.util.Optional; + +final class IdC1PasswordExpiration + implements BTElementHandlerType +{ + private IdServerPasswordExpirationConfiguration result; + + IdC1PasswordExpiration( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = + new IdServerPasswordExpirationConfiguration( + Optional.ofNullable( + attributes.getValue("UserPasswordValidityDuration")) + .map(IdC1Durations::parse), + Optional.ofNullable( + attributes.getValue("AdminPasswordValidityDuration")) + .map(IdC1Durations::parse) + ); + } + + @Override + public IdServerPasswordExpirationConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1RateLimit.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1RateLimit.java new file mode 100644 index 00000000..35c92b32 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1RateLimit.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerRateLimitConfiguration; +import org.xml.sax.Attributes; + +import java.time.Duration; +import java.util.Optional; + +final class IdC1RateLimit + implements BTElementHandlerType +{ + private IdServerRateLimitConfiguration result; + + IdC1RateLimit( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes a) + { + this.result = + new IdServerRateLimitConfiguration( + requiredDuration(a, "EmailVerificationRateLimit"), + requiredDuration(a, "PasswordResetRateLimit"), + optionalDuration(a, "UserLoginRateLimit", Duration.ofSeconds(5L)), + optionalDuration(a, "UserLoginDelay", Duration.ofSeconds(1L)), + optionalDuration(a, "AdminLoginRateLimit", Duration.ofSeconds(5L)), + optionalDuration(a, "AdminLoginDelay", Duration.ofSeconds(1L)) + ); + } + + private static Duration requiredDuration( + final Attributes attributes, + final String name) + { + return IdC1Durations.parse(attributes.getValue(name)); + } + + private static Duration optionalDuration( + final Attributes attributes, + final String name, + final Duration otherwise) + { + return Optional.ofNullable(attributes.getValue(name)) + .map(IdC1Durations::parse) + .orElse(otherwise); + } + + @Override + public IdServerRateLimitConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTP.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTP.java new file mode 100644 index 00000000..1694878e --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTP.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerMailTransportSMTP; +import org.xml.sax.Attributes; + +final class IdC1SMTP + implements BTElementHandlerType +{ + private IdServerMailTransportSMTP result; + + IdC1SMTP( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = new IdServerMailTransportSMTP( + attributes.getValue("Host"), + Integer.parseUnsignedInt(attributes.getValue("Port")) + ); + } + + @Override + public IdServerMailTransportSMTP onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPS.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPS.java new file mode 100644 index 00000000..8dae55a2 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPS.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerMailTransportSMTPS; +import org.xml.sax.Attributes; + +final class IdC1SMTPS + implements BTElementHandlerType +{ + private IdServerMailTransportSMTPS result; + + IdC1SMTPS( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = new IdServerMailTransportSMTPS( + attributes.getValue("Host"), + Integer.parseUnsignedInt(attributes.getValue("Port")) + ); + } + + @Override + public IdServerMailTransportSMTPS onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPTLS.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPTLS.java new file mode 100644 index 00000000..76e0c677 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1SMTPTLS.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerMailTransportSMTP_TLS; +import org.xml.sax.Attributes; + +final class IdC1SMTPTLS + implements BTElementHandlerType +{ + private IdServerMailTransportSMTP_TLS result; + + IdC1SMTPTLS( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + throws Exception + { + this.result = new IdServerMailTransportSMTP_TLS( + attributes.getValue("Host"), + Integer.parseUnsignedInt(attributes.getValue("Port")) + ); + } + + @Override + public IdServerMailTransportSMTP_TLS onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Sessions.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Sessions.java new file mode 100644 index 00000000..41cfc4b4 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Sessions.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerSessionConfiguration; +import org.xml.sax.Attributes; + +final class IdC1Sessions + implements BTElementHandlerType +{ + private IdServerSessionConfiguration result; + + IdC1Sessions( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = + new IdServerSessionConfiguration( + IdC1Durations.parse( + attributes.getValue("UserSessionExpiration")), + IdC1Durations.parse( + attributes.getValue("AdminSessionExpiration")) + ); + } + + @Override + public IdServerSessionConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1StoreConfiguration.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1StoreConfiguration.java new file mode 100644 index 00000000..4a63cf07 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1StoreConfiguration.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.idstore.tls.IdTLSStoreConfiguration; + +import java.util.Objects; + +record IdC1StoreConfiguration( + String semantic, + IdTLSStoreConfiguration configuration) +{ + IdC1StoreConfiguration + { + Objects.requireNonNull(semantic, "semantic"); + Objects.requireNonNull(configuration, "configuration"); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSDisabled.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSDisabled.java new file mode 100644 index 00000000..92a5a11f --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSDisabled.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.tls.IdTLSDisabled; + +final class IdC1TLSDisabled + implements BTElementHandlerType +{ + IdC1TLSDisabled( + final BTElementParsingContextType context) + { + + } + + @Override + public IdTLSDisabled onElementFinished( + final BTElementParsingContextType context) + throws Exception + { + return IdTLSDisabled.TLS_DISABLED; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSEnabled.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSEnabled.java new file mode 100644 index 00000000..4782d2a0 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSEnabled.java @@ -0,0 +1,93 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.tls.IdTLSEnabled; + +import java.util.Map; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.tlsQName; +import static java.util.Map.entry; + +final class IdC1TLSEnabled + implements BTElementHandlerType +{ + private IdC1StoreConfiguration keyStore; + private IdC1StoreConfiguration trustStore; + + IdC1TLSEnabled( + final BTElementParsingContextType context) + { + + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(tlsQName("KeyStore"), IdC1TLSKeyStore::new), + entry(tlsQName("TrustStore"), IdC1TLSTrustStore::new) + ); + } + + @Override + public void onChildValueProduced( + final BTElementParsingContextType context, + final Object result) + { + switch (result) { + case final IdC1StoreConfiguration s -> { + switch (s.semantic()) { + case "KeyStore" -> { + this.keyStore = s; + } + case "TrustStore" -> { + this.trustStore = s; + } + default -> { + throw new IllegalArgumentException( + "Unrecognized semantic: %s".formatted(s.semantic()) + ); + } + } + } + default -> { + throw new IllegalArgumentException( + "Unrecognized element: %s".formatted(result) + ); + } + } + } + + @Override + public IdTLSEnabled onElementFinished( + final BTElementParsingContextType context) + throws Exception + { + return new IdTLSEnabled( + this.keyStore.configuration(), + this.trustStore.configuration() + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSKeyStore.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSKeyStore.java new file mode 100644 index 00000000..8027833b --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSKeyStore.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1TLSKeyStore + extends IdC1AbstractTLSStore +{ + IdC1TLSKeyStore( + final BTElementParsingContextType context) + { + super("KeyStore", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSTrustStore.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSTrustStore.java new file mode 100644 index 00000000..9191d056 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TLSTrustStore.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1TLSTrustStore + extends IdC1AbstractTLSStore +{ + IdC1TLSTrustStore( + final BTElementParsingContextType context) + { + super("TrustStore", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Telemetry.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Telemetry.java new file mode 100644 index 00000000..9ba86330 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1Telemetry.java @@ -0,0 +1,81 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerConstructorType; +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.blackthorne.core.BTQualifiedName; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration; +import org.xml.sax.Attributes; + +import java.util.Map; +import java.util.Optional; + +import static com.io7m.idstore.server.service.configuration.v1.IdC1Names.qName; +import static java.util.Map.entry; + +final class IdC1Telemetry + implements BTElementHandlerType +{ + private String serviceName; + private Optional logs; + private Optional metrics; + private Optional traces; + + IdC1Telemetry( + final BTElementParsingContextType context) + { + this.logs = Optional.empty(); + this.metrics = Optional.empty(); + this.traces = Optional.empty(); + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.serviceName = + attributes.getValue("LogicalServiceName"); + } + + @Override + public Map> + onChildHandlersRequested( + final BTElementParsingContextType context) + { + return Map.ofEntries( + entry(qName("Logs"), IdC1TelemetryLogs::new), + entry(qName("Metrics"), IdC1TelemetryMetrics::new), + entry(qName("Traces"), IdC1TelemetryTraces::new) + ); + } + + @Override + public IdServerOpenTelemetryConfiguration onElementFinished( + final BTElementParsingContextType context) + { + return new IdServerOpenTelemetryConfiguration( + this.serviceName, + this.logs, + this.metrics, + this.traces + ); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryLogs.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryLogs.java new file mode 100644 index 00000000..67da3540 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryLogs.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdLogs; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdOTLPProtocol; +import org.xml.sax.Attributes; + +import java.net.URI; + +final class IdC1TelemetryLogs + implements BTElementHandlerType +{ + private IdLogs result; + + IdC1TelemetryLogs( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = new IdLogs( + URI.create(attributes.getValue("Endpoint")), + IdOTLPProtocol.valueOf(attributes.getValue("Protocol")) + ); + } + + @Override + public IdLogs onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryMetrics.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryMetrics.java new file mode 100644 index 00000000..6303c2a3 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryMetrics.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdMetrics; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdOTLPProtocol; +import org.xml.sax.Attributes; + +import java.net.URI; + +final class IdC1TelemetryMetrics + implements BTElementHandlerType +{ + private IdMetrics result; + + IdC1TelemetryMetrics( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = new IdMetrics( + URI.create(attributes.getValue("Endpoint")), + IdOTLPProtocol.valueOf(attributes.getValue("Protocol")) + ); + } + + @Override + public IdMetrics onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryTraces.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryTraces.java new file mode 100644 index 00000000..dc4a6e45 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TelemetryTraces.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementHandlerType; +import com.io7m.blackthorne.core.BTElementParsingContextType; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdOTLPProtocol; +import com.io7m.idstore.server.api.IdServerOpenTelemetryConfiguration.IdTraces; +import org.xml.sax.Attributes; + +import java.net.URI; + +final class IdC1TelemetryTraces + implements BTElementHandlerType +{ + private IdTraces result; + + IdC1TelemetryTraces( + final BTElementParsingContextType context) + { + + } + + @Override + public void onElementStart( + final BTElementParsingContextType context, + final Attributes attributes) + { + this.result = new IdTraces( + URI.create(attributes.getValue("Endpoint")), + IdOTLPProtocol.valueOf(attributes.getValue("Protocol")) + ); + } + + @Override + public IdTraces onElementFinished( + final BTElementParsingContextType context) + { + return this.result; + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TextColor.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TextColor.java new file mode 100644 index 00000000..6bd671dd --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/IdC1TextColor.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.configuration.v1; + +import com.io7m.blackthorne.core.BTElementParsingContextType; + +final class IdC1TextColor + extends IdC1AbstractColor +{ + IdC1TextColor( + final BTElementParsingContextType context) + { + super("TextColor", context); + } +} diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/package-info.java b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/package-info.java new file mode 100644 index 00000000..0ccd700d --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/java/com/io7m/idstore/server/service/configuration/v1/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Identity server (Server configuration service [v1]) + */ + +@Version("1.0.0") +package com.io7m.idstore.server.service.configuration.v1; + +import org.osgi.annotation.versioning.Version; diff --git a/com.io7m.idstore.server.service.configuration/src/main/java/module-info.java b/com.io7m.idstore.server.service.configuration/src/main/java/module-info.java index d53a3b90..71b8d0dd 100644 --- a/com.io7m.idstore.server.service.configuration/src/main/java/module-info.java +++ b/com.io7m.idstore.server.service.configuration/src/main/java/module-info.java @@ -23,17 +23,18 @@ requires static org.osgi.annotation.versioning; requires static org.osgi.annotation.bundle; + requires com.io7m.idstore.database.api; requires com.io7m.idstore.model; requires com.io7m.idstore.server.api; requires com.io7m.idstore.server.service.telemetry.api; - requires com.io7m.idstore.database.api; + requires com.io7m.idstore.tls; + requires com.io7m.anethum.api; + requires com.io7m.blackthorne.core; + requires com.io7m.blackthorne.jxe; requires com.io7m.cxbutton.core; requires com.io7m.repetoir.core; - requires jakarta.xml.bind; - - opens com.io7m.idstore.server.service.configuration.jaxb - to jakarta.xml.bind; + requires com.io7m.jxe.core; exports com.io7m.idstore.server.service.configuration; } diff --git a/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration.xsd b/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration-1.xsd similarity index 96% rename from com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration.xsd rename to com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration-1.xsd index ce202150..68848fc0 100644 --- a/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration.xsd +++ b/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/configuration-1.xsd @@ -1,9 +1,28 @@ + + + + @@ -461,6 +480,11 @@ + + + + diff --git a/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/tls-1.xsd b/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/tls-1.xsd new file mode 100644 index 00000000..98738103 --- /dev/null +++ b/com.io7m.idstore.server.service.configuration/src/main/resources/com/io7m/idstore/server/service/configuration/tls-1.xsd @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com.io7m.idstore.server.service.mail/pom.xml b/com.io7m.idstore.server.service.mail/pom.xml index 1723828e..0623f26e 100644 --- a/com.io7m.idstore.server.service.mail/pom.xml +++ b/com.io7m.idstore.server.service.mail/pom.xml @@ -57,7 +57,7 @@ jakarta.activation-api - com.sun.mail + org.eclipse.angus jakarta.mail diff --git a/com.io7m.idstore.server.service.tls/pom.xml b/com.io7m.idstore.server.service.tls/pom.xml new file mode 100644 index 00000000..388aa46d --- /dev/null +++ b/com.io7m.idstore.server.service.tls/pom.xml @@ -0,0 +1,73 @@ + + + + + 4.0.0 + + + com.io7m.idstore + com.io7m.idstore + 1.0.0-SNAPSHOT + + + com.io7m.idstore.server.service.tls + + com.io7m.idstore.server.service.tls + Identity server (Server TLS service) + https://www.io7m.com/software/idstore + + + + ${project.groupId} + com.io7m.idstore.error_codes + ${project.version} + + + ${project.groupId} + com.io7m.idstore.tls + ${project.version} + + + ${project.groupId} + com.io7m.idstore.strings + ${project.version} + + + ${project.groupId} + com.io7m.idstore.server.service.telemetry.api + ${project.version} + + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-context + + + + com.io7m.jxtrand + com.io7m.jxtrand.api + + + com.io7m.repetoir + com.io7m.repetoir.core + + + + org.osgi + org.osgi.annotation.bundle + provided + + + org.osgi + org.osgi.annotation.versioning + provided + + + + diff --git a/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextService.java b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextService.java new file mode 100644 index 00000000..a32e3d61 --- /dev/null +++ b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextService.java @@ -0,0 +1,171 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.tls; + + +import com.io7m.idstore.error_codes.IdException; +import com.io7m.idstore.error_codes.IdStandardErrorCodes; +import com.io7m.idstore.server.service.telemetry.api.IdServerTelemetryServiceType; +import com.io7m.idstore.strings.IdStringConstants; +import com.io7m.idstore.strings.IdStrings; +import com.io7m.idstore.tls.IdTLSContext; +import com.io7m.idstore.tls.IdTLSStoreConfiguration; +import com.io7m.repetoir.core.RPServiceDirectoryType; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import static com.io7m.idstore.server.service.telemetry.api.IdServerTelemetryServiceType.recordSpanException; + +/** + * The TLS context service. + */ + +public final class IdTLSContextService + implements IdTLSContextServiceType +{ + private final ConcurrentHashMap.KeySetView contexts; + private final IdServerTelemetryServiceType telemetry; + private final IdStrings strings; + + private IdTLSContextService( + final IdServerTelemetryServiceType inTelemetry, + final IdStrings inStrings) + { + this.telemetry = + Objects.requireNonNull(inTelemetry, "telemetry"); + this.strings = + Objects.requireNonNull(inStrings, "strings"); + this.contexts = + ConcurrentHashMap.newKeySet(); + } + + @Override + public String toString() + { + return "[IdTLSContextService 0x%x]" + .formatted(Integer.valueOf(this.hashCode())); + } + + /** + * @param services The service directory + * + * @return A new TLS context service + */ + + public static IdTLSContextServiceType createService( + final RPServiceDirectoryType services) + { + return new IdTLSContextService( + services.requireService(IdServerTelemetryServiceType.class), + services.requireService(IdStrings.class) + ); + } + + @Override + public IdTLSContext create( + final String user, + final IdTLSStoreConfiguration keyStoreConfiguration, + final IdTLSStoreConfiguration trustStoreConfiguration) + throws IdException + { + try { + final var newContext = + IdTLSContext.create( + user, + keyStoreConfiguration, + trustStoreConfiguration + ); + this.contexts.add(newContext); + return newContext; + } catch (final IOException e) { + throw errorIO(this.strings, e); + } catch (final GeneralSecurityException e) { + throw errorSecurity(e); + } + } + + @Override + public void reload() + { + final var span = + this.telemetry.tracer() + .spanBuilder("ReloadTLSContexts") + .startSpan(); + + try (var ignored = span.makeCurrent()) { + for (final var context : this.contexts) { + this.reloadContext(context); + } + } finally { + span.end(); + } + } + + private void reloadContext( + final IdTLSContext context) + { + final var span = + this.telemetry.tracer() + .spanBuilder("ReloadTLSContext") + .startSpan(); + + try (var ignored = span.makeCurrent()) { + context.reload(); + } catch (final Throwable e) { + recordSpanException(e); + } finally { + span.end(); + } + } + + @Override + public String description() + { + return "The TLS context service."; + } + + private static IdException errorIO( + final IdStrings strings, + final IOException e) + { + return new IdException( + strings.format(IdStringConstants.ERROR_IO), + e, + IdStandardErrorCodes.IO_ERROR, + Map.of(), + Optional.empty() + ); + } + + private static IdException errorSecurity( + final GeneralSecurityException e) + { + return new IdException( + e.getMessage(), + e, + IdStandardErrorCodes.IO_ERROR, + Map.of(), + Optional.empty() + ); + } +} diff --git a/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextServiceType.java b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextServiceType.java new file mode 100644 index 00000000..55fd6928 --- /dev/null +++ b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/IdTLSContextServiceType.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.server.service.tls; + + +import com.io7m.idstore.error_codes.IdException; +import com.io7m.idstore.tls.IdTLSContext; +import com.io7m.idstore.tls.IdTLSStoreConfiguration; +import com.io7m.repetoir.core.RPServiceType; + +/** + * A service that provides preconfigured TLS contexts. + */ + +public interface IdTLSContextServiceType + extends RPServiceType +{ + /** + * Create a TLS context. + * + * @param user The user of this context (such as "HealthService", "AdminService", etc) + * @param keyStoreConfiguration The keystore configuration + * @param trustStoreConfiguration The truststore configuration + * + * @return A TLS context + * + * @throws IdException On errors + */ + + IdTLSContext create( + String user, + IdTLSStoreConfiguration keyStoreConfiguration, + IdTLSStoreConfiguration trustStoreConfiguration) + throws IdException; + + /** + * Reload all TLS contexts. Primarily used to reload short-lived certificates + * issued using the ACME protocol. + */ + + void reload(); +} diff --git a/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/package-info.java b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/package-info.java new file mode 100644 index 00000000..2a1c5a45 --- /dev/null +++ b/com.io7m.idstore.server.service.tls/src/main/java/com/io7m/idstore/server/service/tls/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Identity server (Server TLS service) + */ + +@Export +@Version("1.0.0") +package com.io7m.idstore.server.service.tls; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/com.io7m.idstore.server.service.tls/src/main/java/module-info.java b/com.io7m.idstore.server.service.tls/src/main/java/module-info.java new file mode 100644 index 00000000..5fad654b --- /dev/null +++ b/com.io7m.idstore.server.service.tls/src/main/java/module-info.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Identity server (Server TLS service) + */ + +module com.io7m.idstore.server.service.tls +{ + requires static org.osgi.annotation.bundle; + requires static org.osgi.annotation.versioning; + + requires com.io7m.idstore.error_codes; + requires com.io7m.idstore.server.service.telemetry.api; + requires com.io7m.idstore.strings; + requires com.io7m.idstore.tls; + + requires com.io7m.repetoir.core; + + exports com.io7m.idstore.server.service.tls; +} diff --git a/com.io7m.idstore.server.user_v1/pom.xml b/com.io7m.idstore.server.user_v1/pom.xml index 2885103e..9eaa2bf6 100644 --- a/com.io7m.idstore.server.user_v1/pom.xml +++ b/com.io7m.idstore.server.user_v1/pom.xml @@ -54,6 +54,11 @@ com.io7m.idstore.server.service.reqlimit ${project.version} + + ${project.groupId} + com.io7m.idstore.server.service.tls + ${project.version} + ${project.groupId} com.io7m.idstore.protocol.api @@ -109,6 +114,11 @@ com.io7m.idstore.strings ${project.version} + + ${project.groupId} + com.io7m.idstore.tls + ${project.version} + com.io7m.jxtrand @@ -146,6 +156,10 @@ io.helidon.common helidon-common-parameters + + io.helidon.common + helidon-common-tls + org.osgi diff --git a/com.io7m.idstore.server.user_v1/src/main/java/com/io7m/idstore/server/user_v1/IdU1Server.java b/com.io7m.idstore.server.user_v1/src/main/java/com/io7m/idstore/server/user_v1/IdU1Server.java index bde844e5..1301cb49 100644 --- a/com.io7m.idstore.server.user_v1/src/main/java/com/io7m/idstore/server/user_v1/IdU1Server.java +++ b/com.io7m.idstore.server.user_v1/src/main/java/com/io7m/idstore/server/user_v1/IdU1Server.java @@ -21,7 +21,10 @@ import com.io7m.idstore.server.service.clock.IdServerClock; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.telemetry.api.IdMetricsServiceType; +import com.io7m.idstore.server.service.tls.IdTLSContextServiceType; +import com.io7m.idstore.tls.IdTLSEnabled; import com.io7m.repetoir.core.RPServiceDirectoryType; +import io.helidon.common.tls.TlsConfig; import io.helidon.webserver.WebServer; import io.helidon.webserver.WebServerConfig; import io.helidon.webserver.http.HttpRouting; @@ -65,6 +68,8 @@ public static WebServer createUserAPIServer( { final var configurationService = services.requireService(IdServerConfigurationService.class); + final var tlsService = + services.requireService(IdTLSContextServiceType.class); final var configuration = configurationService.configuration(); final var httpConfig = @@ -89,8 +94,27 @@ public static WebServer createUserAPIServer( .get("/health", new IdU1HandlerHealth(services)) .build(); + final var webServerBuilder = + WebServerConfig.builder(); + + if (httpConfig.tlsConfiguration() instanceof final IdTLSEnabled enabled) { + final var tlsContext = + tlsService.create( + "UserAPI", + enabled.keyStore(), + enabled.trustStore() + ); + + webServerBuilder.tls( + TlsConfig.builder() + .enabled(true) + .sslContext(tlsContext.context()) + .build() + ); + } + final var webServer = - WebServerConfig.builder() + webServerBuilder .port(httpConfig.listenPort()) .address(InetAddress.getByName(httpConfig.listenAddress())) .listenerSocketOptions(Map.ofEntries( diff --git a/com.io7m.idstore.server.user_v1/src/main/java/module-info.java b/com.io7m.idstore.server.user_v1/src/main/java/module-info.java index ff8ea397..17ff127a 100644 --- a/com.io7m.idstore.server.user_v1/src/main/java/module-info.java +++ b/com.io7m.idstore.server.user_v1/src/main/java/module-info.java @@ -38,6 +38,7 @@ requires com.io7m.idstore.server.service.reqlimit; requires com.io7m.idstore.server.service.sessions; requires com.io7m.idstore.server.service.telemetry.api; + requires com.io7m.idstore.server.service.tls; requires com.io7m.idstore.server.service.verdant; requires com.io7m.idstore.strings; @@ -45,6 +46,7 @@ requires io.helidon.webserver; requires io.opentelemetry.api; requires org.slf4j; + requires com.io7m.idstore.tls; exports com.io7m.idstore.server.user_v1; } \ No newline at end of file diff --git a/com.io7m.idstore.server.user_view/pom.xml b/com.io7m.idstore.server.user_view/pom.xml index ae1297e6..1b52be60 100644 --- a/com.io7m.idstore.server.user_view/pom.xml +++ b/com.io7m.idstore.server.user_view/pom.xml @@ -44,6 +44,11 @@ com.io7m.idstore.server.service.branding ${project.version} + + ${project.groupId} + com.io7m.idstore.server.service.tls + ${project.version} + ${project.groupId} com.io7m.idstore.protocol.user @@ -99,6 +104,11 @@ com.io7m.idstore.error_codes ${project.version} + + ${project.groupId} + com.io7m.idstore.tls + ${project.version} + com.io7m.jxtrand @@ -152,6 +162,10 @@ io.helidon.common helidon-common-parameters + + io.helidon.common + helidon-common-tls + org.osgi diff --git a/com.io7m.idstore.server.user_view/src/main/java/com/io7m/idstore/server/user_view/IdUVServer.java b/com.io7m.idstore.server.user_view/src/main/java/com/io7m/idstore/server/user_view/IdUVServer.java index 3440db82..4f195229 100644 --- a/com.io7m.idstore.server.user_view/src/main/java/com/io7m/idstore/server/user_view/IdUVServer.java +++ b/com.io7m.idstore.server.user_view/src/main/java/com/io7m/idstore/server/user_view/IdUVServer.java @@ -22,7 +22,10 @@ import com.io7m.idstore.server.service.clock.IdServerClock; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.telemetry.api.IdMetricsServiceType; +import com.io7m.idstore.server.service.tls.IdTLSContextServiceType; +import com.io7m.idstore.tls.IdTLSEnabled; import com.io7m.repetoir.core.RPServiceDirectoryType; +import io.helidon.common.tls.TlsConfig; import io.helidon.webserver.WebServer; import io.helidon.webserver.WebServerConfig; import io.helidon.webserver.http.HttpRouting; @@ -66,6 +69,8 @@ public static WebServer createUserViewServer( { final var configurationService = services.requireService(IdServerConfigurationService.class); + final var tlsService = + services.requireService(IdTLSContextServiceType.class); final var configuration = configurationService.configuration(); final var httpConfig = @@ -79,9 +84,27 @@ public static WebServer createUserViewServer( final var routing = createRouting(services); + final var webServerBuilder = + WebServerConfig.builder(); + + if (httpConfig.tlsConfiguration() instanceof final IdTLSEnabled enabled) { + final var tlsContext = + tlsService.create( + "UserView", + enabled.keyStore(), + enabled.trustStore() + ); + + webServerBuilder.tls( + TlsConfig.builder() + .enabled(true) + .sslContext(tlsContext.context()) + .build() + ); + } + final var webServer = - WebServerConfig.builder() - .port(httpConfig.listenPort()) + webServerBuilder.port(httpConfig.listenPort()) .address(InetAddress.getByName(httpConfig.listenAddress())) .routing(routing) .listenerSocketOptions(Map.ofEntries( diff --git a/com.io7m.idstore.server.user_view/src/main/java/module-info.java b/com.io7m.idstore.server.user_view/src/main/java/module-info.java index fe6c0c1f..0c584342 100644 --- a/com.io7m.idstore.server.user_view/src/main/java/module-info.java +++ b/com.io7m.idstore.server.user_view/src/main/java/module-info.java @@ -36,7 +36,9 @@ requires com.io7m.idstore.server.service.sessions; requires com.io7m.idstore.server.service.telemetry.api; requires com.io7m.idstore.server.service.templating; + requires com.io7m.idstore.server.service.tls; requires com.io7m.idstore.strings; + requires com.io7m.idstore.tls; requires com.io7m.jvindicator.core; requires freemarker; diff --git a/com.io7m.idstore.server.vanilla/pom.xml b/com.io7m.idstore.server.vanilla/pom.xml index 625dace6..422cc705 100644 --- a/com.io7m.idstore.server.vanilla/pom.xml +++ b/com.io7m.idstore.server.vanilla/pom.xml @@ -29,6 +29,11 @@ com.io7m.idstore.server.service.telemetry.api ${project.version} + + ${project.groupId} + com.io7m.idstore.server.service.tls + ${project.version} + ${project.groupId} com.io7m.idstore.server.service.mail diff --git a/com.io7m.idstore.server.vanilla/src/main/java/com/io7m/idstore/server/vanilla/internal/IdServer.java b/com.io7m.idstore.server.vanilla/src/main/java/com/io7m/idstore/server/vanilla/internal/IdServer.java index f394b450..a6674b08 100644 --- a/com.io7m.idstore.server.vanilla/src/main/java/com/io7m/idstore/server/vanilla/internal/IdServer.java +++ b/com.io7m.idstore.server.vanilla/src/main/java/com/io7m/idstore/server/vanilla/internal/IdServer.java @@ -65,6 +65,8 @@ import com.io7m.idstore.server.service.telemetry.api.IdServerTelemetryServiceType; import com.io7m.idstore.server.service.templating.IdFMTemplateService; import com.io7m.idstore.server.service.templating.IdFMTemplateServiceType; +import com.io7m.idstore.server.service.tls.IdTLSContextService; +import com.io7m.idstore.server.service.tls.IdTLSContextServiceType; import com.io7m.idstore.server.service.verdant.IdVerdantMessages; import com.io7m.idstore.server.user_v1.IdU1Server; import com.io7m.idstore.server.user_view.IdUVServer; @@ -231,6 +233,12 @@ private RPServiceDirectoryType createServiceDirectory( services.register(IdServerTelemetryServiceType.class, this.telemetry); services.register(IdDatabaseType.class, newDatabase); + final var strings = IdStrings.create(this.configuration.locale()); + services.register(IdStrings.class, strings); + + final var tls = IdTLSContextService.createService(services); + services.register(IdTLSContextServiceType.class, tls); + final var metrics = new IdMetricsService(this.telemetry); services.register(IdMetricsServiceType.class, metrics); @@ -242,9 +250,6 @@ private RPServiceDirectoryType createServiceDirectory( final var eventService = IdEventService.create(this.telemetry, metrics); services.register(IdEventServiceType.class, eventService); - final var strings = IdStrings.create(this.configuration.locale()); - services.register(IdStrings.class, strings); - final var mailService = IdServerMailService.create( this.telemetry, diff --git a/com.io7m.idstore.server.vanilla/src/main/java/module-info.java b/com.io7m.idstore.server.vanilla/src/main/java/module-info.java index 3cde2524..39bb8ec9 100644 --- a/com.io7m.idstore.server.vanilla/src/main/java/module-info.java +++ b/com.io7m.idstore.server.vanilla/src/main/java/module-info.java @@ -47,6 +47,7 @@ requires com.io7m.idstore.server.service.sessions; requires com.io7m.idstore.server.service.telemetry.api; requires com.io7m.idstore.server.service.templating; + requires com.io7m.idstore.server.service.tls; requires com.io7m.idstore.server.service.verdant; requires com.io7m.idstore.server.user_v1; requires com.io7m.idstore.server.user_view; diff --git a/com.io7m.idstore.strings/src/main/resources/com/io7m/idstore/strings/Messages.xml b/com.io7m.idstore.strings/src/main/resources/com/io7m/idstore/strings/Messages.xml index a1ccc326..15de48af 100644 --- a/com.io7m.idstore.strings/src/main/resources/com/io7m/idstore/strings/Messages.xml +++ b/com.io7m.idstore.strings/src/main/resources/com/io7m/idstore/strings/Messages.xml @@ -28,6 +28,7 @@ Error You cannot delete your own account. Invalid username or password. + I/O error The login command cannot be used with this method. Malformed parameter: {0} The server sent an unexpected content type. diff --git a/com.io7m.idstore.tests.extensions/src/main/java/com/io7m/idstore/tests/extensions/IdTestServers.java b/com.io7m.idstore.tests.extensions/src/main/java/com/io7m/idstore/tests/extensions/IdTestServers.java index 5d257e36..1c9114da 100644 --- a/com.io7m.idstore.tests.extensions/src/main/java/com/io7m/idstore/tests/extensions/IdTestServers.java +++ b/com.io7m.idstore.tests.extensions/src/main/java/com/io7m/idstore/tests/extensions/IdTestServers.java @@ -39,6 +39,7 @@ import com.io7m.idstore.server.api.IdServerType; import com.io7m.idstore.server.vanilla.IdServers; import com.io7m.idstore.tests.extensions.IdTestDatabases.IdDatabaseFixture; +import com.io7m.idstore.tls.IdTLSDisabled; import com.io7m.jmulticlose.core.CloseableCollection; import com.io7m.jmulticlose.core.CloseableCollectionType; import com.io7m.jmulticlose.core.ClosingResourceFailedException; @@ -307,21 +308,24 @@ public static IdTestServerFixture createWithRateLimitConfiguration( new IdServerHTTPServiceConfiguration( "localhost", userAPIPort, - URI.create("http://localhost:%d/".formatted(userAPIPort)) + URI.create("http://localhost:%d/".formatted(userAPIPort)), + IdTLSDisabled.TLS_DISABLED ); final var userViewConfiguration = new IdServerHTTPServiceConfiguration( "localhost", userViewPort, - URI.create("http://localhost:%d/".formatted(userViewPort)) + URI.create("http://localhost:%d/".formatted(userViewPort)), + IdTLSDisabled.TLS_DISABLED ); final var adminApiConfiguration = new IdServerHTTPServiceConfiguration( "localhost", adminAPIPort, - URI.create("http://localhost:%d/".formatted(adminAPIPort)) + URI.create("http://localhost:%d/".formatted(adminAPIPort)), + IdTLSDisabled.TLS_DISABLED ); final var sessionConfiguration = diff --git a/com.io7m.idstore.tests.extensions/src/main/java/module-info.java b/com.io7m.idstore.tests.extensions/src/main/java/module-info.java index 46dd0364..efc00d60 100644 --- a/com.io7m.idstore.tests.extensions/src/main/java/module-info.java +++ b/com.io7m.idstore.tests.extensions/src/main/java/module-info.java @@ -26,6 +26,7 @@ requires com.io7m.idstore.server.api; requires com.io7m.idstore.server.vanilla; requires com.io7m.idstore.strings; + requires com.io7m.idstore.tls; requires com.io7m.ervilla.api; requires com.io7m.ervilla.postgres; diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/api/IdServerConfigurationsTest.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/api/IdServerConfigurationsTest.java index 19cfcba0..210eceb6 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/api/IdServerConfigurationsTest.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/api/IdServerConfigurationsTest.java @@ -17,8 +17,9 @@ package com.io7m.idstore.tests.server.api; +import com.io7m.anethum.api.ParsingException; import com.io7m.idstore.server.api.IdServerConfigurations; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.tests.IdTestDirectories; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -54,6 +55,9 @@ public void tearDown() public void testLoad() throws Exception { + final var parsers = + new IdServerConfigurationParsers(); + final var file = IdTestDirectories.resourceOf( IdServerConfigurationsTest.class, @@ -62,8 +66,7 @@ public void testLoad() ); final var configFile = - new IdServerConfigurationFiles() - .parse(file); + parsers.parseFile(file); final var configuration = IdServerConfigurations.ofFile( @@ -77,6 +80,9 @@ public void testLoad() public void testPortOverlap() throws Exception { + final var parsers = + new IdServerConfigurationParsers(); + final var file = IdTestDirectories.resourceOf( IdServerConfigurationsTest.class, @@ -85,11 +91,10 @@ public void testPortOverlap() ); final var ex = - assertThrows(IllegalArgumentException.class, () -> { - new IdServerConfigurationFiles() - .parse(file); + assertThrows(ParsingException.class, () -> { + parsers.parseFile(file); }); - assertTrue(ex.getMessage().contains("51000")); + assertTrue(ex.statusValues().get(0).message().contains("51000")); } } diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdACmdAbstractContract.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdACmdAbstractContract.java index 46c4ce64..1b792f23 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdACmdAbstractContract.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdACmdAbstractContract.java @@ -32,7 +32,7 @@ import com.io7m.idstore.server.controller.admin.IdACommandContext; import com.io7m.idstore.server.service.branding.IdServerBrandingServiceType; import com.io7m.idstore.server.service.clock.IdServerClock; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.mail.IdServerMailServiceType; import com.io7m.idstore.server.service.maintenance.IdClosedForMaintenanceService; @@ -164,7 +164,7 @@ protected final void commandSetup() IdServerConfigurations.ofFile( Locale.ROOT, this.clock, - new IdServerConfigurationFiles().parse(this.configFile) + new IdServerConfigurationParsers().parseFile(this.configFile) ); this.maintenance = diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdAdminLoginServiceTest.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdAdminLoginServiceTest.java index 7c8a0854..985480b3 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdAdminLoginServiceTest.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/admin/IdAdminLoginServiceTest.java @@ -34,7 +34,7 @@ import com.io7m.idstore.server.controller.admin.IdAdminLoginService; import com.io7m.idstore.server.controller.command_exec.IdCommandExecutionFailure; import com.io7m.idstore.server.service.clock.IdServerClock; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.ratelimit.IdRateLimitAdminLoginServiceType; import com.io7m.idstore.server.service.sessions.IdSessionAdminService; @@ -140,8 +140,7 @@ public void setup() ); final var configFile = - new IdServerConfigurationFiles() - .parse(file); + new IdServerConfigurationParsers().parseFile(file); final var configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUCmdAbstractContract.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUCmdAbstractContract.java index c4288d1a..f1b59ff7 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUCmdAbstractContract.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUCmdAbstractContract.java @@ -29,7 +29,7 @@ import com.io7m.idstore.server.controller.user.IdUCommandContext; import com.io7m.idstore.server.service.branding.IdServerBrandingServiceType; import com.io7m.idstore.server.service.clock.IdServerClock; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.mail.IdServerMailServiceType; import com.io7m.idstore.server.service.ratelimit.IdRateLimitEmailVerificationServiceType; @@ -133,8 +133,7 @@ protected final void commandSetup() ); final var configFile = - new IdServerConfigurationFiles() - .parse(file); + new IdServerConfigurationParsers().parseFile(file); final var configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUserLoginServiceTest.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUserLoginServiceTest.java index e305e672..a25f00ae 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUserLoginServiceTest.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user/IdUserLoginServiceTest.java @@ -33,7 +33,7 @@ import com.io7m.idstore.server.controller.command_exec.IdCommandExecutionFailure; import com.io7m.idstore.server.controller.user.IdUserLoginService; import com.io7m.idstore.server.service.clock.IdServerClock; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.ratelimit.IdRateLimitUserLoginServiceType; import com.io7m.idstore.server.service.sessions.IdSessionUserService; @@ -138,8 +138,8 @@ public void setup() ); final var configFile = - new IdServerConfigurationFiles() - .parse(file); + new IdServerConfigurationParsers() + .parseFile(file); final var configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user_pwreset/IdUserPasswordResetServiceTest.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user_pwreset/IdUserPasswordResetServiceTest.java index 1f77d53d..f4bfdd1b 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user_pwreset/IdUserPasswordResetServiceTest.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/controller/user_pwreset/IdUserPasswordResetServiceTest.java @@ -38,7 +38,7 @@ import com.io7m.idstore.server.controller.user_pwreset.IdUserPasswordResetServiceType; import com.io7m.idstore.server.service.branding.IdServerBrandingServiceType; import com.io7m.idstore.server.service.clock.IdServerClock; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; import com.io7m.idstore.server.service.mail.IdServerMailServiceType; import com.io7m.idstore.server.service.ratelimit.IdRateLimitPasswordResetServiceType; import com.io7m.idstore.server.service.telemetry.api.IdEventServiceType; @@ -132,8 +132,7 @@ public void setup() ); final var configFile = - new IdServerConfigurationFiles() - .parse(file); + new IdServerConfigurationParsers().parseFile(file); this.configuration = IdServerConfigurations.ofFile( diff --git a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/service/configuration/IdServerConfigurationServiceTest.java b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/service/configuration/IdServerConfigurationServiceTest.java index 692c24de..b1bd5e7e 100644 --- a/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/service/configuration/IdServerConfigurationServiceTest.java +++ b/com.io7m.idstore.tests/src/main/java/com/io7m/idstore/tests/server/service/configuration/IdServerConfigurationServiceTest.java @@ -17,8 +17,11 @@ package com.io7m.idstore.tests.server.service.configuration; +import com.io7m.anethum.slf4j.ParseStatusLogging; +import com.io7m.idstore.server.api.IdServerConfigurationFile; import com.io7m.idstore.server.api.IdServerConfigurations; -import com.io7m.idstore.server.service.configuration.IdServerConfigurationFiles; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationParsers; +import com.io7m.idstore.server.service.configuration.IdServerConfigurationSerializers; import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.telemetry.api.IdMetricsService; import com.io7m.idstore.tests.IdTestDirectories; @@ -27,14 +30,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.Clock; import java.util.Locale; +import static com.io7m.blackthorne.core.BTPreserveLexical.DISCARD_LEXICAL_INFORMATION; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -42,6 +47,9 @@ public final class IdServerConfigurationServiceTest extends IdServiceContract { + private static final Logger LOG = + LoggerFactory.getLogger(IdServerConfigurationServiceTest.class); + private Path directory; @BeforeEach @@ -60,71 +68,92 @@ public void tearDown() @Test public void testConfig0() + throws Exception { this.roundTrip("server-config-0.xml"); } @Test public void testConfig2() + throws Exception { this.roundTrip("server-config-2.xml"); } private void roundTrip( final String name) + throws Exception { - try { - final var files = - new IdServerConfigurationFiles(); + final var parsers = + new IdServerConfigurationParsers(); + final var serializers = + new IdServerConfigurationSerializers(); - final var file = - IdTestDirectories.resourceOf( - IdServerConfigurationServiceTest.class, - this.directory, - name - ); - - final var parsed0 = - files.parse(file); + final var file = + IdTestDirectories.resourceOf( + IdServerConfigurationServiceTest.class, + this.directory, + name + ); - final var parsedConfig0 = - IdServerConfigurations.ofFile( - Locale.getDefault(), - Clock.systemUTC(), - parsed0 - ); + final IdServerConfigurationFile parsed0; + try (var parser = + parsers.createParserForFileWithContext( + DISCARD_LEXICAL_INFORMATION, + file, + x -> ParseStatusLogging.logWithAll(LOG, x))) { + parsed0 = parser.execute(); + } - final var outputFile = - this.directory.resolve("output.xml"); + final var parsedConfig0 = + IdServerConfigurations.ofFile( + Locale.getDefault(), + Clock.systemUTC(), + parsed0 + ); - try (var output = Files.newOutputStream(outputFile, CREATE, WRITE)) { - files.serialize(output, parsedConfig0); - } + final var outputFile = + this.directory.resolve("output.xml"); - final var parsed1 = - files.parse(outputFile); + serializers.serializeFile(outputFile, parsed0); - assertEquals(parsed0, parsed1); - } catch (final IOException e) { - throw new UncheckedIOException(e); + final IdServerConfigurationFile parsed1; + try (var parser = + parsers.createParserForFileWithContext( + DISCARD_LEXICAL_INFORMATION, + outputFile, + x -> ParseStatusLogging.logWithAll(LOG, x))) { + parsed1 = parser.execute(); } + + assertEquals(parsed0.brandingConfiguration(), parsed1.brandingConfiguration()); + assertEquals(parsed0.databaseConfiguration(), parsed1.databaseConfiguration()); + assertEquals(parsed0.historyConfiguration(), parsed1.historyConfiguration()); + assertEquals(parsed0.httpConfiguration(), parsed1.httpConfiguration()); + assertEquals(parsed0.mailConfiguration(), parsed1.mailConfiguration()); + assertEquals(parsed0.openTelemetry(), parsed1.openTelemetry()); + assertEquals(parsed0.passwordExpiration(), parsed1.passwordExpiration()); + assertEquals(parsed0.rateLimit(), parsed1.rateLimit()); + assertEquals(parsed0.sessionConfiguration(), parsed1.sessionConfiguration()); + assertEquals(parsed0, parsed1); } @Override protected IdServerConfigurationService createInstanceA() { try { - final var files = - new IdServerConfigurationFiles(); + final var parsers = + new IdServerConfigurationParsers(); + final var file = IdTestDirectories.resourceOf( - IdServerConfigurationServiceTest.class, - this.directory, - "server-config-0.xml" - ); + IdServerConfigurationServiceTest.class, + this.directory, + "server-config-0.xml" + ); final var configFile = - files.parse(file); + parsers.parseFile(file); final var configuration = IdServerConfigurations.ofFile( @@ -137,8 +166,8 @@ protected IdServerConfigurationService createInstanceA() Mockito.mock(IdMetricsService.class), configuration ); - } catch (final IOException e) { - throw new UncheckedIOException(e); + } catch (final Exception e) { + throw new IllegalStateException(e); } } @@ -146,8 +175,9 @@ protected IdServerConfigurationService createInstanceA() protected IdServerConfigurationService createInstanceB() { try { - final var files = - new IdServerConfigurationFiles(); + final var parsers = + new IdServerConfigurationParsers(); + final var file = IdTestDirectories.resourceOf( IdServerConfigurationServiceTest.class, @@ -156,7 +186,7 @@ protected IdServerConfigurationService createInstanceB() ); final var configFile = - files.parse(file); + parsers.parseFile(file); final var configuration = IdServerConfigurations.ofFile( @@ -169,8 +199,8 @@ protected IdServerConfigurationService createInstanceB() Mockito.mock(IdMetricsService.class), configuration ); - } catch (final IOException e) { - throw new UncheckedIOException(e); + } catch (final Exception e) { + throw new IllegalStateException(e); } } } diff --git a/com.io7m.idstore.tests/src/main/java/module-info.java b/com.io7m.idstore.tests/src/main/java/module-info.java index 9084e891..824b70ea 100644 --- a/com.io7m.idstore.tests/src/main/java/module-info.java +++ b/com.io7m.idstore.tests/src/main/java/module-info.java @@ -49,6 +49,8 @@ requires com.io7m.idstore.user_client; requires com.helger.css; + requires com.io7m.anethum.api; + requires com.io7m.anethum.slf4j; requires com.io7m.ervilla.api; requires com.io7m.ervilla.test_extension; requires com.io7m.junreachable.core; @@ -77,6 +79,7 @@ requires org.junit.jupiter.engine; requires org.junit.platform.commons; requires org.junit.platform.engine; + requires com.io7m.blackthorne.core; exports com.io7m.idstore.tests.database; exports com.io7m.idstore.tests.integration; diff --git a/com.io7m.idstore.tests/src/main/resources/com/io7m/idstore/tests/server-config-0.xml b/com.io7m.idstore.tests/src/main/resources/com/io7m/idstore/tests/server-config-0.xml index 006e1381..ec6216ca 100644 --- a/com.io7m.idstore.tests/src/main/resources/com/io7m/idstore/tests/server-config-0.xml +++ b/com.io7m.idstore.tests/src/main/resources/com/io7m/idstore/tests/server-config-0.xml @@ -1,6 +1,6 @@ - + @@ -150,13 +150,19 @@ + ExternalURI="http://localhost:51000/"> + + + ExternalURI="http://localhost:50000/"> + + + ExternalURI="http://localhost:50001/"> + + - + @@ -151,13 +151,19 @@ + ExternalURI="http://localhost:51000/"> + + + ExternalURI="http://localhost:51000/"> + + + ExternalURI="http://localhost:50001/"> + + - + @@ -18,13 +18,19 @@ + ExternalURI="http://localhost:51000/"> + + + ExternalURI="http://localhost:50000/"> + + + ExternalURI="http://localhost:50001/"> + + + + + + 4.0.0 + + + com.io7m.idstore + com.io7m.idstore + 1.0.0-SNAPSHOT + + com.io7m.idstore.tls + + jar + com.io7m.idstore.tls + Identity server (TLS) + https://www.io7m.com/software/idstore + + + + org.slf4j + slf4j-api + + + + org.osgi + org.osgi.annotation.bundle + provided + + + org.osgi + org.osgi.annotation.versioning + provided + + + + diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSConfigurationType.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSConfigurationType.java new file mode 100644 index 00000000..6a543f02 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSConfigurationType.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.tls; + +/** + * The type of TLS configuration settings. + */ + +public sealed interface IdTLSConfigurationType + permits IdTLSDisabled, IdTLSEnabled +{ + +} diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSContext.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSContext.java new file mode 100644 index 00000000..b5012170 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSContext.java @@ -0,0 +1,252 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.tls; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.util.Objects; + +/** + * Functions to create custom SSL contexts. + */ + +public final class IdTLSContext +{ + private static final Logger LOG = + LoggerFactory.getLogger(IdTLSContext.class); + + private final String user; + private final IdTLSStoreConfiguration keyStoreConfiguration; + private final KeyStore keyStore; + private final IdTLSStoreConfiguration trustStoreConfiguration; + private final KeyStore trustStore; + private final SSLContext context; + + private IdTLSContext( + final String inUser, + final IdTLSStoreConfiguration inKeyStoreConfiguration, + final KeyStore inKeyStore, + final IdTLSStoreConfiguration inTrustStoreConfiguration, + final KeyStore inTrustStore, + final SSLContext inContext) + { + this.user = + Objects.requireNonNull(inUser, "user"); + this.keyStoreConfiguration = + Objects.requireNonNull(inKeyStoreConfiguration, "keyStoreConfiguration"); + this.keyStore = + Objects.requireNonNull(inKeyStore, "keyStore"); + this.trustStoreConfiguration = + Objects.requireNonNull( + inTrustStoreConfiguration, + "trustStoreConfiguration"); + this.trustStore = + Objects.requireNonNull(inTrustStore, "trustStore"); + this.context = + Objects.requireNonNull(inContext, "context"); + } + + /** + * Create a new SSL context using the given keystore and truststore. + * + * @param user The part of the application creating the context + * @param keyStoreConfiguration The key store + * @param trustStoreConfiguration The trust store + * + * @return A new SSL context + * + * @throws IOException On I/O errors + * @throws GeneralSecurityException On security errors + */ + + public static IdTLSContext create( + final String user, + final IdTLSStoreConfiguration keyStoreConfiguration, + final IdTLSStoreConfiguration trustStoreConfiguration) + throws IOException, GeneralSecurityException + { + Objects.requireNonNull(user, "user"); + Objects.requireNonNull(keyStoreConfiguration, "keyStoreConfiguration"); + Objects.requireNonNull(trustStoreConfiguration, "trustStoreConfiguration"); + + LOG.info( + "KeyStore [{}] {} (Provider {}, Type {})", + user, + keyStoreConfiguration.storePath(), + keyStoreConfiguration.storeProvider(), + keyStoreConfiguration.storeType() + ); + + LOG.info( + "TrustStore [{}] {} (Provider {}, Type {})", + user, + trustStoreConfiguration.storePath(), + trustStoreConfiguration.storeProvider(), + trustStoreConfiguration.storeType() + ); + + final var keyStore = + KeyStore.getInstance( + keyStoreConfiguration.storeType(), + keyStoreConfiguration.storeProvider() + ); + + final var keyStorePassChars = + keyStoreConfiguration.storePassword() + .toCharArray(); + + try (var stream = + Files.newInputStream(keyStoreConfiguration.storePath())) { + keyStore.load(stream, keyStorePassChars); + } + + final var trustStore = + KeyStore.getInstance( + trustStoreConfiguration.storeType(), + trustStoreConfiguration.storeProvider() + ); + + final var trustStorePassChars = + trustStoreConfiguration.storePassword().toCharArray(); + + try (var stream = Files.newInputStream(trustStoreConfiguration.storePath())) { + trustStore.load(stream, trustStorePassChars); + } + + final var keyManagerFactory = + createKeyManagerFactory(keyStore, keyStorePassChars); + final var trustManagerFactory = + createTrustManagerFactory(trustStore); + + final var context = + SSLContext.getInstance("TLSv1.3"); + + context.init( + keyManagerFactory.getKeyManagers(), + trustManagerFactory.getTrustManagers(), + SecureRandom.getInstanceStrong() + ); + + return new IdTLSContext( + user, + keyStoreConfiguration, + keyStore, + trustStoreConfiguration, + trustStore, + context + ); + } + + private static TrustManagerFactory createTrustManagerFactory( + final KeyStore trustStore) + throws GeneralSecurityException + { + final var trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + + trustManagerFactory.init(trustStore); + return trustManagerFactory; + } + + private static KeyManagerFactory createKeyManagerFactory( + final KeyStore keyStore, + final char[] keyStorePassChars) + throws GeneralSecurityException + { + final var keyManagerFactory = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + + keyManagerFactory.init(keyStore, keyStorePassChars); + return keyManagerFactory; + } + + @Override + public String toString() + { + return "[IdTLSContext 0x%x]".formatted(Integer.valueOf(this.hashCode())); + } + + /** + * Reload the key stores and associated SSL context. + * + * @throws IOException On I/O errors + * @throws GeneralSecurityException On security errors + */ + + public void reload() + throws IOException, GeneralSecurityException + { + LOG.info( + "KeyStore [{}] {} reloading", + this.user, + this.keyStoreConfiguration.storePath() + ); + + final var keyStorePassChars = + this.keyStoreConfiguration.storePassword() + .toCharArray(); + + try (var stream = + Files.newInputStream(this.keyStoreConfiguration.storePath())) { + this.keyStore.load(stream, keyStorePassChars); + } + + LOG.info( + "TrustStore [{}] {} reloading", + this.user, + this.keyStoreConfiguration.storePath() + ); + + final var trustStorePassChars = + this.trustStoreConfiguration.storePassword().toCharArray(); + + try (var stream = + Files.newInputStream(this.trustStoreConfiguration.storePath())) { + this.trustStore.load(stream, trustStorePassChars); + } + + final var keyManagerFactory = + createKeyManagerFactory(this.keyStore, keyStorePassChars); + final var trustManagerFactory = + createTrustManagerFactory(this.trustStore); + + this.context.init( + keyManagerFactory.getKeyManagers(), + trustManagerFactory.getTrustManagers(), + SecureRandom.getInstanceStrong() + ); + } + + /** + * @return The SSL context + */ + + public SSLContext context() + { + return this.context; + } +} diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSDisabled.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSDisabled.java new file mode 100644 index 00000000..129c7588 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSDisabled.java @@ -0,0 +1,31 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.tls; + +/** + * TLS is disabled. + */ + +public enum IdTLSDisabled implements IdTLSConfigurationType +{ + /** + * TLS is disabled. + */ + + TLS_DISABLED +} diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSEnabled.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSEnabled.java new file mode 100644 index 00000000..6dd68049 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSEnabled.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.tls; + +import java.util.Objects; + +/** + * TLS is enabled. + * + * @param keyStore The key store + * @param trustStore The trust store + */ + +public record IdTLSEnabled( + IdTLSStoreConfiguration keyStore, + IdTLSStoreConfiguration trustStore) + implements IdTLSConfigurationType +{ + /** + * TLS is enabled. + * + * @param keyStore The key store + * @param trustStore The trust store + */ + + public IdTLSEnabled + { + Objects.requireNonNull(keyStore, "keyStore"); + Objects.requireNonNull(trustStore, "trustStore"); + } +} diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSStoreConfiguration.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSStoreConfiguration.java new file mode 100644 index 00000000..edaf73e1 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/IdTLSStoreConfiguration.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +package com.io7m.idstore.tls; + +import java.nio.file.Path; +import java.util.Objects; + +/** + * Configuration information for a key/trust store. + * + * @param storeType The store type (such as "JKS" or "CANONMILL") + * @param storeProvider The store provider (such as "SUN" or "CANONMILL") + * @param storePassword The store password + * @param storePath The store path + */ + +public record IdTLSStoreConfiguration( + String storeType, + String storeProvider, + String storePassword, + Path storePath) +{ + /** + * Configuration information for a key/trust store. + * + * @param storeType The store type (such as "JKS" or "CANONMILL") + * @param storeProvider The store provider (such as "SUN" or "CANONMILL") + * @param storePassword The store password + * @param storePath The store path + */ + + public IdTLSStoreConfiguration + { + Objects.requireNonNull(storeType, "storeType"); + Objects.requireNonNull(storeProvider, "storeProvider"); + Objects.requireNonNull(storePassword, "storePassword"); + Objects.requireNonNull(storePath, "storePath"); + } +} diff --git a/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/package-info.java b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/package-info.java new file mode 100644 index 00000000..3d7ee2d8 --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/com/io7m/idstore/tls/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Identity server (TLS) + */ + +@Export +@Version("1.0.0") +package com.io7m.idstore.tls; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/com.io7m.idstore.tls/src/main/java/module-info.java b/com.io7m.idstore.tls/src/main/java/module-info.java new file mode 100644 index 00000000..fcf7f84f --- /dev/null +++ b/com.io7m.idstore.tls/src/main/java/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2023 Mark Raynsford https://www.io7m.com + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * Identity server (TLS) + */ + +module com.io7m.idstore.tls +{ + requires static org.osgi.annotation.bundle; + requires static org.osgi.annotation.versioning; + + requires org.slf4j; + + exports com.io7m.idstore.tls; +} diff --git a/pom.xml b/pom.xml index f0f290ca..f8c31974 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,7 @@ com.io7m.idstore.server.service.telemetry.api com.io7m.idstore.server.service.telemetry.otp com.io7m.idstore.server.service.templating + com.io7m.idstore.server.service.tls com.io7m.idstore.server.service.verdant com.io7m.idstore.server.user_v1 com.io7m.idstore.server.user_view @@ -62,12 +63,14 @@ com.io7m.idstore.tests.arbitraries com.io7m.idstore.tests.extensions com.io7m.idstore.tests + com.io7m.idstore.tls com.io7m.idstore.user_client.api com.io7m.idstore.user_client 1.1.0 + 2.0.0 1.2.0 0.0.5 0.0.5 @@ -315,6 +318,11 @@ com.io7m.anethum.api ${com.io7m.anethum.version} + + com.io7m.anethum + com.io7m.anethum.slf4j + ${com.io7m.anethum.version} + org.postgresql postgresql @@ -507,21 +515,21 @@ 1.0.0 - + - jakarta.xml.bind - jakarta.xml.bind-api - 4.0.1 + com.io7m.blackthorne + com.io7m.blackthorne.core + ${com.io7m.blackthorne.version} - com.sun.xml.bind - jaxb-impl - 4.0.4 + com.io7m.blackthorne + com.io7m.blackthorne.jxe + ${com.io7m.blackthorne.version} - jakarta.activation - jakarta.activation-api - 2.1.2 + com.io7m.jxe + com.io7m.jxe.core + 1.0.2 @@ -531,15 +539,9 @@ 1.6.0 - com.sun.mail + org.eclipse.angus jakarta.mail - 2.0.1 - - - com.sun.activation - jakarta.activation - - + 2.0.2 com.github.davidmoten @@ -550,8 +552,17 @@ com.google.code.findbugs jsr305 + + com.sun.mail + jakarta.mail + + + jakarta.activation + jakarta.activation-api + 2.1.2 + diff --git a/spotbugs-filter.xml b/spotbugs-filter.xml index 9bcf90af..5ad0c23f 100644 --- a/spotbugs-filter.xml +++ b/spotbugs-filter.xml @@ -605,9 +605,22 @@ - + + + + + + - + + + + + + + + + @@ -626,6 +639,12 @@ + + + + + + @@ -882,6 +901,24 @@ + + + + + + + + + + + + + + + + + +