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

org.eclipse.ditto.connectivity.service.messaging.validation.SshTunnelValidator Maven / Gradle / Ivy

/*
 * Copyright (c) 2021 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.eclipse.ditto.connectivity.service.messaging.validation;

import java.net.URI;

import org.eclipse.ditto.base.model.exceptions.DittoRuntimeException;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.connectivity.model.ClientCertificateCredentials;
import org.eclipse.ditto.connectivity.model.ConnectionConfigurationInvalidException;
import org.eclipse.ditto.connectivity.model.CredentialsVisitor;
import org.eclipse.ditto.connectivity.model.HmacCredentials;
import org.eclipse.ditto.connectivity.model.OAuthClientCredentials;
import org.eclipse.ditto.connectivity.model.SshPublicKeyCredentials;
import org.eclipse.ditto.connectivity.model.SshTunnel;
import org.eclipse.ditto.connectivity.model.UserPasswordCredentials;
import org.eclipse.ditto.connectivity.service.messaging.internal.ssl.PublicKeyAuthenticationFactory;

/**
 * Validates the ssh tunnel configuration of a connection.
 */
final class SshTunnelValidator {

    private static final String SSH_SCHEME = "ssh";
    private final DittoHeaders dittoHeaders;
    private final HostValidator hostValidator;

    /**
     * Creates a new instance of SshTunnelValidator with the given headers.
     *
     * @param dittoHeaders the ditto headers
     * @param hostValidator the host validator to check the configured ssh host
     * @return the new instance
     */
    public static SshTunnelValidator getInstance(final DittoHeaders dittoHeaders,
            final HostValidator hostValidator) {
        return new SshTunnelValidator(dittoHeaders, hostValidator);
    }

    private SshTunnelValidator(final DittoHeaders dittoHeaders,
            final HostValidator hostValidator) {
        this.dittoHeaders = dittoHeaders;
        this.hostValidator = hostValidator;
    }

    /**
     * Validates the ssh tunnel configuration of the connection.
     *
     * @param tunnel the tunnel to validate
     */
    void validate(final SshTunnel tunnel) {
        validateUri(tunnel.getUri());
        tunnel.getCredentials().accept(new SshTunnelCredentialsValidator());
        validateFingerprints(tunnel);
    }

    private void validateFingerprints(final SshTunnel tunnel) {
        if (tunnel.isValidateHost() && tunnel.getKnownHosts().isEmpty()) {
            throw configError("Specify at least one fingerprint if host validationis enabled.");
        }
    }

    private void validateUri(final String uriString) {
        if (uriString == null || uriString.isEmpty()) {
            throw configError("The URI of the ssh server must not be empty.");
        }
        try {
            final URI uri = new URI(uriString).parseServerAuthority();
            if (!uri.getScheme().equals(SSH_SCHEME)) {
                throw configError("The scheme for the ssh endpoint must be 'ssh'.");
            }
            hostValidator.validateHostname(uri.getHost(), dittoHeaders);
        } catch (final Exception exception) {
            final String message = String.format("The SSH server URI '%s' is not valid: %s", uriString,
                    exception.getMessage());
            throw configError(message);
        }
    }

    private DittoRuntimeException configError(final String message) {

        return ConnectionConfigurationInvalidException.newBuilder(message)
                .dittoHeaders(dittoHeaders)
                .build();
    }

    private final class SshTunnelCredentialsValidator implements CredentialsVisitor {

        @Override
        public Void clientCertificate(final ClientCertificateCredentials credentials) {
            throw notSupportedException(ClientCertificateCredentials.TYPE);
        }

        @Override
        public Void usernamePassword(final UserPasswordCredentials credentials) {
            if (credentials.getUsername().isEmpty()) {
                throw configError("SSH tunnel username must not be empty.");
            }
            if (credentials.getPassword().isEmpty()) {
                throw configError("SSH tunnel password must not be empty.");
            }
            return null;
        }

        @Override
        public Void sshPublicKeyAuthentication(final SshPublicKeyCredentials credentials) {
            credentials.accept(PublicKeyAuthenticationFactory.getInstance(dittoHeaders));
            return null;
        }

        @Override
        public Void hmac(final HmacCredentials credentials) {
            throw notSupportedException(HmacCredentials.TYPE);
        }

        @Override
        public Void oauthClientCredentials(final OAuthClientCredentials credentials) {
            throw notSupportedException(OAuthClientCredentials.TYPE);
        }

        private DittoRuntimeException notSupportedException(final String type) {
            return ConnectionConfigurationInvalidException.newBuilder(
                            "Credentials type " + type + " cannot be used for an ssh tunnel.")
                    .dittoHeaders(dittoHeaders)
                    .build();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy