tikhomirov@699: /* tikhomirov@699: * Copyright (c) 2013 TMate Software Ltd tikhomirov@699: * tikhomirov@699: * This program is free software; you can redistribute it and/or modify tikhomirov@699: * it under the terms of the GNU General Public License as published by tikhomirov@699: * the Free Software Foundation; version 2 of the License. tikhomirov@699: * tikhomirov@699: * This program is distributed in the hope that it will be useful, tikhomirov@699: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@699: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@699: * GNU General Public License for more details. tikhomirov@699: * tikhomirov@699: * For information on how to redistribute this software under tikhomirov@699: * the terms of a license other than GNU General Public License tikhomirov@699: * contact TMate Software at support@hg4j.com tikhomirov@699: */ tikhomirov@699: package org.tmatesoft.hg.internal.remote; tikhomirov@699: tikhomirov@699: import java.io.CharArrayWriter; tikhomirov@699: import java.io.IOException; tikhomirov@699: import java.io.InputStream; tikhomirov@699: import java.security.cert.X509Certificate; tikhomirov@699: import java.util.Arrays; tikhomirov@699: tikhomirov@699: import org.tmatesoft.hg.auth.HgAuthFailedException; tikhomirov@699: import org.tmatesoft.hg.auth.HgAuthMethod; tikhomirov@699: tikhomirov@699: import com.trilead.ssh2.Connection; tikhomirov@699: tikhomirov@699: /** tikhomirov@699: * tikhomirov@699: * @author Artem Tikhomirov tikhomirov@699: * @author TMate Software Ltd. tikhomirov@699: */ tikhomirov@699: public final class SshAuthMethod implements HgAuthMethod { tikhomirov@699: tikhomirov@699: private final Connection conn; tikhomirov@699: tikhomirov@699: public SshAuthMethod(Connection connection) { tikhomirov@699: conn = connection; tikhomirov@699: } tikhomirov@699: tikhomirov@699: public void tryWithUserInfo(String uriUserInfo) throws HgAuthFailedException { tikhomirov@699: assert uriUserInfo != null && uriUserInfo.trim().length() > 0; tikhomirov@699: int colon = uriUserInfo.indexOf(':'); tikhomirov@699: if (colon == -1) { tikhomirov@699: String username = uriUserInfo; tikhomirov@699: withPassword(username, null); tikhomirov@699: } else { tikhomirov@699: String username = uriUserInfo.substring(0, colon); tikhomirov@699: String password = uriUserInfo.substring(colon+1); tikhomirov@699: withPassword(username, password); tikhomirov@699: } tikhomirov@699: return; tikhomirov@699: } tikhomirov@699: tikhomirov@699: public void noCredentials() throws HgAuthFailedException { tikhomirov@699: try { tikhomirov@699: String username = System.getProperty("user.name"); tikhomirov@699: if (!conn.authenticateWithNone(username)) { tikhomirov@699: throw authFailed(username); tikhomirov@699: } tikhomirov@699: } catch (IOException ex) { tikhomirov@699: throw commFailed(ex); tikhomirov@699: } tikhomirov@699: } tikhomirov@699: tikhomirov@699: public void withPublicKey(String username, InputStream privateKey, String passphrase) throws HgAuthFailedException { tikhomirov@699: if (username == null) { tikhomirov@699: // FIXME AuthFailure and AuthFailed or similar distinct exceptions to tell true authentication issues from tikhomirov@699: // failures around it. tikhomirov@699: throw new HgAuthFailedException("Need username", null); tikhomirov@699: } tikhomirov@699: if (privateKey == null) { tikhomirov@699: throw new HgAuthFailedException("Need private key", null); tikhomirov@699: } tikhomirov@699: CharArrayWriter a = new CharArrayWriter(2048); tikhomirov@699: int r; tikhomirov@699: try { tikhomirov@699: while((r = privateKey.read()) != -1) { tikhomirov@699: a.append((char) r); tikhomirov@699: } tikhomirov@699: } catch (IOException ex) { tikhomirov@699: throw new HgAuthFailedException("Failed to read private key", ex); tikhomirov@699: } tikhomirov@699: try { tikhomirov@699: boolean success = conn.authenticateWithPublicKey(username, a.toCharArray(), passphrase); tikhomirov@699: if (!success) { tikhomirov@699: throw authFailed(username); tikhomirov@699: } tikhomirov@699: } catch (IOException ex) { tikhomirov@699: throw commFailed(ex); tikhomirov@699: } tikhomirov@699: } tikhomirov@699: tikhomirov@699: public void withPassword(String username, String password) throws HgAuthFailedException { tikhomirov@699: if (username == null) { tikhomirov@699: throw new HgAuthFailedException("Need username", null); tikhomirov@699: } tikhomirov@699: try { tikhomirov@699: boolean success; tikhomirov@699: if (password == null) { tikhomirov@699: success = conn.authenticateWithNone(username); tikhomirov@699: } else { tikhomirov@699: success = conn.authenticateWithPassword(username, password); tikhomirov@699: } tikhomirov@699: if (!success) { tikhomirov@699: throw authFailed(username); tikhomirov@699: } tikhomirov@699: } catch (IOException ex) { tikhomirov@699: throw commFailed(ex); tikhomirov@699: } tikhomirov@699: } tikhomirov@699: tikhomirov@699: public void withCertificate(X509Certificate[] clientCert) throws HgAuthFailedException { tikhomirov@699: } tikhomirov@699: tikhomirov@699: public boolean supportsPublicKey() { tikhomirov@699: return true; tikhomirov@699: } tikhomirov@699: tikhomirov@699: public boolean supportsPassword() { tikhomirov@699: return true; tikhomirov@699: } tikhomirov@699: tikhomirov@699: public boolean supportsCertificate() { tikhomirov@699: return true; tikhomirov@699: } tikhomirov@699: tikhomirov@699: private HgAuthFailedException commFailed(IOException ex) { tikhomirov@699: return new HgAuthFailedException("Communication failure while authenticating", ex); tikhomirov@699: } tikhomirov@699: tikhomirov@699: private HgAuthFailedException authFailed(String username) throws IOException { tikhomirov@699: final String[] authMethodsLeft = conn.getRemainingAuthMethods(username); tikhomirov@699: return new HgAuthFailedException(String.format("Failed to authenticate, other methods to try: %s", Arrays.toString(authMethodsLeft)), null); tikhomirov@699: } tikhomirov@699: }