Skip to content

Commit

Permalink
Adding support for MFA.
Browse files Browse the repository at this point in the history
  • Loading branch information
iiordanov committed Sep 5, 2015
1 parent 4a79c12 commit e4199db
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 16 deletions.
2 changes: 1 addition & 1 deletion eclipse_projects/bVNC/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iiordanov.bVNC" android:installLocation="auto"
android:versionCode="3780" android:versionName="v3.7.8">
android:versionCode="3790" android:versionName="v3.7.9">

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"></uses-sdk>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Expand Down
5 changes: 4 additions & 1 deletion eclipse_projects/bVNC/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<string name="address_caption_ssh_hint">SSH Сервер</string>
<string name="ad_donate_text_rdp">Pro версия ARDP теперь поддерживает перенаправление звука!</string>
<string name="ad_donate_text_spice">Pro версия aSPICE теперь поддерживает перенаправление USB! Просто приложите вашу OTG кабель перед подключением.</string>
<string name="ad_donate_text0">Pro версия теперь имеет очень нужную функциональность мастер-пароль, который предотвращает несанкционированное использование, а также защищает от кражи информации посредством шифрования все ваши настройки подключения, включая пароли и ключи безопасности. Включите его из главного меню. Если кнопка меню отсутствует, пожалуйста, долгое нажатие на кнопку, которая отображает запущенные приложения, чтобы получить меню.</string>
<string name="ad_donate_text0">Про версия теперь имеет поддержку для многофакторной аутентификации. Pro версия также имеет очень нужную функциональность мастер-пароль, который предотвращает несанкционированное использование, а также защищает от кражи информации посредством шифрования все ваши настройки подключения, включая пароли и ключи безопасности. Включите его из главного меню. Если кнопка меню отсутствует, пожалуйста, долгое нажатие на кнопку, которая отображает запущенные приложения, чтобы получить меню.</string>
<string name="ad_donate_text1">Нажмите здесь, чтобы поддержать проект небольшим пожертвованием, купив PRO версию!</string>
<string name="ad_donate_text2">Pro-версия позволяет отключить этот диалог и дает вам доступ к дополнительным функциям.</string>
<string name="ad_donate_text3">Если вы хотели бы поддержать проект дальше, следуйте следующим ссылкам для ссылок на клиентские приложения для:</string>
Expand Down Expand Up @@ -352,6 +352,7 @@
<string name="port_hint">Порт</string>
<string name="port_ssh_hint">Порт</string>
<string name="portrait_mode">Перейти в портретный режим при подключении.</string>
<string name="pro_feature_mfa">На сервере многофакторной аутентификации включен. Пожалуйста, поддержите проект, купив Pro версию, которая имеет поддержку этой функции. Ссылка на Pro версия доступна в диалоговом окне запуска.</string>
<string name="rdp_address_caption_hint">RDP Сервер</string>
<string name="rdp_adv_remotefx">Включить RemoteFX</string>
<string name="rdp_adv_desktop_background">Отображать обои на удаленной машине</string>
Expand Down Expand Up @@ -594,5 +595,7 @@
<string name="username_hint_ssh">SSH Имя пользователя</string>
<string name="view_only">Режим просмотра</string>
<string name="vnc_server_empty">VNC сервер или порт пусты. Соединение невозможно!</string>
<string name="verification_code">Проверочный код</string>
<string name="verification_code_message">Пожалуйста, введите многофакторную аутентификацию проверочный код</string>
<string name="super_check">Супер</string>
</resources>
5 changes: 4 additions & 1 deletion eclipse_projects/bVNC/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<string name="address_caption_ssh_hint">SSH Server</string>
<string name="ad_donate_text_rdp">The Pro version of aRDP now supports sound redirection!</string>
<string name="ad_donate_text_spice">The Pro version of aSPICE now supports USB redirection! Just attach your OTG cable prior to connecting.</string>
<string name="ad_donate_text0">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.</string>
<string name="ad_donate_text0">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.</string>
<string name="ad_donate_text1">Tap here to support the project with a small donation by buying the Pro version.</string>
<string name="ad_donate_text2">The Pro version allows you to disable this dialog and gives you access to additional features.</string>
<string name="ad_donate_text3">If you would like to support the project further, follow the following links for links to client apps for: </string>
Expand Down Expand Up @@ -353,6 +353,7 @@ If you are looking for a quick performance boost, try setting the Color mode to
<string name="port_hint">Port</string>
<string name="port_ssh_hint">Port</string>
<string name="portrait_mode">Switch to portrait mode when connected</string>
<string name="pro_feature_mfa">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.</string>
<string name="rdp_address_caption_hint">RDP Server</string>
<string name="rdp_adv_console_mode">Console Mode</string>
<string name="rdp_adv_redirect_sdcard">Redirect SD Card</string>
Expand Down Expand Up @@ -597,5 +598,7 @@ Known issues:
<string name="username_hint_ssh">SSH Username</string>
<string name="view_only">View-only mode</string>
<string name="vnc_server_empty">VNC Server or port empty. Cannot connect!</string>
<string name="verification_code">Verification Code</string>
<string name="verification_code_message">Please enter the multi-factor authentication Verification Code</string>
<string name="super_check">Super</string>
</resources>
3 changes: 3 additions & 0 deletions eclipse_projects/bVNC/src/com/iiordanov/bVNC/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 25 additions & 3 deletions eclipse_projects/bVNC/src/com/iiordanov/bVNC/RemoteCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 ();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";

Expand Down
61 changes: 52 additions & 9 deletions eclipse_projects/bVNC/src/com/iiordanov/bVNC/SSHConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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();
Expand All @@ -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() {
Expand All @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}

0 comments on commit e4199db

Please sign in to comment.