diff --git a/eclipse_projects/bVNC/AndroidManifest.xml b/eclipse_projects/bVNC/AndroidManifest.xml index 85128ed37..9fb5933d4 100644 --- a/eclipse_projects/bVNC/AndroidManifest.xml +++ b/eclipse_projects/bVNC/AndroidManifest.xml @@ -1,7 +1,7 @@ + android:versionCode="3790" android:versionName="v3.7.9"> diff --git a/eclipse_projects/bVNC/res/values-ru/strings.xml b/eclipse_projects/bVNC/res/values-ru/strings.xml index c9a1675ce..fa79c80ff 100644 --- a/eclipse_projects/bVNC/res/values-ru/strings.xml +++ b/eclipse_projects/bVNC/res/values-ru/strings.xml @@ -7,7 +7,7 @@ SSH Сервер Pro версия ARDP теперь поддерживает перенаправление звука! Pro версия aSPICE теперь поддерживает перенаправление USB! Просто приложите вашу OTG кабель перед подключением. -Pro версия теперь имеет очень нужную функциональность мастер-пароль, который предотвращает несанкционированное использование, а также защищает от кражи информации посредством шифрования все ваши настройки подключения, включая пароли и ключи безопасности. Включите его из главного меню. Если кнопка меню отсутствует, пожалуйста, долгое нажатие на кнопку, которая отображает запущенные приложения, чтобы получить меню. +Про версия теперь имеет поддержку для многофакторной аутентификации. Pro версия также имеет очень нужную функциональность мастер-пароль, который предотвращает несанкционированное использование, а также защищает от кражи информации посредством шифрования все ваши настройки подключения, включая пароли и ключи безопасности. Включите его из главного меню. Если кнопка меню отсутствует, пожалуйста, долгое нажатие на кнопку, которая отображает запущенные приложения, чтобы получить меню. Нажмите здесь, чтобы поддержать проект небольшим пожертвованием, купив PRO версию! Pro-версия позволяет отключить этот диалог и дает вам доступ к дополнительным функциям. Если вы хотели бы поддержать проект дальше, следуйте следующим ссылкам для ссылок на клиентские приложения для: @@ -352,6 +352,7 @@ Порт Порт Перейти в портретный режим при подключении. +На сервере многофакторной аутентификации включен. Пожалуйста, поддержите проект, купив Pro версию, которая имеет поддержку этой функции. Ссылка на Pro версия доступна в диалоговом окне запуска. RDP Сервер Включить RemoteFX Отображать обои на удаленной машине @@ -594,5 +595,7 @@ SSH Имя пользователя Режим просмотра VNC сервер или порт пусты. Соединение невозможно! +Проверочный код +Пожалуйста, введите многофакторную аутентификацию проверочный код Супер \ No newline at end of file diff --git a/eclipse_projects/bVNC/res/values/strings.xml b/eclipse_projects/bVNC/res/values/strings.xml index da4ac8e03..6c25e2f0d 100644 --- a/eclipse_projects/bVNC/res/values/strings.xml +++ b/eclipse_projects/bVNC/res/values/strings.xml @@ -7,7 +7,7 @@ SSH Server The Pro version of aRDP now supports sound redirection! The Pro version of aSPICE now supports USB redirection! Just attach your OTG cable prior to connecting. -The Pro version now has a much requested Master Password feature which prevents unauthorized use and also encrypts all connection settings including passwords and SSH keys to guard against theft. Enable it from the main Menu. If the Menu button is missing, please long-tap the running apps button for the Menu. +The Pro version now has support for multi-factor authentication. In addition, it supports the much requested Master Password feature that prevents unauthorized use and also encrypts all connection settings including passwords and SSH keys to guard against theft. Enable it from the main Menu. If the Menu button is missing, please long-tap the running apps button for the Menu. Tap here to support the project with a small donation by buying the Pro version. The Pro version allows you to disable this dialog and gives you access to additional features. If you would like to support the project further, follow the following links for links to client apps for: @@ -353,6 +353,7 @@ If you are looking for a quick performance boost, try setting the Color mode to Port Port Switch to portrait mode when connected +It appears your server has multi-factor authentication enabled. Please support the project by purchasing the Pro version which has support for this feature. A link to the Pro version is available in the start dialog. RDP Server Console Mode Redirect SD Card @@ -597,5 +598,7 @@ Known issues: SSH Username View-only mode VNC Server or port empty. Cannot connect! +Verification Code +Please enter the multi-factor authentication Verification Code Super diff --git a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/Constants.java b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/Constants.java index ebd35ef84..d382ff5d6 100644 --- a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/Constants.java +++ b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/Constants.java @@ -90,6 +90,9 @@ public class Constants { public static final int RDP_CONNECT_FAILURE = 7; public static final int RDP_UNABLE_TO_CONNECT = 8; public static final int RDP_AUTH_FAILED = 9; + public static final int GET_PASSWORD = 10; + public static final int GET_VERIFICATIONCODE = 11; + public static final int PRO_FEATURE = 99; public static final int EXTRA_KEYS_OFF = 0; public static final int EXTRA_KEYS_ON = 1; diff --git a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvas.java b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvas.java index 584ec257d..65b674856 100644 --- a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvas.java +++ b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvas.java @@ -51,6 +51,8 @@ import android.os.Handler; import android.os.Message; import android.os.SystemClock; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; import android.text.ClipboardManager; import android.text.Editable; import android.text.InputType; @@ -83,6 +85,7 @@ import com.iiordanov.bVNC.input.RemoteVncPointer; import com.iiordanov.tigervnc.vncviewer.CConn; +import com.iiordanov.bVNC.dialogs.GetTextFragment; public class RemoteCanvas extends ImageView implements LibFreeRDP.UIEventListener, LibFreeRDP.EventListener { private final static String TAG = "RemoteCanvas"; @@ -424,7 +427,7 @@ private void startVncConnection() throws Exception { connection.getUseRepeater(), connection.getRepeaterId(), connection.getConnectionType(), connection.getSshHostKey()); } catch (Exception e) { - throw new Exception (getContext().getString(R.string.error_vnc_unable_to_connect) + e.getLocalizedMessage()); + throw new Exception (getContext().getString(R.string.error_vnc_unable_to_connect) + e.getStackTrace().toString() + e.getLocalizedMessage()); } rfbconn = rfb; @@ -578,7 +581,7 @@ int getPort(int port) throws Exception { if (connection.getConnectionType() == Constants.CONN_TYPE_SSH) { if (sshConnection == null) { - sshConnection = new SSHConnection(connection, getContext()); + sshConnection = new SSHConnection(connection, getContext(), handler); } // TODO: Take the AutoX stuff out to a separate function. int newPort = sshConnection.initializeSSHTunnel (); @@ -1429,7 +1432,26 @@ public void OnRemoteClipboardChanged(String data) { public Handler handler = new Handler() { @Override public void handleMessage(Message msg) { + FragmentManager fm = null; + switch (msg.what) { + case Constants.PRO_FEATURE: + if (pd != null && pd.isShowing()) { + pd.dismiss(); + } + showFatalMessageAndQuit(getContext().getString(R.string.pro_feature_mfa)); + break; + case Constants.GET_VERIFICATIONCODE: + if (pd != null && pd.isShowing()) { + pd.dismiss(); + } + fm = ((FragmentActivity)getContext()).getSupportFragmentManager(); + GetTextFragment getPassword = GetTextFragment.newInstance( + RemoteCanvas.this.getContext().getString(R.string.verification_code), + sshConnection, GetTextFragment.Plaintext, R.string.verification_code_message, R.string.verification_code); + getPassword.setCancelable(false); + getPassword.show(fm, RemoteCanvas.this.getContext().getString(R.string.verification_code)); + break; case Constants.DIALOG_X509_CERT: validateX509Cert ((X509Certificate)msg.obj); break; @@ -1641,7 +1663,7 @@ private void initializeSshHostKey() { displayShortToastMessage(getContext().getString(R.string.info_ssh_initializing_hostkey)); - sshConnection = new SSHConnection(connection, getContext()); + sshConnection = new SSHConnection(connection, getContext(), handler); if (!sshConnection.connect()) { // Failed to connect, so show error message and quit activity. showFatalMessageAndQuit(getContext().getString(R.string.error_ssh_unable_to_connect)); diff --git a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvasActivity.java b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvasActivity.java index e251a0d4d..9d5a46462 100644 --- a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvasActivity.java +++ b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvasActivity.java @@ -45,6 +45,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; +import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.InputDevice; import android.view.KeyEvent; @@ -82,7 +83,7 @@ import com.iiordanov.bVNC.input.TouchMouseSwipePanInputHandler; -public class RemoteCanvasActivity extends Activity implements OnKeyListener { +public class RemoteCanvasActivity extends FragmentActivity implements OnKeyListener { private final static String TAG = "VncCanvasActivity"; diff --git a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/SSHConnection.java b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/SSHConnection.java index 1bdc96016..2a2075295 100644 --- a/eclipse_projects/bVNC/src/com/iiordanov/bVNC/SSHConnection.java +++ b/eclipse_projects/bVNC/src/com/iiordanov/bVNC/SSHConnection.java @@ -27,8 +27,11 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; import android.content.Context; +import android.os.Handler; +import android.os.Message; import android.util.Base64; import android.util.Log; @@ -38,12 +41,13 @@ import com.trilead.ssh2.InteractiveCallback; import com.trilead.ssh2.KnownHosts; import com.trilead.ssh2.Session; +import com.iiordanov.bVNC.dialogs.GetTextFragment; /** * @author Iordan K Iordanov * */ -public class SSHConnection implements InteractiveCallback { +public class SSHConnection implements InteractiveCallback, GetTextFragment.OnFragmentDismissedListener { private final static String TAG = "SSHConnection"; private final static int MAXTRIES = 3; @@ -85,8 +89,13 @@ public class SSHConnection implements InteractiveCallback { private boolean autoXUnixpw; private String autoXRandFileNm; private Context context; + private Handler handler; - public SSHConnection(ConnectionBean conn, Context cntxt) { + // Used to communicate the MFA verification code obtained. + private String verificationCode; + private CountDownLatch vcLatch; + + public SSHConnection(ConnectionBean conn, Context cntxt, Handler handler) { host = conn.getSshServer(); sshPort = conn.getSshPort(); user = conn.getSshUser(); @@ -109,6 +118,9 @@ public SSHConnection(ConnectionBean conn, Context cntxt) { connection = new Connection(host, sshPort); autoXRandFileNm = conn.getAutoXRandFileNm(); context = cntxt; + vcLatch = new CountDownLatch(1); + this.verificationCode = new String(); + this.handler = handler; } String getServerHostKey() { @@ -118,6 +130,11 @@ String getIdHash() { return idHash; } + public void setVerificationCode(String verificationCode) { + this.verificationCode = verificationCode; + this.vcLatch.countDown(); + } + /** * Initializes the SSH Tunnel * @return -1 if the target port was not determined, and the port obtained from x11vnc if it was @@ -342,14 +359,14 @@ private boolean authenticateWithPassword () { boolean isAuthenticated = false; try { - if (hasPasswordAuth()) { - Log.i(TAG, "Trying SSH password authentication."); - isAuthenticated = connection.authenticateWithPassword(user, password); - } - if (!isAuthenticated && hasKeyboardInteractiveAuth()) { + if (hasKeyboardInteractiveAuth()) { Log.i(TAG, "Trying SSH keyboard-interactive authentication."); isAuthenticated = connection.authenticateWithKeyboardInteractive(user, this); } + if (!isAuthenticated && hasPasswordAuth()) { + Log.i(TAG, "Trying SSH password authentication."); + isAuthenticated = connection.authenticateWithPassword(user, password); + } return isAuthenticated; } catch (IOException e) { e.printStackTrace(); @@ -516,8 +533,34 @@ public String[] replyToChallenge(String name, String instruction, boolean[] echo) throws Exception { String[] responses = new String[numPrompts]; for (int x=0; x < numPrompts; x++) { - responses[x] = password; + if (prompt[0].indexOf("Verification code:") != -1) { + Log.e(TAG, prompt[x] + " Will request verification code from user"); + if (Utils.isFree(context)) { + handler.sendEmptyMessage(Constants.PRO_FEATURE); + responses[x] = ""; + } else { + vcLatch = new CountDownLatch(1); + Log.e(TAG, "Requesting verification code from user"); + handler.sendEmptyMessage(Constants.GET_VERIFICATIONCODE); + while (true) { + try { + vcLatch.await(); + break; + } catch (InterruptedException e) { e.printStackTrace(); } + } + Log.e(TAG, prompt[0] + " Sending verification code: " + verificationCode); + responses[x] = verificationCode; + } + } else { + Log.e(TAG, prompt[0] + " Sending password: " + password); + responses[x] = password; + } } - return responses; + return responses; + } + + @Override + public void onTextObtained(String obtainedString, boolean dialogCancelled) { + setVerificationCode(obtainedString); } }