Ver código fonte

add own sso token manager with custom dialog

David Luhmer 6 anos atrás
pai
commit
086492b6d4

+ 1 - 0
build.gradle

@@ -213,6 +213,7 @@ dependencies {
     implementation 'com.android.support:multidex:1.0.3'
 //    implementation project('nextcloud-android-library')
     genericImplementation "com.github.nextcloud:android-library:master-SNAPSHOT"
+    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
     gplayImplementation "com.github.nextcloud:android-library:master-SNAPSHOT"
     versionDevImplementation 'com.github.nextcloud:android-library:master-SNAPSHOT' // use always latest master
     implementation "com.android.support:support-v4:${supportLibraryVersion}"

+ 4 - 1
src/main/AndroidManifest.xml

@@ -304,6 +304,9 @@
             android:exported="true" >
         </service>
 
+        <activity
+            android:name=".ui.activity.SsoGrantPermissionActivity"
+            android:exported="true"/>
     </application>
 
-</manifest>
+</manifest>

+ 14 - 8
src/main/java/com/nextcloud/android/sso/Constants.java

@@ -3,14 +3,20 @@ package com.nextcloud.android.sso;
 public class Constants {
 
     // Authenticator related constants
-    public final static String SSO_USERNAME = "username";
-    public final static String SSO_TOKEN = "token";
-    public final static String SSO_SERVER_URL = "server_url";
+    public static final String SSO_USERNAME = "username";
+    public static final String SSO_TOKEN = "token";
+    public static final String SSO_SERVER_URL = "server_url";
+    public static final String SSO_SHARED_PREFERENCE = "single-sign-on";
+    public static final String NEXTCLOUD_SSO_EXCEPTION = "NextcloudSsoException";
+    public static final String NEXTCLOUD_SSO = "NextcloudSSO";
+    public static final String NEXTCLOUD_FILES_ACCOUNT = "NextcloudFilesAccount";
+
 
     // Custom Exceptions
-    static final String EXCEPTION_INVALID_TOKEN = "CE_1";
-    static final String EXCEPTION_ACCOUNT_NOT_FOUND = "CE_2";
-    static final String EXCEPTION_UNSUPPORTED_METHOD = "CE_3";
-    static final String EXCEPTION_INVALID_REQUEST_URL = "CE_4";
-    static final String EXCEPTION_HTTP_REQUEST_FAILED = "CE_5";
+    public static final String EXCEPTION_INVALID_TOKEN = "CE_1";
+    public static final String EXCEPTION_ACCOUNT_NOT_FOUND = "CE_2";
+    public static final String EXCEPTION_UNSUPPORTED_METHOD = "CE_3";
+    public static final String EXCEPTION_INVALID_REQUEST_URL = "CE_4";
+    public static final String EXCEPTION_HTTP_REQUEST_FAILED = "CE_5";
+    public static final String EXCEPTION_ACCOUNT_ACCESS_DECLINED = "CE_6";
 }

+ 2 - 2
src/main/java/com/nextcloud/android/sso/InputStreamBinder.java

@@ -33,7 +33,6 @@ import android.util.Log;
 import com.nextcloud.android.sso.aidl.IInputStreamService;
 import com.nextcloud.android.sso.aidl.NextcloudRequest;
 import com.nextcloud.android.sso.aidl.ParcelFileDescriptorUtil;
-import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
@@ -64,6 +63,7 @@ import static com.nextcloud.android.sso.Constants.EXCEPTION_HTTP_REQUEST_FAILED;
 import static com.nextcloud.android.sso.Constants.EXCEPTION_INVALID_REQUEST_URL;
 import static com.nextcloud.android.sso.Constants.EXCEPTION_INVALID_TOKEN;
 import static com.nextcloud.android.sso.Constants.EXCEPTION_UNSUPPORTED_METHOD;
+import static com.nextcloud.android.sso.Constants.SSO_SHARED_PREFERENCE;
 
 
 /**
@@ -220,7 +220,7 @@ public class InputStreamBinder extends IInputStreamService.Stub {
     private boolean isValid(NextcloudRequest request) {
         String callingPackageName = context.getPackageManager().getNameForUid(Binder.getCallingUid());
 
-        SharedPreferences sharedPreferences = context.getSharedPreferences(AccountAuthenticator.SSO_SHARED_PREFERENCE,
+        SharedPreferences sharedPreferences = context.getSharedPreferences(SSO_SHARED_PREFERENCE,
                 Context.MODE_PRIVATE);
         String hash = sharedPreferences.getString(callingPackageName, "");
         return validateToken(hash, request.getToken());

+ 1 - 56
src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java

@@ -28,21 +28,14 @@ import android.accounts.AccountManager;
 import android.accounts.NetworkErrorException;
 import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Handler;
 import android.widget.Toast;
 
-import com.nextcloud.android.sso.Constants;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
-import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
-import com.owncloud.android.lib.common.accounts.AccountUtils;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.utils.EncryptionUtils;
-
-import java.util.UUID;
 
 
 /**
@@ -64,10 +57,7 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
     public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
     public static final String KEY_LOGIN_OPTIONS = "loginOptions";
     public static final String KEY_ACCOUNT = "account";
-    public static final String SSO_SHARED_PREFERENCE = "sso";
-    
-    private static final String NEXTCLOUD_SSO = "NextcloudSSO";
-    
+
     private static final String TAG = AccountAuthenticator.class.getSimpleName();
     
     private Context mContext;
@@ -162,51 +152,6 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
     @Override
     public Bundle getAuthToken(AccountAuthenticatorResponse response,
                                Account account, String authTokenType, Bundle options) {
-
-        if (NEXTCLOUD_SSO.equals(authTokenType)) {
-            final Bundle result = new Bundle();
-
-            String packageName = options.getString("androidPackageName");
-
-            if (packageName == null) {
-                Log_OC.e(TAG, "No calling package, exit.");
-                return result;
-            }
-
-            // create token
-            SharedPreferences sharedPreferences = mContext.getSharedPreferences(SSO_SHARED_PREFERENCE,
-                    Context.MODE_PRIVATE);
-            String token = UUID.randomUUID().toString().replaceAll("-", "");
-
-            String hashedTokenWithSalt = EncryptionUtils.generateSHA512(token);
-
-            SharedPreferences.Editor editor = sharedPreferences.edit();
-            editor.putString(packageName, hashedTokenWithSalt);
-            editor.apply();
-                        
-            String serverUrl;
-            String userId;
-            try {
-                OwnCloudAccount ocAccount = new OwnCloudAccount(account, mContext);
-                serverUrl = ocAccount.getBaseUri().toString();
-                AccountManager accountManager = AccountManager.get(mContext);
-                userId = accountManager.getUserData(account,
-                        com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
-            } catch (AccountUtils.AccountNotFoundException e) {
-                Log_OC.e(TAG, "Account not found");
-                return new Bundle();
-            }
-
-            result.putString(AccountManager.KEY_ACCOUNT_NAME,  account.name);
-            result.putString(AccountManager.KEY_ACCOUNT_TYPE,  MainApp.getAccountType(mContext));
-            result.putString(AccountManager.KEY_AUTHTOKEN,     NEXTCLOUD_SSO);
-            result.putString(Constants.SSO_USERNAME,   userId);
-            result.putString(Constants.SSO_TOKEN,      token);
-            result.putString(Constants.SSO_SERVER_URL, serverUrl);
-
-            return result;
-        }
-
         // validate parameters
         try {
             validateAccountType(account.type);

+ 151 - 0
src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java

@@ -0,0 +1,151 @@
+package com.owncloud.android.ui.activity;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.nextcloud.android.sso.Constants;
+import com.owncloud.android.MainApp;
+import com.owncloud.android.R;
+import com.owncloud.android.lib.common.OwnCloudAccount;
+import com.owncloud.android.lib.common.accounts.AccountUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.utils.EncryptionUtils;
+
+import java.util.UUID;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+
+import static com.nextcloud.android.sso.Constants.EXCEPTION_ACCOUNT_ACCESS_DECLINED;
+import static com.nextcloud.android.sso.Constants.EXCEPTION_ACCOUNT_NOT_FOUND;
+import static com.nextcloud.android.sso.Constants.NEXTCLOUD_FILES_ACCOUNT;
+import static com.nextcloud.android.sso.Constants.NEXTCLOUD_SSO;
+import static com.nextcloud.android.sso.Constants.NEXTCLOUD_SSO_EXCEPTION;
+import static com.nextcloud.android.sso.Constants.SSO_SHARED_PREFERENCE;
+
+
+public class SsoGrantPermissionActivity extends BaseActivity {
+
+    private static final String TAG = SsoGrantPermissionActivity.class.getCanonicalName();
+
+    private String packageName;
+    private Account account;
+
+
+    @BindView(R.id.imageView)
+    ImageView imageView;
+
+    @BindView(R.id.tvInfoText)
+    TextView tvInfo;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_sso_grant_permission);
+
+        ButterKnife.bind(this);
+        try {
+            ComponentName callingActivity = getCallingActivity();
+            if(callingActivity != null) {
+                packageName = callingActivity.getPackageName();
+                String appName = getAppNameForPackage(packageName);
+                account = getIntent().getParcelableExtra(NEXTCLOUD_FILES_ACCOUNT);
+                Drawable appIcon = getPackageManager().getApplicationIcon(packageName);
+                imageView.setImageDrawable(appIcon);
+
+
+                tvInfo.setText(getString(R.string.single_sign_on_request_token, appName, account.name));
+
+                Log.v(TAG, "TOKEN-REQUEST: Calling Package: " + packageName);
+                Log.v(TAG, "TOKEN-REQUEST: App Name: " + appName);
+            } else {
+                // Activity was not started using startActivityForResult!
+                Log.e(TAG, "Calling Package is null");
+                setResultAndExit("Request was not executed properly. Use startActivityForResult()");
+            }
+            
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void setResultAndExit(String exception) {
+        Intent data = new Intent();
+        data.putExtra(NEXTCLOUD_SSO_EXCEPTION, exception);
+        setResult(RESULT_CANCELED, data);
+        finish();
+    }
+
+    private String getAppNameForPackage(String pkg) {
+        final PackageManager pm = getApplicationContext().getPackageManager();
+        ApplicationInfo ai;
+        try {
+            ai = pm.getApplicationInfo(pkg, 0);
+        } catch (final PackageManager.NameNotFoundException e) {
+            ai = null;
+        }
+        return (String) (ai != null ? pm.getApplicationLabel(ai) : "(unknown)");
+    }
+
+    @OnClick(R.id.btnDecline)
+    void exitFailed() {
+        setResultAndExit(EXCEPTION_ACCOUNT_ACCESS_DECLINED);
+    }
+
+    @OnClick(R.id.btnGrant)
+    void grantPermission() {
+        final Bundle result = new Bundle();
+
+        // create token
+        SharedPreferences sharedPreferences = getSharedPreferences(SSO_SHARED_PREFERENCE, Context.MODE_PRIVATE);
+        String token = UUID.randomUUID().toString().replaceAll("-", "");
+
+        String hashedTokenWithSalt = EncryptionUtils.generateSHA512(token);
+
+        SharedPreferences.Editor editor = sharedPreferences.edit();
+        editor.putString(packageName, hashedTokenWithSalt);
+        editor.apply();
+
+        String serverUrl;
+        String userId;
+        try {
+            OwnCloudAccount ocAccount = new OwnCloudAccount(account, this);
+            serverUrl = ocAccount.getBaseUri().toString();
+            AccountManager accountManager = AccountManager.get(this);
+            userId = accountManager.getUserData(account,
+                    com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
+        } catch (AccountUtils.AccountNotFoundException e) {
+            Log_OC.e(TAG, "Account not found");
+            setResultAndExit(EXCEPTION_ACCOUNT_NOT_FOUND);
+            return;
+        }
+
+        result.putString(AccountManager.KEY_ACCOUNT_NAME,  account.name);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE,  MainApp.getAccountType(this));
+        result.putString(AccountManager.KEY_AUTHTOKEN,     NEXTCLOUD_SSO);
+        result.putString(Constants.SSO_USERNAME,   userId);
+        result.putString(Constants.SSO_TOKEN,      token);
+        result.putString(Constants.SSO_SERVER_URL, serverUrl);
+
+        //return result;
+
+        Intent data = new Intent();
+        data.putExtra(NEXTCLOUD_SSO, result);
+        setResult(RESULT_OK, data);
+        finish();
+    }
+
+}

+ 44 - 0
src/main/res/layout/activity_sso_grant_permission.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.owncloud.android.ui.activity.SsoGrantPermissionActivity">
+
+
+    <TextView
+        android:id="@+id/tvInfoText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/btnGrant"
+        android:layout_width="180dp"
+        android:layout_height="wrap_content"
+        android:text="@android:string/ok"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/btnDecline"
+        app:layout_constraintHorizontal_bias="0.5" />
+
+    <Button
+        android:id="@+id/btnDecline"
+        android:layout_width="180dp"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginRight="8dp"
+        android:text="@android:string/cancel"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toEndOf="@+id/btnGrant" />
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:srcCompat="@drawable/background"
+        app:layout_constraintTop_toBottomOf="@id/tvInfoText"/>
+
+</android.support.constraint.ConstraintLayout>

+ 2 - 0
src/main/res/values/strings.xml

@@ -817,4 +817,6 @@
     <string name="file_rename">Rename</string>
     <string name="fab_label">Add or upload</string>
     <string name="account_creation_failed">Account creation failed</string>
+
+    <string name="single_sign_on_request_token" formatted="true">App %1$s wants access to your Nextcloud account (%2$s), do you want to grant permission?</string>
 </resources>