diff --git a/components/camel-ssh/pom.xml b/components/camel-ssh/pom.xml new file mode 100644 index 0000000000000..e52a273ae1471 --- /dev/null +++ b/components/camel-ssh/pom.xml @@ -0,0 +1,87 @@ + + + + + 4.0.0 + + + org.apache.camel + camel-parent + 2.10-SNAPSHOT + ../../parent + + + camel-ssh + bundle + Camel :: SSH + Camel SSH support + + + org.apache.camel.component.ssh.* + + + + + org.apache.camel + camel-core + + + org.apache.mina + mina-core + 2.0.2 + + + org.apache.sshd + sshd-core + 0.6.0 + + + + + org.apache.camel + camel-test + test + + + + bouncycastle + bcprov-jdk15 + 140 + test + + + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java new file mode 100644 index 0000000000000..7d36d2906b355 --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import java.net.*; +import java.util.*; + +import org.apache.camel.Endpoint; +import org.apache.camel.impl.DefaultComponent; +import org.apache.sshd.common.KeyPairProvider; + +/** + * Represents the component that manages {@link SshEndpoint}. + */ +public class SshComponent extends DefaultComponent { + private SshConfiguration configuration; + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { + SshConfiguration newConfig; + + if (configuration == null) { + newConfig = new SshConfiguration(new URI(uri)); + } else { + newConfig = configuration.copy(); + } + + SshEndpoint endpoint = new SshEndpoint(uri, this, newConfig); + setProperties(endpoint.getConfiguration(), parameters); + //setProperties(endpoint, parameters); + return endpoint; + } + + public SshConfiguration getConfiguration() { + if (configuration == null) { + configuration = new SshConfiguration(); + } + return configuration; + } + + public void setConfiguration(SshConfiguration configuration) { + this.configuration = configuration; + } + + public String getHost() { + return getConfiguration().getHost(); + } + + public void setHost(String host) { + getConfiguration().setHost(host); + } + + public int getPort() { + return getConfiguration().getPort(); + } + + public void setPort(int port) { + getConfiguration().setPort(port); + } + + public String getUsername() { + return getConfiguration().getUsername(); + } + + public void setUsername(String username) { + getConfiguration().setUsername(username); + } + + public String getPassword() { + return getConfiguration().getPassword(); + } + + public void setPassword(String password) { + getConfiguration().setPassword(password); + } + + public String getPollCommand() { + return getConfiguration().getPollCommand(); + } + + public void setPollCommand(String pollCommand) { + getConfiguration().setPollCommand(pollCommand); + } + + public KeyPairProvider getKeyPairProvider() { + return getConfiguration().getKeyPairProvider(); + } + + public void setKeyPairProvider(KeyPairProvider keyPairProvider) { + getConfiguration().setKeyPairProvider(keyPairProvider); + } + + public String getKeyType() { + return getConfiguration().getKeyType(); + } + + public void setKeyType(String keyType) { + getConfiguration().setKeyType(keyType); + } + + public long getTimeout() { + return getConfiguration().getTimeout(); + } + + public void setTimeout(long timeout) { + getConfiguration().setTimeout(timeout); + } +} diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java new file mode 100644 index 0000000000000..28ef07f2cf771 --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java @@ -0,0 +1,189 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import java.net.*; + +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.util.ObjectHelper; +import org.apache.sshd.common.KeyPairProvider; + +public class SshConfiguration implements Cloneable { + public static final int DEFAULT_SSH_PORT = 22; + + private String username; + private String host; + private int port = DEFAULT_SSH_PORT; + private String password; + private String pollCommand; + private KeyPairProvider keyPairProvider; + private String keyType; + private long timeout = 30000; + + public SshConfiguration() { + } + + public SshConfiguration(URI uri) { + configure(uri); + } + + public void configure(URI uri) { + // UserInfo can contain both username and password as: user:pwd@sshserver + // see: http://en.wikipedia.org/wiki/URI_scheme + String username = uri.getUserInfo(); + String pw = null; + if (username != null && username.contains(":")) { + pw = ObjectHelper.after(username, ":"); + username = ObjectHelper.before(username, ":"); + } + if (username != null) { + setUsername(username); + } + if (pw != null) { + setPassword(pw); + } + + setHost(uri.getHost()); + + // URI.getPort returns -1 if port not defined, else use default port + int uriPort = uri.getPort(); + if (uriPort != -1) { + setPort(uriPort); + } + } + + public SshConfiguration copy() { + try { + return (SshConfiguration) clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeCamelException(e); + } + } + + public String getUsername() { + return username; + } + + /** + * Sets the username to use in logging into the remote SSH server. + * + * @param username String representing login username. + */ + public void setUsername(String username) { + this.username = username; + } + + public String getHost() { + return host; + } + + /** + * Sets the hostname of the remote SSH server. + * + * @param host String representing hostname of SSH server. + */ + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + /** + * Sets the port number for the remote SSH server. + * + * @param port int representing port number on remote host. Defaults to 22. + */ + public void setPort(int port) { + this.port = port; + } + + public String getPassword() { + return password; + } + + /** + * Sets the password to use in connecting to remote SSH server. + * Requires keyPairProvider to be set to null. + * + * @param password String representing password for username at remote host. + */ + public void setPassword(String password) { + this.password = password; + } + + public String getPollCommand() { + return pollCommand; + } + + /** + * Sets the command string to send to the remote SSH server during every poll cycle. + * Only works with camel-ssh component being used as a consumer, i.e. from("ssh://...") + * + * @param pollCommand String representing the command to send. + */ + public void setPollCommand(String pollCommand) { + this.pollCommand = pollCommand; + } + + public KeyPairProvider getKeyPairProvider() { + return keyPairProvider; + } + + /** + * Sets the KeyPairProvider reference to use when connecting using Certificates to the remote SSH Server. + * + * @param keyPairProvider KeyPairProvider reference to use in authenticating. If set to 'null', + * then will attempt to connect using username/password settings. + * + * @see KeyPairProvider + */ + public void setKeyPairProvider(KeyPairProvider keyPairProvider) { + this.keyPairProvider = keyPairProvider; + } + + public String getKeyType() { + return keyType; + } + + /** + * Sets the key type to pass to the KeyPairProvider as part of authentication. + * KeyPairProvider.loadKey(...) will be passed this value. + * + * @param keyType String defining the type of KeyPair to use for authentication. + * + * @see KeyPairProvider + */ + public void setKeyType(String keyType) { + this.keyType = keyType; + } + + public long getTimeout() { + return timeout; + } + + /** + * Sets the timeout in milliseconds to wait in establishing the remote SSH server connection. + * Defaults to 30000 milliseconds. + * + * @param timeout long millisconeds to wait. + */ + public void setTimeout(long timeout) { + this.timeout = timeout; + } +} diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java new file mode 100644 index 0000000000000..36dbc59a4e532 --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.impl.ScheduledPollConsumer; + +public class SshConsumer extends ScheduledPollConsumer { + private final SshEndpoint endpoint; + + public SshConsumer(SshEndpoint endpoint, Processor processor) { + super(endpoint, processor); + this.endpoint = endpoint; + } + + @Override + protected int poll() throws Exception { + String command = endpoint.getPollCommand(); + byte[] result = endpoint.sendExecCommand(command); + + Exchange exchange = endpoint.createExchange(); + exchange.getIn().setBody(result); + + try { + // send message to next processor in the route + getProcessor().process(exchange); + return 1; // number of messages polled + } finally { + // log exception if an exception occurred and was not handled + if (exchange.getException() != null) { + getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException()); + } + } + } +} diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java new file mode 100644 index 0000000000000..77b45eb591ec5 --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java @@ -0,0 +1,229 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import java.io.*; +import java.security.KeyPair; + +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.impl.ScheduledPollEndpoint; +import org.apache.sshd.ClientChannel; +import org.apache.sshd.ClientSession; +import org.apache.sshd.SshClient; +import org.apache.sshd.client.future.AuthFuture; +import org.apache.sshd.client.future.ConnectFuture; +import org.apache.sshd.client.future.OpenFuture; +import org.apache.sshd.common.KeyPairProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents an SSH endpoint. + */ +public class SshEndpoint extends ScheduledPollEndpoint { + protected final transient Logger log = LoggerFactory.getLogger(getClass()); + + private SshClient client; + private SshConfiguration sshConfiguration; + + public SshEndpoint() { + } + + public SshEndpoint(String uri, SshComponent component) { + super(uri, component); + } + + public SshEndpoint(String uri, SshComponent component, SshConfiguration configuration) { + super(uri, component); + this.sshConfiguration = configuration; + } + + @Override + public Producer createProducer() throws Exception { + return new SshProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + SshConsumer consumer = new SshConsumer(this, processor); + + configureConsumer(consumer); + + return consumer; + } + + @Override + public boolean isSingleton() { + return false; + } + + public byte[] sendExecCommand(String command) throws Exception { + byte[] result = null; + + if (getConfiguration() == null) { + throw new IllegalStateException("configuration must be set"); + } + + ConnectFuture connectFuture = client.connect(getHost(), getPort()); + + // Wait getTimeout milliseconds for connect operation to complete + connectFuture.await(getTimeout()); + + if (!connectFuture.isDone() || !connectFuture.isConnected()) { + final String msg = "Failed to connect to " + getHost() + ":" + getPort() + " within timeout " + getTimeout() + "ms"; + log.debug(msg); + throw new RuntimeCamelException(msg); + } + + log.debug("Connected to {}:{}", getHost(), getPort()); + + AuthFuture authResult; + ClientSession session = connectFuture.getSession(); + + final KeyPairProvider keyPairProvider = getKeyPairProvider(); + if (keyPairProvider != null) { + log.debug("Attempting to authenticate username '{}' using Key...", getUsername()); + KeyPair pair = keyPairProvider.loadKey(getKeyType()); + authResult = session.authPublicKey(getUsername(), pair); + } else { + log.debug("Attempting to authenticate username '{}' using Password...", getUsername()); + authResult = session.authPassword(getUsername(), getPassword()); + } + + authResult.await(getTimeout()); + + if (!authResult.isDone() || authResult.isFailure()) { + log.debug("Failed to authenticate"); + throw new RuntimeCamelException("Failed to authenticate username " + getUsername()); + } + + ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_EXEC, command); + + ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0}); + channel.setIn(in); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + channel.setOut(out); + + ByteArrayOutputStream err = new ByteArrayOutputStream(); + channel.setErr(err); + + OpenFuture openFuture = channel.open(); + + openFuture.await(getTimeout()); + + if (openFuture.isOpened()) { + channel.waitFor(ClientChannel.CLOSED, 0); + result = out.toByteArray(); + } + + return result; + } + + @Override + protected void doStart() throws Exception { + super.doStart(); + + client = SshClient.setUpDefaultClient(); + client.start(); + } + + @Override + protected void doStop() throws Exception { + if (client != null) { + client.stop(); + client = null; + } + + super.doStop(); + } + + public SshConfiguration getConfiguration() { + return sshConfiguration; + } + + public void setConfiguration(SshConfiguration configuration) { + this.sshConfiguration = configuration; + } + + public String getHost() { + return getConfiguration().getHost(); + } + + public void setHost(String host) { + getConfiguration().setHost(host); + } + + public int getPort() { + return getConfiguration().getPort(); + } + + public void setPort(int port) { + getConfiguration().setPort(port); + } + + public String getUsername() { + return getConfiguration().getUsername(); + } + + public void setUsername(String username) { + getConfiguration().setUsername(username); + } + + public String getPassword() { + return getConfiguration().getPassword(); + } + + public void setPassword(String password) { + getConfiguration().setPassword(password); + } + + public String getPollCommand() { + return getConfiguration().getPollCommand(); + } + + public void setPollCommand(String pollCommand) { + getConfiguration().setPollCommand(pollCommand); + } + + public KeyPairProvider getKeyPairProvider() { + return getConfiguration().getKeyPairProvider(); + } + + public void setKeyPairProvider(KeyPairProvider keyPairProvider) { + getConfiguration().setKeyPairProvider(keyPairProvider); + } + + public String getKeyType() { + return getConfiguration().getKeyType(); + } + + public void setKeyType(String keyType) { + getConfiguration().setKeyType(keyType); + } + + public long getTimeout() { + return getConfiguration().getTimeout(); + } + + public void setTimeout(long timeout) { + getConfiguration().setTimeout(timeout); + } +} diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.java new file mode 100644 index 0000000000000..2edc73a04a1b4 --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.CamelExchangeException; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.impl.DefaultProducer; + +public class SshProducer extends DefaultProducer { + private SshEndpoint endpoint; + + public SshProducer(SshEndpoint endpoint) { + super(endpoint); + this.endpoint = endpoint; + } + + @Override + public void process(Exchange exchange) throws Exception { + final Message in = exchange.getIn(); + final Message out = exchange.getOut(); + + String command = in.getBody(String.class); + + try { + byte[] result = endpoint.sendExecCommand(command); + + out.setBody(result); + } catch (Exception e) { + throw new CamelExchangeException(e.getMessage(), exchange, e); + } + + // propagate headers and attachments + out.getHeaders().putAll(in.getHeaders()); + out.setAttachments(in.getAttachments()); + } +} \ No newline at end of file diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html new file mode 100644 index 0000000000000..f24393f50eb5b --- /dev/null +++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html @@ -0,0 +1,25 @@ + + + + + + +Defines the SSH Component + + + diff --git a/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh b/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh new file mode 100644 index 0000000000000..1f76f468d7f2a --- /dev/null +++ b/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +class=org.apache.camel.component.ssh.SshComponent diff --git a/components/camel-ssh/src/main/resources/log4j.properties b/components/camel-ssh/src/main/resources/log4j.properties new file mode 100644 index 0000000000000..4621723d31a1b --- /dev/null +++ b/components/camel-ssh/src/main/resources/log4j.properties @@ -0,0 +1,16 @@ + +# +# The logging properties used +# +log4j.rootLogger=INFO, out + +# uncomment the following line to turn on Camel debugging +#log4j.logger.org.apache.camel=DEBUG + +# CONSOLE appender not used by default +log4j.appender.out=org.apache.log4j.ConsoleAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n +#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n + +log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer \ No newline at end of file diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java new file mode 100644 index 0000000000000..9ad5ee2aede19 --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.session.ServerSession; + +/** + * TODO Add javadoc + * + * @author Apache MINA SSHD Project + */ +public class BogusPasswordAuthenticator implements PasswordAuthenticator { + + @Override + public boolean authenticate(String username, String password, ServerSession session) { + return username != null && username.equals(password); + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java new file mode 100644 index 0000000000000..52e05d3329f08 --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import java.security.PublicKey; + +import org.apache.sshd.server.PublickeyAuthenticator; +import org.apache.sshd.server.session.ServerSession; + +/** + * TODO Add javadoc + * + * @author Apache MINA SSHD Project + */ +public class BogusPublickeyAuthenticator implements PublickeyAuthenticator { + + @Override + public boolean authenticate(String username, PublicKey key, ServerSession session) { + return true; + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java new file mode 100644 index 0000000000000..5873365651855 --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java @@ -0,0 +1,93 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import java.io.*; + +import org.apache.sshd.server.Command; +import org.apache.sshd.server.CommandFactory; +import org.apache.sshd.server.Environment; +import org.apache.sshd.server.ExitCallback; + +/** + * TODO Add javadoc + * + * @author Apache MINA SSHD Project + */ +public class EchoCommandFactory implements CommandFactory { + + @Override + public Command createCommand(String command) { + return new EchoCommand(command); + } + + protected static class EchoCommand implements Command, Runnable { + private String command; + private InputStream in; + private OutputStream out; + private OutputStream err; + private ExitCallback callback; + private Thread thread; + + public EchoCommand(String command) { + this.command = command; + } + + @Override + public void setInputStream(InputStream in) { + this.in = in; + } + + @Override + public void setOutputStream(OutputStream out) { + this.out = out; + } + + @Override + public void setErrorStream(OutputStream err) { + this.err = err; + } + + @Override + public void setExitCallback(ExitCallback callback) { + this.callback = callback; + } + + @Override + public void start(Environment env) throws IOException { + thread = new Thread(this, "EchoCommand"); + thread.start(); + } + + @Override + public void destroy() { + thread.interrupt(); + } + + @Override + public void run() { + try { + out.write(command.getBytes()); + out.flush(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + callback.onExit(0); + } + } + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java new file mode 100644 index 0000000000000..7d7525e54f5ae --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; + +public class SshComponentConsumerTest extends SshComponentTestSupport { + @Test + public void testPollingConsumer() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived("test\r"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + from("ssh://smx:smx@localhost:" + port + "?useFixedDelay=true&delay=5000&pollCommand=test%0D") + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java new file mode 100644 index 0000000000000..cd51c6752786e --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; + +public class SshComponentErrorHandlingTest extends SshComponentTestSupport { + @Test + public void testRedelivery() throws Exception { + final String msg = "test\n"; + + MockEndpoint mockError = getMockEndpoint("mock:error"); + mockError.expectedMinimumMessageCount(0); + + MockEndpoint mock = getMockEndpoint("mock:success"); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived(msg); + mock.expectedHeaderReceived(Exchange.REDELIVERED, true); + + sshd.stop(); + + template.sendBody("direct:redeliver", msg); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + errorHandler(deadLetterChannel("mock:error") + .maximumRedeliveries(3) + .redeliveryDelay(0L) // speedup unit test by not waiting between redeliveries + .onRedelivery(new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + final Message in = exchange.getIn(); + final int count = in.getHeader(Exchange.REDELIVERY_COUNTER, Integer.class); + final int maxCount = in.getHeader(Exchange.REDELIVERY_MAX_COUNTER, Integer.class); + + log.info("Redelivery count = {}", count); + + // Restart the sshd server before the last redelivery attempt + if (count >= (maxCount - 1)) { + if (sshd != null) { + sshd.start(); + log.info("Restarting SSHD"); + } + } + } + })); + + from("direct:redeliver") + .tracing() + .to("ssh://smx:smx@localhost:" + port) + .to("mock:success"); + } + }; + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java new file mode 100644 index 0000000000000..1da5a1befe764 --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.sshd.common.KeyPairProvider; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; +import org.junit.Test; + +public class SshComponentProducerTest extends SshComponentTestSupport { + @Test + public void testProducer() throws Exception { + final String msg = "test\n"; + + MockEndpoint mock = getMockEndpoint("mock:password"); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived(msg); + + template.sendBody("direct:ssh", msg); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testReconnect() throws Exception { + final String msg = "test\n"; + + MockEndpoint mock = getMockEndpoint("mock:password"); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived(msg); + + template.sendBody("direct:ssh", msg); + + assertMockEndpointsSatisfied(); + + sshd.stop(); + sshd.start(); + + mock.reset(); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived(msg); + + template.sendBody("direct:ssh", msg); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testRsa() throws Exception { + final String msg = "test\n"; + + MockEndpoint mock = getMockEndpoint("mock:rsa"); + mock.expectedMinimumMessageCount(1); + mock.expectedBodiesReceived(msg); + + template.sendBody("direct:ssh-rsa", msg); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testConnectionTimeout() throws Exception { + final String msg = "test\n"; + + MockEndpoint mock = getMockEndpoint("mock:password"); + mock.expectedMinimumMessageCount(0); + + MockEndpoint mockError = getMockEndpoint("mock:error"); + mockError.expectedMinimumMessageCount(1); + + sshd.stop(); + sshd = null; + + template.sendBody("direct:ssh", msg); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + onException(Exception.class) + .handled(true) + .to("mock:error"); + + from("direct:ssh") + .to("ssh://smx:smx@localhost:" + port + "?timeout=3000") + .to("mock:password"); + + SshComponent sshComponent = new SshComponent(); + sshComponent.setHost("localhost"); + sshComponent.setPort(port); + sshComponent.setUsername("smx"); + sshComponent.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"})); + sshComponent.setKeyType(KeyPairProvider.SSH_RSA); + + getContext().addComponent("ssh-rsa", sshComponent); + + from("direct:ssh-rsa") + .to("ssh-rsa:test") + .to("mock:rsa"); + } + }; + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java new file mode 100644 index 0000000000000..3a2eb1ddcdd3d --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.ssh; + +import org.apache.camel.test.AvailablePortFinder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.sshd.SshServer; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; + +public class SshComponentTestSupport extends CamelTestSupport { + protected SshServer sshd; + protected int port; + + @Override + public void setUp() throws Exception { + port = AvailablePortFinder.getNextAvailable(22000); + + sshd = SshServer.setUpDefaultServer(); + sshd.setPort(port); + sshd.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"})); + sshd.setCommandFactory(new TestEchoCommandFactory()); + sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator()); + sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator()); + sshd.start(); + + super.setUp(); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + + if (sshd != null) { + sshd.stop(true); + Thread.sleep(50); + } + } +} diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.java new file mode 100644 index 0000000000000..f412502fcb1ea --- /dev/null +++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.component.ssh; + +import java.util.concurrent.CountDownLatch; + +import org.apache.sshd.server.Command; + +public class TestEchoCommandFactory extends EchoCommandFactory { + @Override + public Command createCommand(String command) { + return new TestEchoCommand(command); + } + + public static class TestEchoCommand extends EchoCommand { + public static CountDownLatch latch = new CountDownLatch(1); + + public TestEchoCommand(String command) { + super(command); + } + + @Override + public void destroy() { + if (latch != null) { + latch.countDown(); + } + super.destroy(); + } + } +} \ No newline at end of file diff --git a/components/camel-ssh/src/test/resources/dsaprivkey.pem b/components/camel-ssh/src/test/resources/dsaprivkey.pem new file mode 100644 index 0000000000000..c920b7fc04e23 --- /dev/null +++ b/components/camel-ssh/src/test/resources/dsaprivkey.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQDEA7leYDKyJOFJU3h0uPpWN52iTpJk8+IM53Vc/91k7pBIjjka ++MP24BMh+sI2SRhxg2AtvwnzRRBVJWzEA4+tuCI6WukgeDQtSNp3YuWzOMefZ6Wb +SAk1Y4goZb7nyqV9HZSFNSqUFQRZM10L768VURBlerNqR//GqdVd8bp7lwIVAM39 +h6x2DeXbqUM8iOi01bh5jpLFAoGAEi1oFGFMEZXH/hCX+Y2VE5WvR+fBaoS9WuZl +3E0wsWPzQhbL13yD+6Htxd3XoQvrHnzyrIgi2AiAmr3mLokQbZ3d92IxEBcNB/0p +nVi020TXSeD/lWkpk5FRvgBiJ82/LeC2Lj6cssznX73aLUhR0tsSoJoXxas0sQKa +/UJgq5wCgYAtgeY99J0JxplWGSyGY/1DUpgzhdgpLdDA/o/qIjBEeHXN0QX4Ajoa +vHggJ2SwNtAxbQedBxqmB3mquFRtpfEP5zGzsVx5HHnljSH8u0SqEoLnYKFpluwh +tZ/Q3F2NHslXw8Hw+pIaPe4PAINQPAu3U+BknNUkGpLg8zU6h5+B+wIVAKRqeps1 +Xl7MxZcSZp7FnmmmMecB +-----END DSA PRIVATE KEY----- diff --git a/components/camel-ssh/src/test/resources/hostkey.pem b/components/camel-ssh/src/test/resources/hostkey.pem new file mode 100644 index 0000000000000..6b6974c78e606 --- /dev/null +++ b/components/camel-ssh/src/test/resources/hostkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDdfIWeSV4o68dRrKSzFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDP +jXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHj +W5q4OOgWhVvj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQIDAQAB +AoGBANG3JDW6NoP8rF/zXoeLgLCj+tfVUPSczhGFVrQkAk4mWfyRkhN0WlwHFOec +K89MpkV1ij/XPVzU4MNbQ2yod1KiDylzvweYv+EaEhASCmYNs6LS03punml42SL9 +97tOmWfVJXxlQoLiY6jHPU97vTc65k8gL+gmmrpchsW0aqmZAkEA/c8zfmKvY37T +cxcLLwzwsqqH7g2KZGTf9aRmx2ebdW+QKviJJhbdluDgl1TNNFj5vCLznFDRHiqJ +wq0wkZ39cwJBAN9l5v3kdXj21UrurNPdlV0n2GZBt2vblooQC37XHF97r2zM7Ou+ +Lg6MyfJClyguhWL9dxnGbf3btQ0l3KDstxMCQCRaiEqjAfIjWVATzeNIXDWLHXso +b1kf5cA+cwY+vdKdTy4IeUR+Y/DXdvPWDqpf0C11aCVMohdLCn5a5ikFUycCQDhV +K/BuAallJNfmY7JxN87r00fF3ojWMJnT/fIYMFFrkQrwifXQWTDWE76BSDibsosJ +u1TGksnm8zrDh2UVC/0CQFrHTiSl/3DHvWAbOJawGKg46cnlDcAhSyV8Frs8/dlP +7YGG3eqkw++lsghqmFO6mRUTKsBmiiB2wgLGhL5pyYY= +-----END RSA PRIVATE KEY----- diff --git a/components/pom.xml b/components/pom.xml index 2103f459ff8df..439cad6610d94 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -136,6 +136,7 @@ camel-spring-security camel-spring-ws camel-sql + camel-ssh camel-stax camel-stream camel-stringtemplate diff --git a/examples/camel-example-ssh/README.txt b/examples/camel-example-ssh/README.txt new file mode 100644 index 0000000000000..26e0c61153d0c --- /dev/null +++ b/examples/camel-example-ssh/README.txt @@ -0,0 +1,42 @@ +SSH Example +===================== + +This example shows how use SSH with Camel. It can be run using Maven. + +This example is built assuming you have a running Apache ServiceMix container with the default SSH port 8101 and +username / password of smx/smx. + +Running from cmd line outside OSGi container +============================================ + +You will need to compile this example first: + mvn compile + +To run the example using Maven type + mvn camel:run + +To stop the example hit ctrl + c + + + +Running inside OSGi container +============================= + +You will need to compile and install this example first: + mvn compile install + +If using Apache Karaf / Apache ServiceMix you can install this example +from the shell + + > features:addurl mvn:org.apache.camel/camel-example-ssh//xml/features + > features:install camel-example-ssh + +If you hit any problems please let us know on the Camel Forums + http://camel.apache.org/discussion-forums.html + +Please help us make Apache Camel better - we appreciate any feedback you +may have. Enjoy! + +------------------------ +The Camel riders! + diff --git a/examples/camel-example-ssh/pom.xml b/examples/camel-example-ssh/pom.xml new file mode 100644 index 0000000000000..9370c75defb12 --- /dev/null +++ b/examples/camel-example-ssh/pom.xml @@ -0,0 +1,120 @@ + + + + + + + 4.0.0 + + + org.apache.camel + examples + 2.10-SNAPSHOT + .. + + + camel-example-ssh + bundle + Camel :: Example :: SSH + A simple SSH example which creates a bundle that can be dropped into any OSGi container + + + org.apache.camel.example.ssh.* + + + + + + org.apache.camel + camel-core + + + org.apache.camel + camel-spring + + + org.apache.camel + camel-ssh + ${project.version} + + + org.apache.mina + mina-core + 2.0.1 + + + + + org.slf4j + slf4j-simple + ${slf4j-version} + + + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + + org.apache.camel.component.ssh, + * + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + package + + attach-artifact + + + + + target/classes/features.xml + xml + features + + + + + + + + + + org.apache.camel + camel-maven-plugin + ${project.version} + + + + + + diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt new file mode 100644 index 0000000000000..6b0b1270ff0ca --- /dev/null +++ b/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt new file mode 100644 index 0000000000000..2e215bf2e6b1f --- /dev/null +++ b/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt @@ -0,0 +1,11 @@ + ========================================================================= + == NOTICE file corresponding to the section 4 d of == + == the Apache License, Version 2.0, == + == in this case for the Apache Camel distribution. == + ========================================================================= + + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Please read the different LICENSE files present in the licenses directory of + this distribution. diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml b/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml new file mode 100644 index 0000000000000..fd75c686cd6f1 --- /dev/null +++ b/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + features:list + + + + + + + diff --git a/examples/camel-example-ssh/src/main/resources/features.xml b/examples/camel-example-ssh/src/main/resources/features.xml new file mode 100644 index 0000000000000..c9058427506b4 --- /dev/null +++ b/examples/camel-example-ssh/src/main/resources/features.xml @@ -0,0 +1,26 @@ + + + + mvn:org.apache.camel.karaf/apache-camel/${project.version}/xml/features + + + camel-ssh + mvn:org.apache.camel/camel-example-ssh/${project.version} + + + \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index ba9b99f6477b0..3051cfe657461 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -63,6 +63,7 @@ camel-example-spring-ws camel-example-spring-xquery camel-example-spring-security + camel-example-ssh camel-example-tracer diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml index ea78a26196d12..d47530208b090 100644 --- a/platforms/karaf/features/src/main/resources/features.xml +++ b/platforms/karaf/features/src/main/resources/features.xml @@ -667,6 +667,12 @@ camel-core mvn:org.apache.camel/camel-sql/${project.version} + + camel-core + mvn:org.apache.mina/mina-core/2.0.2 + mvn:org.apache.sshd/sshd-core/0.6.0 + mvn:org.apache.camel/camel-ssh/${project.version} + camel-core mvn:org.apache.camel/camel-stax/${project.version}