/** * Try public key * * @param c a ssh connection * @param keyPath a path to key * @return true if authentication is successful */ private boolean tryPublicKey(final Connection c, final String keyPath) { try { final File file = new File(keyPath); if (file.exists()) { // if encrypted ask user for passphrase String passphrase = null; char[] text = FileUtil.loadFileText(file); if (isEncryptedKey(text)) { // need to ask passphrase from user int i; for (i = myHost.getNumberOfPasswordPrompts(); i > 0; i--) { passphrase = myXmlRpcClient.askPassphrase( myHandlerNo, getUserHostString(), keyPath, myLastError); if (passphrase == null) { // if no passphrase was entered, just return false and try something other return false; } else { try { PEMDecoder.decode(text, passphrase); myLastError = ""; } catch (IOException e) { // decoding failed myLastError = GitBundle.message("sshmain.invalidpassphrase", keyPath); continue; } break; } } if (i == 0) { myLastError = GitBundle.message( "sshmain.too.mush.passphrase.guesses", keyPath, myHost.getNumberOfPasswordPrompts()); return false; } } // try authentication if (c.authenticateWithPublicKey(myHost.getUser(), text, passphrase)) { myLastError = ""; return true; } else { if (passphrase != null) { // mark as failed authentication only if passphrase were asked myLastError = GitBundle.message("sshmain.pk.authenitication.failed", keyPath); } else { myLastError = ""; } } } return false; } catch (Exception e) { return false; } }
/** @return user and host string */ private String getUserHostString() { int port = myHost.getPort(); return myHost.getUser() + "@" + myHost.getHostName() + (port == 22 ? "" : ":" + port); }
/** * Authenticate using some supported methods. If authentication fails, the method throws {@link * IOException}. * * @param c the connection to use for authentication * @throws IOException in case of IO error or authentication failure */ private void authenticate(final Connection c) throws IOException { for (String method : myHost.getPreferredMethods()) { if (c.isAuthenticationComplete()) { return; } if (PUBLIC_KEY_METHOD.equals(method)) { if (!myHost.supportsPubkeyAuthentication()) { continue; } if (!c.isAuthMethodAvailable(myHost.getUser(), PUBLIC_KEY_METHOD)) { continue; } File key = myHost.getIdentityFile(); if (key == null) { for (String a : myHost.getHostKeyAlgorithms()) { if (SSH_RSA_ALGORITHM.equals(a)) { if (tryPublicKey(c, idRSAPath)) { return; } } else if (SSH_DSS_ALGORITHM.equals(a)) { if (tryPublicKey(c, idDSAPath)) { return; } } } } else { if (tryPublicKey(c, key.getPath())) { return; } } } else if (KEYBOARD_INTERACTIVE_METHOD.equals(method)) { if (!c.isAuthMethodAvailable(myHost.getUser(), KEYBOARD_INTERACTIVE_METHOD)) { continue; } InteractiveSupport interactiveSupport = new InteractiveSupport(); for (int i = myHost.getNumberOfPasswordPrompts(); i > 0; i--) { if (c.isAuthenticationComplete()) { return; } if (c.authenticateWithKeyboardInteractive(myHost.getUser(), interactiveSupport)) { myLastError = ""; return; } else { myLastError = GitBundle.getString("sshmain.keyboard.interactive.failed"); } if (interactiveSupport.myPromptCount == 0 || interactiveSupport.myCancelled) { // the interactive callback has never been asked or it was cancelled, exit the loop myLastError = ""; break; } } } else if (PASSWORD_METHOD.equals(method)) { if (!myHost.supportsPasswordAuthentication()) { continue; } if (!c.isAuthMethodAvailable(myHost.getUser(), PASSWORD_METHOD)) { continue; } for (int i = myHost.getNumberOfPasswordPrompts(); i > 0; i--) { String password = myXmlRpcClient.askPassword(myHandlerNo, getUserHostString(), myLastError); if (password == null) { break; } else { if (c.authenticateWithPassword(myHost.getUser(), password)) { myLastError = ""; return; } else { myLastError = GitBundle.getString("sshmain.password.failed"); } } } } } throw new IOException("Authentication failed"); }