All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.fraunhofer.iosb.ilt.faaast.service.endpoint.http.HttpEndpoint Maven / Gradle / Ivy

/*
 * Copyright (c) 2021 Fraunhofer IOSB, eine rechtlich nicht selbstaendige
 * Einrichtung der Fraunhofer-Gesellschaft zur Foerderung der angewandten
 * Forschung e.V.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.fraunhofer.iosb.ilt.faaast.service.endpoint.http;

import static de.fraunhofer.iosb.ilt.faaast.service.certificate.util.KeyStoreHelper.DEFAULT_ALIAS;

import de.fraunhofer.iosb.ilt.faaast.service.ServiceContext;
import de.fraunhofer.iosb.ilt.faaast.service.certificate.CertificateData;
import de.fraunhofer.iosb.ilt.faaast.service.certificate.CertificateInformation;
import de.fraunhofer.iosb.ilt.faaast.service.certificate.util.KeyStoreHelper;
import de.fraunhofer.iosb.ilt.faaast.service.config.CoreConfig;
import de.fraunhofer.iosb.ilt.faaast.service.endpoint.Endpoint;
import de.fraunhofer.iosb.ilt.faaast.service.exception.EndpointException;
import de.fraunhofer.iosb.ilt.faaast.service.util.Ensure;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Objects;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Implementation of HTTP endpoint. Accepts http request and maps them to Request objects passes them to the service and
 * expects a response object which is streamed as json response to the http client
 */
public class HttpEndpoint implements Endpoint {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpEndpoint.class);
    private static final CertificateInformation SELFSIGNED_CERTIFICATE_INFORMATION = CertificateInformation.builder()
            .applicationUri("urn:de:fraunhofer:iosb:ilt:faaast:service:endpoint:http")
            .commonName("FA³ST Service HTTP Endpoint")
            .countryCode("DE")
            .localityName("Karlsruhe")
            .organization("Fraunhofer IOSB")
            .organizationUnit("ILT")
            .build();
    private HttpEndpointConfig config;
    private ServiceContext serviceContext;
    private Server server;
    private Handler handler;

    @Override
    public HttpEndpointConfig asConfig() {
        return config;
    }


    /**
     * {@inheritDoc}
     *
     * @throws IllegalArgumentException is config is null
     */
    @Override
    public void init(CoreConfig coreConfig, HttpEndpointConfig config, ServiceContext serviceContext) {
        Ensure.requireNonNull(config, "config must be non-null");
        Ensure.requireNonNull(serviceContext, "serviceContext must be non-null");
        this.config = config;
        this.serviceContext = serviceContext;
    }


    @Override
    public void start() throws EndpointException {
        if (server != null && server.isStarted()) {
            return;
        }
        server = new Server();
        configureHttpServer();
        handler = new RequestHandler(serviceContext, config);
        server.setHandler(handler);
        server.setErrorHandler(new HttpErrorHandler());
        try {
            server.start();
        }
        catch (Exception e) {
            throw new EndpointException("error starting HTTP endpoint", e);
        }
    }


    private void configureHttpServer() throws EndpointException {
        HttpConfiguration httpConfig = new HttpConfiguration();
        httpConfig.setSendServerVersion(false);
        httpConfig.setSendDateHeader(false);
        httpConfig.setSendXPoweredBy(false);
        HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(httpConfig);
        ServerConnector serverConnector;
        SecureRequestCustomizer secureRequestCustomizer = new SecureRequestCustomizer();
        secureRequestCustomizer.setSniHostCheck(config.isSniEnabled());
        httpConfig.addCustomizer(secureRequestCustomizer);
        serverConnector = buildSSLServerConnector(httpConnectionFactory);
        serverConnector.setPort(config.getPort());
        server.addConnector(serverConnector);
    }


    private KeyStore generateSelfSignedCertificate() throws EndpointException {
        try {
            LOGGER.debug("Generating self-signed certificate for HTTP endpoint...");
            CertificateData certificateData = KeyStoreHelper.generateSelfSigned(SELFSIGNED_CERTIFICATE_INFORMATION);
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry(DEFAULT_ALIAS, certificateData.getCertificate());
            keyStore.setKeyEntry(DEFAULT_ALIAS, certificateData.getKeyPair().getPrivate(), null, certificateData.getCertificateChain());
            LOGGER.debug("Self-signed certificate for HTTP endpoint successfully generated");
            return keyStore;
        }
        catch (IOException | CertificateException | KeyStoreException | NoSuchAlgorithmException e) {
            throw new EndpointException("error generating self-signed certificate for HTTPS endpoint", e);
        }
    }


    private ServerConnector buildSSLServerConnector(HttpConnectionFactory httpConnectionFactory) throws EndpointException {
        SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
        if (Objects.isNull(config.getCertificate())
                || Objects.isNull(config.getCertificate().getKeyStorePath())
                || config.getCertificate().getKeyStorePath().equals("")) {
            LOGGER.info("Generating self-signed certificate for HTTPS (reason: no certificate provided)");
            sslContextFactory.setKeyStore(generateSelfSignedCertificate());
        }
        else {
            try {
                KeyStore keyStore = KeyStoreHelper.load(
                        new File(config.getCertificate().getKeyStorePath()),
                        config.getCertificate().getKeyStoreType(),
                        config.getCertificate().getKeyStorePassword());
                sslContextFactory.setKeyStorePassword(config.getCertificate().getKeyStorePassword());
                sslContextFactory.setKeyManagerPassword(config.getCertificate().getKeyPassword());
                sslContextFactory.setKeyStore(keyStore);
            }
            catch (IOException | GeneralSecurityException e) {
                throw new EndpointException("Error loading certificate for HTTP endpoint", e);
            }
        }
        SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, httpConnectionFactory.getProtocol());
        return new ServerConnector(server, sslConnectionFactory, httpConnectionFactory);
    }


    @Override
    public void stop() {
        if (handler != null) {
            try {
                handler.stop();
            }
            catch (Exception e) {
                LOGGER.debug("stopping HTTP handler failed", e);
            }
        }
        try {
            server.stop();
            server.join();
        }
        catch (Exception e) {
            LOGGER.debug("HTTP endpoint did non shutdown correctly", e);
            Thread.currentThread().interrupt();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy