001package org.apache.maven.scm.provider.cvslib.cvsjava.util; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import ch.ethz.ssh2.Connection; 023import ch.ethz.ssh2.Session; 024import ch.ethz.ssh2.StreamGobbler; 025import org.netbeans.lib.cvsclient.CVSRoot; 026import org.netbeans.lib.cvsclient.command.CommandAbortedException; 027import org.netbeans.lib.cvsclient.connection.AbstractConnection; 028import org.netbeans.lib.cvsclient.connection.AuthenticationException; 029import org.netbeans.lib.cvsclient.connection.ConnectionModifier; 030import org.netbeans.lib.cvsclient.util.LoggedDataInputStream; 031import org.netbeans.lib.cvsclient.util.LoggedDataOutputStream; 032 033import java.io.BufferedReader; 034import java.io.File; 035import java.io.IOException; 036import java.io.InputStream; 037import java.io.InputStreamReader; 038 039/** 040 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a> 041 * 042 */ 043public class ExtConnection 044 extends AbstractConnection 045{ 046 private String host; 047 048 private int port; 049 050 private String userName; 051 052 private String password; 053 054 private Connection connection; 055 056 private Session session; 057 058 private BufferedReader stderrReader; 059 060 public ExtConnection( CVSRoot cvsRoot ) 061 { 062 this( cvsRoot.getHostName(), cvsRoot.getPort(), cvsRoot.getUserName(), cvsRoot.getPassword(), 063 cvsRoot.getRepository() ); 064 } 065 066 public ExtConnection( String host, int port, String username, String password, String repository ) 067 { 068 this.userName = username; 069 070 if ( this.userName == null ) 071 { 072 this.userName = System.getProperty( "user.name" ); 073 } 074 075 this.password = password; 076 077 this.host = host; 078 079 setRepository( repository ); 080 081 this.port = port; 082 083 if ( this.port == 0 ) 084 { 085 this.port = 22; 086 } 087 } 088 089 /** {@inheritDoc} */ 090 public void open() 091 throws AuthenticationException, CommandAbortedException 092 { 093 connection = new Connection( host, port ); 094 095 /* TODO: add proxy support 096 ProxyData proxy = new HTTPProxyData( proxyHost, proxyPort, proxyUserName, proxyPassword ); 097 098 connection.setProxyData( proxy ); 099 */ 100 101 try 102 { 103 // TODO: connection timeout? 104 connection.connect(); 105 } 106 catch ( IOException e ) 107 { 108 String message = "Cannot connect. Reason: " + e.getMessage(); 109 throw new AuthenticationException( message, e, message ); 110 } 111 112 File privateKey = getPrivateKey(); 113 114 try 115 { 116 boolean authenticated; 117 if ( privateKey != null && privateKey.exists() ) 118 { 119 authenticated = connection.authenticateWithPublicKey( userName, privateKey, getPassphrase() ); 120 } 121 else 122 { 123 authenticated = connection.authenticateWithPassword( userName, password ); 124 } 125 126 if ( !authenticated ) 127 { 128 String message = "Authentication failed."; 129 throw new AuthenticationException( message, message ); 130 } 131 } 132 catch ( IOException e ) 133 { 134 closeConnection(); 135 String message = "Cannot authenticate. Reason: " + e.getMessage(); 136 throw new AuthenticationException( message, e, message ); 137 } 138 139 try 140 { 141 session = connection.openSession(); 142 } 143 catch ( IOException e ) 144 { 145 String message = "Cannot open session. Reason: " + e.getMessage(); 146 throw new CommandAbortedException( message, message ); 147 } 148 149 String command = "cvs server"; 150 try 151 { 152 session.execCommand( command ); 153 } 154 catch ( IOException e ) 155 { 156 String message = "Cannot execute remote command: " + command; 157 throw new CommandAbortedException( message, message ); 158 } 159 160 InputStream stdout = new StreamGobbler( session.getStdout() ); 161 InputStream stderr = new StreamGobbler( session.getStderr() ); 162 stderrReader = new BufferedReader( new InputStreamReader( stderr ) ); 163 setInputStream( new LoggedDataInputStream( stdout ) ); 164 setOutputStream( new LoggedDataOutputStream( session.getStdin() ) ); 165 } 166 167 /** {@inheritDoc} */ 168 public void verify() 169 throws AuthenticationException 170 { 171 try 172 { 173 open(); 174 verifyProtocol(); 175 close(); 176 } 177 catch ( Exception e ) 178 { 179 String message = "Failed to verify the connection: " + e.getMessage(); 180 throw new AuthenticationException( message, e, message ); 181 } 182 } 183 184 private void closeConnection() 185 { 186 try 187 { 188 if ( stderrReader != null ) 189 { 190 while ( true ) 191 { 192 String line = stderrReader.readLine(); 193 if ( line == null ) 194 { 195 break; 196 } 197 198 System.err.println( line ); 199 } 200 } 201 } 202 catch ( IOException e ) 203 { 204 //nothing to do 205 } 206 207 if ( session != null ) 208 { 209 System.out.println( "Exit code:" + session.getExitStatus().intValue() ); 210 session.close(); 211 } 212 213 if ( connection != null ) 214 { 215 connection.close(); 216 } 217 218 reset(); 219 } 220 221 private void reset() 222 { 223 connection = null; 224 session = null; 225 stderrReader = null; 226 setInputStream( null ); 227 setOutputStream( null ); 228 } 229 230 /** {@inheritDoc} */ 231 public void close() 232 throws IOException 233 { 234 closeConnection(); 235 } 236 237 /** {@inheritDoc} */ 238 public boolean isOpen() 239 { 240 return connection != null; 241 } 242 243 /** {@inheritDoc} */ 244 public int getPort() 245 { 246 return port; 247 } 248 249 /** {@inheritDoc} */ 250 public void modifyInputStream( ConnectionModifier modifier ) 251 throws IOException 252 { 253 modifier.modifyInputStream( getInputStream() ); 254 } 255 256 /** {@inheritDoc} */ 257 public void modifyOutputStream( ConnectionModifier modifier ) 258 throws IOException 259 { 260 modifier.modifyOutputStream( getOutputStream() ); 261 } 262 263 private File getPrivateKey() 264 { 265 // If user don't define a password, he want to use a private key 266 File privateKey = null; 267 if ( password == null ) 268 { 269 String pk = System.getProperty( "maven.scm.cvs.java.ssh.privateKey" ); 270 if ( pk != null ) 271 { 272 privateKey = new File( pk ); 273 } 274 else 275 { 276 privateKey = findPrivateKey(); 277 } 278 } 279 return privateKey; 280 } 281 282 private String getPassphrase() 283 { 284 String passphrase = System.getProperty( "maven.scm.cvs.java.ssh.passphrase" ); 285 286 if ( passphrase == null ) 287 { 288 passphrase = ""; 289 } 290 291 return passphrase; 292 } 293 294 private File findPrivateKey() 295 { 296 String privateKeyDirectory = System.getProperty( "maven.scm.ssh.privateKeyDirectory" ); 297 298 if ( privateKeyDirectory == null ) 299 { 300 privateKeyDirectory = System.getProperty( "user.home" ); 301 } 302 303 File privateKey = new File( privateKeyDirectory, ".ssh/id_dsa" ); 304 305 if ( !privateKey.exists() ) 306 { 307 privateKey = new File( privateKeyDirectory, ".ssh/id_rsa" ); 308 } 309 310 return privateKey; 311 } 312}