1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.geronimo.gshell.commands.ssh;
21
22 import com.google.code.sshd.ClientChannel;
23 import com.google.code.sshd.ClientSession;
24 import com.google.code.sshd.SshClient;
25 import com.google.code.sshd.common.util.NoCloseInputStream;
26 import com.google.code.sshd.common.util.NoCloseOutputStream;
27 import org.apache.geronimo.gshell.clp.Argument;
28 import org.apache.geronimo.gshell.clp.Option;
29 import org.apache.geronimo.gshell.command.CommandAction;
30 import org.apache.geronimo.gshell.command.CommandContext;
31 import org.apache.geronimo.gshell.i18n.MessageSource;
32 import org.apache.geronimo.gshell.io.IO;
33 import org.apache.geronimo.gshell.io.PromptReader;
34 import org.apache.geronimo.gshell.spring.BeanContainer;
35 import org.apache.geronimo.gshell.spring.BeanContainerAware;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44 public class SshAction
45 implements CommandAction, BeanContainerAware
46 {
47 private final Logger log = LoggerFactory.getLogger(getClass());
48
49 @Option(name="-l", aliases={"--username"})
50 private String username;
51
52 @Option(name="-P", aliases={"--password"})
53 private String password;
54
55 @Argument(required=true)
56 private String hostname;
57
58 @Option(name="-p", aliases={"--port"})
59 private int port = 22;
60
61 private BeanContainer container;
62
63 public void setBeanContainer(final BeanContainer container) {
64 assert container != null;
65 this.container = container;
66 }
67
68
69
70
71 private class UsernamePasswordValidator
72 implements PromptReader.Validator
73 {
74 private String type;
75
76 private int count = 0;
77
78 private int max = 3;
79
80 public UsernamePasswordValidator(final String type) {
81 assert type != null;
82
83 this.type = type;
84 }
85
86 public boolean isValid(final String value) {
87 count++;
88
89 if (value != null && value.trim().length() > 0) {
90 return true;
91 }
92
93 if (count >= max) {
94 throw new RuntimeException("Too many attempts; failed to prompt user for " + type + " after " + max + " tries");
95 }
96
97 return false;
98 }
99 }
100
101 public Object execute(final CommandContext context) throws Exception {
102 assert context != null;
103 IO io = context.getIo();
104 MessageSource messages = context.getCommand().getMessages();
105
106
107
108
109
110 io.info(messages.format("info.connecting", hostname, port));
111
112
113 if (username == null || password == null) {
114 PromptReader prompter = new PromptReader(io);
115 String text;
116
117 log.debug("Prompting user for credentials");
118
119 if (username == null) {
120 text = messages.getMessage("prompt.username");
121 username = prompter.readLine(text + ": ", new UsernamePasswordValidator(text));
122 }
123
124 if (password == null) {
125 text = messages.getMessage("prompt.password");
126 password = prompter.readPassword(text + ": ", new UsernamePasswordValidator(text));
127 }
128 }
129
130
131 SshClient client = container.getBean(SshClient.class);
132 log.debug("Created client: {}", client);
133 client.start();;
134
135 try {
136 ClientSession session = client.connect(hostname, port);
137 try {
138 io.info(messages.getMessage("info.connected"));
139
140 session.authPassword(username, password);
141 int ret = session.waitFor(ClientSession.WAIT_AUTH | ClientSession.CLOSED | ClientSession.AUTHED, 0);
142 if ((ret & ClientSession.AUTHED) == 0) {
143 io.err.println("Authentication failed");
144 return Result.FAILURE;
145 }
146
147 ClientChannel channel = session.createChannel("shell");
148 channel.setIn(new NoCloseInputStream(io.inputStream));
149 channel.setOut(new NoCloseOutputStream(io.outputStream));
150 channel.setErr(new NoCloseOutputStream(io.errorStream));
151 channel.open();
152 channel.waitFor(ClientChannel.CLOSED, 0);
153 } finally {
154 session.close();
155 }
156 } finally {
157 client.stop();
158 }
159
160 io.verbose(messages.getMessage("verbose.disconnected"));
161
162 return Result.SUCCESS;
163 }
164 }