001    package 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    
022    import ch.ethz.ssh2.Connection;
023    import ch.ethz.ssh2.Session;
024    import ch.ethz.ssh2.StreamGobbler;
025    import org.netbeans.lib.cvsclient.CVSRoot;
026    import org.netbeans.lib.cvsclient.command.CommandAbortedException;
027    import org.netbeans.lib.cvsclient.connection.AbstractConnection;
028    import org.netbeans.lib.cvsclient.connection.AuthenticationException;
029    import org.netbeans.lib.cvsclient.connection.ConnectionModifier;
030    import org.netbeans.lib.cvsclient.util.LoggedDataInputStream;
031    import org.netbeans.lib.cvsclient.util.LoggedDataOutputStream;
032    
033    import java.io.BufferedReader;
034    import java.io.File;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.InputStreamReader;
038    
039    /**
040     * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
041     * @version $Id: ExtConnection.java 685548 2008-08-13 13:35:49Z vsiveton $
042     */
043    public 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    }