Skip to content

Commit

Permalink
Merge pull request #559 from Logan676/feature/support_two_factor_auth
Browse files Browse the repository at this point in the history
Support two-factor authentication
  • Loading branch information
Logan676 authored Jul 23, 2016
2 parents f71d233 + c40621a commit 425ed21
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 9 deletions.
37 changes: 32 additions & 5 deletions app/src/main/java/com/seafile/seadroid2/SeafConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;

Expand Down Expand Up @@ -151,12 +152,19 @@ private HttpRequest prepareApiDeleteRequest(String apiPath, Map<String, ?> param
* @return true if login success, false otherwise
* @throws SeafException
*/
private boolean realLogin(String passwd) throws SeafException {
private boolean realLogin(String passwd, String authToken) throws SeafException {
boolean withAuthToken = false;
HttpRequest req = null;
try {
req = prepareApiPostRequest("api2/auth-token/", false, null);
// Log.d(DEBUG_TAG, "Login to " + account.server + "api2/auth-token/");

if (!TextUtils.isEmpty(authToken)) {
req.header("X-Seafile-OTP", authToken);
withAuthToken = true;
// Log.d(DEBUG_TAG, "authToken " + authToken);
}

req.form("username", account.email);
req.form("password", passwd);

Expand All @@ -179,7 +187,7 @@ private boolean realLogin(String passwd) throws SeafException {
req.form("client_version", appVersion);
req.form("platform_version", Build.VERSION.RELEASE);

checkRequestResponseStatus(req, HttpURLConnection.HTTP_OK);
checkRequestResponseStatus(req, HttpURLConnection.HTTP_OK, withAuthToken);

String contentAsString = new String(req.bytes(), "UTF-8");
JSONObject obj = Utils.parseJsonObject(contentAsString);
Expand Down Expand Up @@ -243,12 +251,12 @@ public String getServerInfo() throws SeafException {
return result;
}

public boolean doLogin(String passwd) throws SeafException {
public boolean doLogin(String passwd, String authToken) throws SeafException {
try {
return realLogin(passwd);
return realLogin(passwd, authToken);
} catch (Exception e) {
// do again
return realLogin(passwd);
return realLogin(passwd, authToken);
}
}

Expand Down Expand Up @@ -1514,6 +1522,25 @@ private void checkRequestResponseStatus(HttpRequest req, int expectedStatusCode)
}
}

private void checkRequestResponseStatus(HttpRequest req, int expectedStatusCode, boolean withAuthToken) throws SeafException {
if (req.code() != expectedStatusCode) {
Log.d(DEBUG_TAG, "HTTP request failed : " + req.url() + ", " + req.code() + ", " + req.message());

if (req.message() == null) {
throw SeafException.networkException;
} else if (req.header("X-Seafile-OTP") != null && req.header("X-Seafile-OTP").equals("required")) {
if (withAuthToken)
throw SeafException.twoFactorAuthTokenInvalid;
else
throw SeafException.twoFactorAuthTokenMissing;
} else {
throw new SeafException(req.code(), req.message());
}
} else {
// Log.v(DEBUG_TAG, "HTTP request ok : " + req.url());
}
}

private SeafException getSeafExceptionFromHttpRequestException(HttpRequestException e) {
if (e.getCause() instanceof SSLHandshakeException) {
return SeafException.sslException;
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/seafile/seadroid2/SeafException.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class SeafException extends Exception {
public static final SeafException encryptException = new SeafException(10, "encryption key or iv is null");
public static final SeafException decryptException = new SeafException(11, "decryption key or iv is null");
public static final SeafException remoteWipedException = new SeafException(12, "Remote Wiped Error");
public static final SeafException twoFactorAuthTokenMissing = new SeafException(13, "Two factor auth token is missing");
public static final SeafException twoFactorAuthTokenInvalid = new SeafException(14, "Two factor auth token is invalid");

public SeafException(int code, String msg) {
super(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.widget.Toolbar;
Expand Down Expand Up @@ -62,6 +63,8 @@ public class AccountDetailActivity extends BaseActivity implements Toolbar.OnMen
private TextView seahubUrlHintText;
private ImageView clearEmail, clearPasswd, ivEyeClick;
private RelativeLayout rlEye;
private TextInputLayout authTokenLayout;
private EditText authTokenText;

private android.accounts.AccountManager mAccountManager;
private boolean serverTextHasFocus;
Expand All @@ -88,6 +91,10 @@ public void onCreate(Bundle savedInstanceState) {
rlEye = (RelativeLayout) findViewById(R.id.rl_layout_eye);
ivEyeClick = (ImageView) findViewById(R.id.iv_eye_click);

authTokenLayout = (TextInputLayout) findViewById(R.id.auth_token_hint);
authTokenText = (EditText) findViewById(R.id.auth_token);
authTokenLayout.setVisibility(View.GONE);

setupServerText();

Intent intent = getIntent();
Expand Down Expand Up @@ -375,6 +382,15 @@ public void login(View view) {
return;
}

String authToken = null;
if (authTokenLayout.getVisibility() == View.VISIBLE) {
authToken = authTokenText.getText().toString().trim();
if (TextUtils.isEmpty(authToken)) {
authTokenText.setError(getResources().getString(R.string.two_factor_auth_token_empty));
return;
}
}

try {
serverURL = Utils.cleanServerURL(serverURL);
} catch (MalformedURLException e) {
Expand All @@ -394,7 +410,7 @@ public void login(View view) {
progressDialog = new ProgressDialog(this);
progressDialog.setMessage(getString(R.string.settings_cuc_loading));
progressDialog.setCancelable(false);
ConcurrentAsyncTask.execute(new LoginTask(tmpAccount, passwd));
ConcurrentAsyncTask.execute(new LoginTask(tmpAccount, passwd, authToken));
} else {
statusView.setText(R.string.network_down);
}
Expand All @@ -404,10 +420,12 @@ private class LoginTask extends AsyncTask<Void, Void, String> {
Account loginAccount;
SeafException err = null;
String passwd;
String authToken;

public LoginTask(Account loginAccount, String passwd) {
public LoginTask(Account loginAccount, String passwd, String authToken) {
this.loginAccount = loginAccount;
this.passwd = passwd;
this.authToken = authToken;
}

@Override
Expand All @@ -425,13 +443,14 @@ protected String doInBackground(Void... params) {
}

private void resend() {
ConcurrentAsyncTask.execute(new LoginTask(loginAccount, passwd));
ConcurrentAsyncTask.execute(new LoginTask(loginAccount, passwd, authToken));
}

@Override
protected void onPostExecute(final String result) {
progressDialog.dismiss();
if (err == SeafException.sslException) {
authTokenLayout.setVisibility(View.GONE);
SslConfirmDialog dialog = new SslConfirmDialog(loginAccount,
new SslConfirmDialog.Listener() {
@Override
Expand All @@ -448,6 +467,16 @@ public void onRejected() {
});
dialog.show(getSupportFragmentManager(), SslConfirmDialog.FRAGMENT_TAG);
return;
} else if (err == SeafException.twoFactorAuthTokenMissing) {
// show auth token input box
authTokenLayout.setVisibility(View.VISIBLE);
authTokenText.setError(getString(R.string.two_factor_auth_error));
} else if (err == SeafException.twoFactorAuthTokenInvalid) {
// show auth token input box
authTokenLayout.setVisibility(View.VISIBLE);
authTokenText.setError(getString(R.string.two_factor_auth_invalid));
} else {
authTokenLayout.setVisibility(View.GONE);
}

if (result != null && result.equals("Success")) {
Expand All @@ -473,7 +502,7 @@ private String doLogin() {

try {
// if successful, this will place the auth token into "loginAccount"
if (!sc.doLogin(passwd))
if (!sc.doLogin(passwd, authToken))
return getString(R.string.err_login_failed);

// fetch email address from the server
Expand All @@ -492,6 +521,10 @@ private String doLogin() {
err = e;
if (e == SeafException.sslException) {
return getString(R.string.ssl_error);
} else if (e == SeafException.twoFactorAuthTokenMissing) {
return getString(R.string.two_factor_auth_error);
} else if (e == SeafException.twoFactorAuthTokenInvalid) {
return getString(R.string.two_factor_auth_invalid);
}
switch (e.getCode()) {
case HttpURLConnection.HTTP_BAD_REQUEST:
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/res/layout/account_detail.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@
</RelativeLayout>
</RelativeLayout>

<android.support.design.widget.TextInputLayout
android:id="@+id/auth_token_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">

<EditText
android:id="@+id/auth_token"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/two_factor_auth_token"
android:inputType="number"
android:layout_marginBottom="@dimen/et_margin_bottom"
android:layout_marginLeft="@dimen/auto_complete_ed_margin_left"
android:layout_marginRight="@dimen/auto_complete_ed_margin_right" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>


Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -497,4 +497,10 @@
<string name="clear_password_failed">Clear password failed</string>
<string name="clear_password_warning">Do you want to clear password?</string>
<string name="clear_password_auto">Auto clear passwords</string>

<!-- Two factor auth -->
<string name="two_factor_auth_error">Two-factor authentication token is required</string>
<string name="two_factor_auth_invalid">Two-factor authentication token is invalid</string>
<string name="two_factor_auth_token">Authentication token</string>
<string name="two_factor_auth_token_empty">Authentication token can\`t be empty</string>
</resources>

0 comments on commit 425ed21

Please sign in to comment.