Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfb2f678 authored by David Luhmer's avatar David Luhmer
Browse files

store auth token in client app / request auth token from files app only on login

parent 08577103
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -7,10 +7,13 @@ import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.RequiresApi;
import android.util.Log;

import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotInstalledException;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException;
@@ -62,6 +65,10 @@ public class AccountImporter {

    public static void PickNewAccount(android.support.v4.app.Fragment fragment) throws NextcloudFilesAppNotInstalledException {
        if(AppInstalledOrNot(fragment.getContext(), "com.nextcloud.client")) {

            // Clear all tokens first to prevent some caching issues..
            ClearAllAuthTokens(fragment.getContext());

            Intent intent = AccountManager.newChooseAccountIntent(null, null, new String[]{"nextcloud"},
                    true, null, null, null, null);
            fragment.startActivityForResult(intent, CHOOSE_ACCOUNT_SSO);
@@ -117,8 +124,28 @@ public class AccountImporter {
        return result;
    }

    public static void ClearAllAuthTokens(Context context) {
        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        for(String key : mPrefs.getAll().keySet()) {
            if(key.startsWith(PREF_ACCOUNT_STRING)) {
                mPrefs.edit().remove(key).apply();
            }
        }
    }

    // Get the AuthToken (Password) for a selected account
    public static SingleSignOnAccount GetAuthToken(Context context, Account account) throws AuthenticatorException, OperationCanceledException, IOException, NextcloudFilesAppNotSupportedException {
        SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
        String prefKey = PREF_ACCOUNT_STRING + account.name;
        if(mPrefs.contains(prefKey)) {
            try {
                return SingleSignOnAccount.fromString(mPrefs.getString(prefKey, null));
            } catch (ClassNotFoundException e) {
                Log.e(TAG, "This should never happen!");
                e.printStackTrace();
            }
        }

        final AccountManager accMgr = AccountManager.get(context);
        Bundle options = new Bundle();
        accMgr.invalidateAuthToken(account.type, AUTH_TOKEN);
@@ -147,7 +174,9 @@ public class AccountImporter {
        String token = future.getString(Constants.SSO_TOKEN);
        String server_url = future.getString(Constants.SSO_SERVER_URL);

        return new SingleSignOnAccount(account.name, username, token, server_url);
        SingleSignOnAccount ssoAccount = new SingleSignOnAccount(account.name, username, token, server_url);
        mPrefs.edit().putString(prefKey, SingleSignOnAccount.toString(ssoAccount)).apply();
        return ssoAccount;
    }


+1 −25
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import java.util.Map;

public class NextcloudRequest implements Serializable {

    private static final long serialVersionUID = 215521212534239L; //assign a long value
    private static final long serialVersionUID = 215521212534240L; //assign a long value

    private String method;
    private Map<String, List<String>> header = new HashMap<>();
@@ -81,11 +81,6 @@ public class NextcloudRequest implements Serializable {
            return this;
        }

        public Builder setPackageName(String packageName) {
            ncr.packageName = packageName;
            return this;
        }

        public Builder setAccountName(String accountName) {
            ncr.accountName = accountName;
            return this;
@@ -149,23 +144,4 @@ public class NextcloudRequest implements Serializable {
    public boolean isFollowRedirects() {
        return this.followRedirects;
    }

    public boolean validateToken(String token) {
        // As discussed with Lukas R. at the Nextcloud Conf 2018, always compare whole strings
        // and don't exit prematurely if the string does not match anymore to prevent timing-attacks
        return isEqual(this.token.getBytes(), token.getBytes());
    }

    // Taken from http://codahale.com/a-lesson-in-timing-attacks/
    private static boolean isEqual(byte[] a, byte[] b) {
        if (a.length != b.length) {
            return false;
        }

        int result = 0;
        for (int i = 0; i < a.length; i++) {
            result |= a[i] ^ b[i];
        }
        return result == 0;
    }
}
+0 −5
Original line number Diff line number Diff line
@@ -289,11 +289,6 @@ public class NextcloudAPI {








    public static <T> T deserializeObjectAndCloseStream(InputStream is) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(is);
        T result = (T) ois.readObject();
+33 −1
Original line number Diff line number Diff line
package com.nextcloud.android.sso.model;

import android.util.Base64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 *  Nextcloud SingleSignOn
 *
@@ -20,7 +29,9 @@ package com.nextcloud.android.sso.model;

 */

public class SingleSignOnAccount {
public class SingleSignOnAccount implements Serializable {

    private static final long serialVersionUID = 21523240203234240L; //assign a long value

    public SingleSignOnAccount(String name, String username, String token, String url) {
        this.name = name;
@@ -34,4 +45,25 @@ public class SingleSignOnAccount {
    public String token;
    public String url;


    /** Read the object from Base64 string. */
    public static SingleSignOnAccount fromString(String s) throws IOException, ClassNotFoundException {
        byte [] data = Base64.decode(s, Base64.DEFAULT);
        ObjectInputStream ois = new ObjectInputStream(
                new ByteArrayInputStream(  data ) );
        SingleSignOnAccount o  = (SingleSignOnAccount) ois.readObject();
        ois.close();
        return o;
    }

    /** Write the object to a Base64 string.
     * @param o*/
    public static String toString(SingleSignOnAccount o) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream( baos );
        oos.writeObject( o );
        oos.close();
        return new String(Base64.encode(baos.toByteArray(), Base64.DEFAULT));
    }

}