1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.common.util.channel.model;
17
18 import static com.google.common.base.Optional.absent;
19 import static org.kuali.common.util.base.Precondition.checkNotBlank;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Properties;
25
26 import org.kuali.common.util.Assert;
27 import org.kuali.common.util.CollectionUtils;
28 import org.kuali.common.util.LocationUtils;
29 import org.kuali.common.util.channel.util.SSHUtils;
30 import org.kuali.common.util.enc.EncUtils;
31 import org.kuali.common.util.enc.EncryptionService;
32 import org.kuali.common.util.nullify.NullUtils;
33 import org.kuali.common.util.property.ImmutableProperties;
34 import org.kuali.common.util.spring.SpringUtils;
35 import org.kuali.common.util.spring.env.EnvUtils;
36 import org.kuali.common.util.spring.env.EnvironmentService;
37
38 import com.google.common.base.Charsets;
39 import com.google.common.base.Optional;
40 import com.google.common.collect.ImmutableList;
41
42
43
44
45 @Deprecated
46 public final class ChannelContext {
47
48 private final Optional<String> username;
49 private final String hostname;
50 private final List<String> privateKeys;
51 private final int port;
52 private final String encoding;
53 private final boolean strictHostKeyChecking;
54 private final boolean requestPseudoTerminal;
55 private final Optional<Integer> connectTimeout;
56 private final Properties options;
57 private final File knownHosts;
58 private final File config;
59 private final boolean useConfigFile;
60 private final boolean useKnownHosts;
61 private final boolean includeDefaultPrivateKeyLocations;
62 private final int waitForClosedSleepMillis;
63 private final List<File> privateKeyFiles;
64 private final boolean echo;
65 private final boolean debug;
66
67 public static class Builder {
68
69
70 private final String hostname;
71
72
73 private Optional<String> username = absent();
74 private int port = 22;
75 private Optional<Integer> connectTimeout = absent();
76 private String encoding = Charsets.UTF_8.name();
77 private Properties options = ImmutableProperties.of();
78 private boolean strictHostKeyChecking = false;
79 private boolean requestPseudoTerminal = false;
80 private File knownHosts = SSHUtils.DEFAULT_KNOWN_HOSTS;
81 private boolean useKnownHosts = false;
82 private File config = SSHUtils.DEFAULT_CONFIG_FILE;
83 private boolean useConfigFile = false;
84 private boolean includeDefaultPrivateKeyLocations = false;
85 private int waitForClosedSleepMillis = 10;
86 private List<File> privateKeyFiles = ImmutableList.of();
87 private List<String> privateKeys = ImmutableList.of();
88 private boolean echo = true;
89 private boolean debug = false;
90
91
92 private final Optional<EnvironmentService> env;
93 private final Optional<EncryptionService> enc;
94 private static final String HOSTNAME_KEY = "ssh.hostname";
95 private static final String USERNAME_KEY = "ssh.username";
96 private static final String REQUEST_PSEUDO_TERMINAL_KEY = "ssh.requestPseudoTerminal";
97 private static final String PRIVATE_KEYS_KEY = "ssh.privateKeys";
98 private static final String ECHO_KEY = "ssh.echo";
99 private static final String PORT_KEY = "ssh.port";
100 private static final String ENCODING_KEY = "ssh.encoding";
101 private static final String CONNECT_TIMEOUT_KEY = "ssh.connectTimeout";
102
103
104
105
106 public Builder(String hostname) {
107 this(EnvUtils.ABSENT, EncUtils.ABSENT, hostname);
108 }
109
110
111
112
113 public Builder(EnvironmentService env, String hostname) {
114 this(Optional.of(env), EncUtils.ABSENT, hostname);
115 }
116
117
118
119
120 public Builder(EnvironmentService env, EncryptionService enc, String hostname) {
121 this(Optional.of(env), Optional.of(enc), hostname);
122 }
123
124
125
126
127 private Builder(Optional<EnvironmentService> env, Optional<EncryptionService> enc, String hostname) {
128 if (env.isPresent()) {
129 this.hostname = env.get().getString(HOSTNAME_KEY, hostname);
130 } else {
131 this.hostname = hostname;
132 }
133 this.env = env;
134 this.enc = enc;
135 }
136
137 public Builder requestPseudoTerminal(boolean requestPseudoTerminal) {
138 this.requestPseudoTerminal = requestPseudoTerminal;
139 return this;
140 }
141
142 public Builder debug(boolean debug) {
143 this.debug = debug;
144 return this;
145 }
146
147 public Builder echo(boolean echo) {
148 this.echo = echo;
149 return this;
150 }
151
152 public Builder username(String username) {
153 this.username = NullUtils.toAbsent(username);
154 return this;
155 }
156
157 public Builder port(int port) {
158 this.port = port;
159 return this;
160 }
161
162 public Builder encoding(String encoding) {
163 this.encoding = encoding;
164 return this;
165 }
166
167 public Builder connectTimeout(int connectTimeout) {
168 this.connectTimeout = Optional.of(connectTimeout);
169 return this;
170 }
171
172 public Builder options(Properties options) {
173 this.options = options;
174 return this;
175 }
176
177 public Builder knownHosts(File knownHosts) {
178 this.knownHosts = knownHosts;
179 return this;
180 }
181
182 public Builder useKnownHosts(boolean useKnownHosts) {
183 this.useKnownHosts = useKnownHosts;
184 return this;
185 }
186
187 public Builder config(File config) {
188 this.config = config;
189 return this;
190 }
191
192 public Builder useConfigFile(boolean useConfigFile) {
193 this.useConfigFile = useConfigFile;
194 return this;
195 }
196
197 public Builder includeDefaultPrivateKeyLocations(boolean includeDefaultPrivateKeyLocations) {
198 this.includeDefaultPrivateKeyLocations = includeDefaultPrivateKeyLocations;
199 return this;
200 }
201
202 public Builder waitForClosedSleepMillis(int waitForClosedSleepMillis) {
203 this.waitForClosedSleepMillis = waitForClosedSleepMillis;
204 return this;
205 }
206
207 public Builder privateKeyFiles(List<File> privateKeyFiles) {
208 this.privateKeyFiles = privateKeyFiles;
209 return this;
210 }
211
212 public Builder privateKey(String privateKey) {
213 Optional<String> trimmed = NullUtils.toAbsent(privateKey);
214 if (trimmed.isPresent()) {
215 return privateKeys(ImmutableList.of(trimmed.get()));
216 } else {
217 return privateKeys(ImmutableList.<String> of());
218 }
219 }
220
221 public Builder privateKeys(List<String> privateKeys) {
222 this.privateKeys = privateKeys;
223 return this;
224 }
225
226
227
228
229 private void override() {
230 if (env.isPresent()) {
231 username(SpringUtils.getString(env.get(), USERNAME_KEY, username).orNull());
232 requestPseudoTerminal(env.get().getBoolean(REQUEST_PSEUDO_TERMINAL_KEY, requestPseudoTerminal));
233 privateKeys(SpringUtils.getStrings(env.get(), PRIVATE_KEYS_KEY, privateKeys));
234 echo(env.get().getBoolean(ECHO_KEY, echo));
235 port(env.get().getInteger(PORT_KEY, port));
236 encoding(env.get().getString(ENCODING_KEY, encoding));
237 Optional<Integer> connectTimeout = SpringUtils.getProperty(env, CONNECT_TIMEOUT_KEY, Integer.class, this.connectTimeout);
238 if (connectTimeout.isPresent()) {
239 connectTimeout(connectTimeout.get());
240 }
241 }
242 }
243
244 private void finish() {
245 override();
246 privateKeys(EncUtils.decrypt(enc, privateKeys));
247 this.privateKeyFiles = ImmutableList.copyOf(getUniquePrivateKeyFiles(privateKeyFiles, useConfigFile, config, includeDefaultPrivateKeyLocations));
248 this.privateKeys = ImmutableList.copyOf(privateKeys);
249 this.options = ImmutableProperties.copyOf(getSessionProperties(options, strictHostKeyChecking));
250 }
251
252 private static void validate(ChannelContext ctx) {
253 checkNotBlank(ctx.hostname, "hostname");
254 checkNotBlank(ctx.encoding, "encoding");
255 Assert.noNulls(ctx.getUsername(), ctx.getConnectTimeout(), ctx.getOptions(), ctx.getKnownHosts(), ctx.getConfig(), ctx.getPrivateKeyFiles(), ctx.getPrivateKeys());
256 Assert.isPort(ctx.getPort());
257 Assert.positive(ctx.getWaitForClosedSleepMillis());
258 Assert.notEncrypted(ctx.getPrivateKeys());
259 if (ctx.isUseConfigFile()) {
260 Assert.exists(ctx.getConfig());
261 Assert.isTrue(ctx.getConfig().canRead(), "[" + ctx.getConfig() + "] exists but is not readable");
262 }
263 if (ctx.getConnectTimeout().isPresent()) {
264 Assert.positive(ctx.getConnectTimeout().get());
265 }
266 }
267
268 public ChannelContext build() {
269 finish();
270 ChannelContext ctx = new ChannelContext(this);
271 validate(ctx);
272 return ctx;
273 }
274
275 private List<File> getUniquePrivateKeyFiles(List<File> privateKeyFiles, boolean useConfigFile, File config, boolean includeDefaultPrivateKeyLocations) {
276 List<String> paths = new ArrayList<String>();
277 for (File privateKeyFile : privateKeyFiles) {
278 paths.add(LocationUtils.getCanonicalPath(privateKeyFile));
279 }
280 if (useConfigFile) {
281 for (String path : SSHUtils.getFilenames(config)) {
282 paths.add(path);
283 }
284 }
285 if (includeDefaultPrivateKeyLocations) {
286 for (String path : SSHUtils.PRIVATE_KEY_DEFAULTS) {
287 paths.add(path);
288 }
289 }
290 List<String> uniquePaths = CollectionUtils.getUniqueStrings(paths);
291 return SSHUtils.getExistingAndReadable(uniquePaths);
292 }
293
294 private Properties getSessionProperties(Properties options, boolean strictHostKeyChecking) {
295 Properties properties = new Properties();
296 properties.putAll(options);
297 if (!strictHostKeyChecking) {
298 properties.setProperty(SSHUtils.STRICT_HOST_KEY_CHECKING, SSHUtils.NO);
299 }
300 return properties;
301 }
302 }
303
304 private ChannelContext(Builder builder) {
305 this.username = builder.username;
306 this.hostname = builder.hostname;
307 this.port = builder.port;
308 this.encoding = builder.encoding;
309 this.connectTimeout = builder.connectTimeout;
310 this.options = builder.options;
311 this.strictHostKeyChecking = builder.strictHostKeyChecking;
312 this.requestPseudoTerminal = builder.requestPseudoTerminal;
313 this.knownHosts = builder.knownHosts;
314 this.config = builder.config;
315 this.useConfigFile = builder.useConfigFile;
316 this.includeDefaultPrivateKeyLocations = builder.includeDefaultPrivateKeyLocations;
317 this.waitForClosedSleepMillis = builder.waitForClosedSleepMillis;
318 this.privateKeyFiles = builder.privateKeyFiles;
319 this.privateKeys = builder.privateKeys;
320 this.useKnownHosts = builder.useKnownHosts;
321 this.echo = builder.echo;
322 this.debug = builder.debug;
323 }
324
325 public Optional<String> getUsername() {
326 return username;
327 }
328
329 public String getHostname() {
330 return hostname;
331 }
332
333 public int getPort() {
334 return port;
335 }
336
337 public Optional<Integer> getConnectTimeout() {
338 return connectTimeout;
339 }
340
341 public String getEncoding() {
342 return encoding;
343 }
344
345 public Properties getOptions() {
346 return options;
347 }
348
349 public boolean isStrictHostKeyChecking() {
350 return strictHostKeyChecking;
351 }
352
353 public boolean isRequestPseudoTerminal() {
354 return requestPseudoTerminal;
355 }
356
357 public File getKnownHosts() {
358 return knownHosts;
359 }
360
361 public File getConfig() {
362 return config;
363 }
364
365 public boolean isUseConfigFile() {
366 return useConfigFile;
367 }
368
369 public boolean isUseKnownHosts() {
370 return useKnownHosts;
371 }
372
373 public boolean isIncludeDefaultPrivateKeyLocations() {
374 return includeDefaultPrivateKeyLocations;
375 }
376
377 public int getWaitForClosedSleepMillis() {
378 return waitForClosedSleepMillis;
379 }
380
381 public List<File> getPrivateKeyFiles() {
382 return privateKeyFiles;
383 }
384
385 public List<String> getPrivateKeys() {
386 return privateKeys;
387 }
388
389 public boolean isEcho() {
390 return echo;
391 }
392
393 public boolean isDebug() {
394 return debug;
395 }
396
397 }