blob: 56151129d10f7e225073d01026100686fefb2b0a [file] [log] [blame]
jaegonkimdcf7c822019-02-06 15:00:14 +09001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.ofoverlay.impl.util;
17
18import com.jcraft.jsch.Channel;
19import com.jcraft.jsch.ChannelSftp;
20import com.jcraft.jsch.JSch;
21import com.jcraft.jsch.JSchException;
22import com.jcraft.jsch.KeyPair;
23import com.jcraft.jsch.Session;
24import com.jcraft.jsch.SftpATTRS;
25import com.jcraft.jsch.SftpException;
26import org.onlab.packet.IpAddress;
27import org.slf4j.Logger;
28
29import java.io.File;
30import java.io.FileInputStream;
31import java.io.IOException;
32import java.nio.file.Files;
33import java.nio.file.Paths;
34import java.util.stream.Collectors;
35import java.util.stream.Stream;
36
37import static org.slf4j.LoggerFactory.getLogger;
38
39/**
40 * Class for SSH key exchange.
41 */
42public class SshkeyExchange {
43
44 protected static final Logger log = getLogger(SshkeyExchange.class);
45 private static final String HOME_ENV = System.getProperty("user.home");
46 private static final String USER_ENV = System.getProperty("user.name");
47 private static final String PUBLIC_KEY = "/.ssh/id_rsa.pub";
48 private static final String PRIVATE_KEY = "/.ssh/id_rsa";
49 private static final String SFTP_CHANNEL = "sftp";
50 private static final String SSH_HOME = "/.ssh/";
51 private static final String SSH_AUTH_KEY = "/.ssh/authorized_keys";
52 private static final int SFTPPORT = 22;
53 private static final int DIR_PER = 448;
54 private static final int FILE_PER = 384;
55 private static final int KEY_SIZE = 2048;
56 private static final int DEFAULT_SESSION_TIMEOUT = 30000; // milliseconds
57
58 private Session getJschSession(String user, String host, String password) {
59 java.util.Properties config = new java.util.Properties();
60 config.put("StrictHostKeyChecking", "no");
61 Session session;
62 try {
63 session = new JSch().getSession(user, host, SFTPPORT);
64 session.setPassword(password);
65 session.setConfig(config);
66 } catch (JSchException e) {
67 log.error("Exception in getJschSession", e);
68 return null;
69 }
70
71 return session;
72 }
73
74 private boolean generateKeyPair() {
75 KeyPair kpair;
76 StringBuilder command = new StringBuilder()
77 .append("chmod 600 ")
78 .append(HOME_ENV)
79 .append(PRIVATE_KEY);
80 try {
81 kpair = KeyPair.genKeyPair(new JSch(), KeyPair.RSA, KEY_SIZE);
82 kpair.writePrivateKey(HOME_ENV + PRIVATE_KEY);
83 kpair.writePublicKey(HOME_ENV + PUBLIC_KEY, USER_ENV);
84 Runtime.getRuntime().exec(command.toString());
85 kpair.dispose();
86 } catch (JSchException | IOException e) {
87 log.error("Exception in generateKeyPair", e);
88 return false;
89 }
90 return true;
91 }
92
93 /**
94 * Exchanges SSH key.
95 * @param host SSH server host
96 * @param user user
97 * @param password password
98 * @return SSH key exchange success or not
99 */
100 public boolean sshAutoKeyExchange(IpAddress host, String user, String password) {
101
102 Session session = getJschSession(user, host.toString(), password);
103 boolean returnFlag;
104 File publickeyPath = new File(HOME_ENV + PUBLIC_KEY);
105 if (session == null) {
106 log.error("Error While establishing SFTP connection with {}", host.toString());
107 return false;
108 }
109 Channel channel;
110 String remoteHome;
111 ChannelSftp sftp;
112 FileInputStream fis = null;
113 SftpATTRS attrs = null;
114 try {
115 session.connect(DEFAULT_SESSION_TIMEOUT);
116 channel = session.openChannel(SFTP_CHANNEL);
117 if (channel == null) {
118 log.error("SFTP channel open failed for {}", host.toString());
119 return false;
120 }
121 channel.connect();
122 sftp = (ChannelSftp) channel;
123 remoteHome = sftp.getHome();
124 // checking key pair existance
125
126 if (!publickeyPath.exists()) {
127 File dirs = new File(HOME_ENV + SSH_HOME);
128 if (!dirs.exists() && !dirs.mkdirs()) {
129 log.error("{} not exists and unable to create ", dirs.getPath());
130 return false;
131 } else if (!generateKeyPair()) {
132 log.error("SSH Key pair generation failed");
133 return false;
134 }
135 }
136
137 // checking for authenticate_keys file existance
138 fis = new FileInputStream(publickeyPath);
139 try {
140 sftp.lstat(remoteHome + SSH_HOME);
141 } catch (SftpException e) {
142 sftp.mkdir(remoteHome + SSH_HOME);
143 sftp.chmod(700, remoteHome + SSH_HOME);
144 }
145 try {
146 attrs = sftp.lstat(remoteHome + SSH_AUTH_KEY);
147 } catch (SftpException e) {
148 log.info("authorized_keys file does not exist at remote device ,"
149 + "a new file will be created");
150 }
151
152 if (attrs != null) {
153 sftp.get(remoteHome + SSH_AUTH_KEY, HOME_ENV + "/tempauthorized_keys");
154
155 String pubKey;
156 try (Stream<String> st = Files.lines(Paths.get(HOME_ENV + PUBLIC_KEY))) {
157 pubKey = st.collect(Collectors.joining());
158 }
159
160 String authKey;
161 try (Stream<String> st = Files.lines(Paths.get(HOME_ENV + "/tempauthorized_keys"))) {
162 authKey = st.collect(Collectors.joining());
163 }
164
165 if (authKey.contains(pubKey)) {
166 log.info("Skipping key append to server as Key is already added");
167 } else {
168 sftp.put(fis, remoteHome + SSH_AUTH_KEY, ChannelSftp.APPEND);
169 log.info("Public key appended to server");
170 }
171 } else {
172
173 sftp.put(fis, remoteHome + SSH_AUTH_KEY, ChannelSftp.APPEND);
174 // Give proper permission to file and directory.
175 sftp.chmod(DIR_PER, remoteHome + SSH_HOME);
176 sftp.chmod(FILE_PER, remoteHome + SSH_AUTH_KEY);
177 log.info("Public key appended to server");
178 }
179
180 sftp.exit();
181 session.disconnect();
182 returnFlag = true;
183 } catch (JSchException | SftpException | IOException e) {
184 log.error("Exception occured because of {} ", e);
185 returnFlag = false;
186 } finally {
187 if (fis != null) {
188 try {
189 fis.close();
190 } catch (IOException e) {
191 log.info("Error closing public key file");
192 }
193 }
194 }
195 return returnFlag;
196
197 }
198}