From fd110432cc2a7b334b61502bf391c42dabb50f54 Mon Sep 17 00:00:00 2001 From: kenstir Date: Wed, 18 Nov 2015 10:52:24 -0500 Subject: [PATCH] Improved auth flow for generic app. * factored AccountManager interaction out into AccountUtils * switching back and forth between c/w mars accounts works, but not switching to admin@demo.evergreencatalog.com or admin@mlnc4.mvlcstaff.org. Will debug further. --- .../evergreen_ils/accountAccess/AccountAccess.java | 89 +++++++++------------- .../evergreen_ils/accountAccess/AccountUtils.java | 74 ++++++++++++++++++ .../evergreen_ils/auth/AuthenticatorActivity.java | 10 ++- .../core/src/org/evergreen_ils/auth/Const.java | 1 + .../evergreen_ils/auth/EvergreenAuthenticator.java | 8 +- .../org/evergreen_ils/globals/GlobalConfigs.java | 2 +- .../core/src/org/evergreen_ils/globals/Utils.java | 3 +- .../views/splashscreen/LoadingTask.java | 44 ++--------- .../views/splashscreen/SplashActivity.java | 15 ++-- 9 files changed, 135 insertions(+), 111 deletions(-) create mode 100644 Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountUtils.java diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountAccess.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountAccess.java index 61dfa22277..81f0aa0e60 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountAccess.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountAccess.java @@ -19,30 +19,25 @@ */ package org.evergreen_ils.accountAccess; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.*; - -import android.accounts.*; import android.app.Activity; -import android.os.Bundle; -import android.os.Looper; import android.text.TextUtils; import android.util.Log; -import org.evergreen_ils.R; import org.evergreen_ils.accountAccess.bookbags.BookBag; import org.evergreen_ils.accountAccess.bookbags.BookBagItem; import org.evergreen_ils.accountAccess.checkout.CircRecord; import org.evergreen_ils.accountAccess.fines.FinesRecord; import org.evergreen_ils.accountAccess.holds.HoldRecord; +import org.evergreen_ils.auth.Const; import org.evergreen_ils.globals.GlobalConfigs; import org.evergreen_ils.globals.Utils; import org.evergreen_ils.searchCatalog.RecordInfo; -import org.evergreen_ils.auth.Const; import org.opensrf.net.http.HttpConnection; import org.opensrf.util.OSRFObject; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + /** * The Class AuthenticateUser. Singleton class */ @@ -156,8 +151,6 @@ public class AccountAccess { /** home library ID. */ private Integer homeLibraryID = null; - private boolean haveSession; - /** The user name. */ public static String userName = null; @@ -236,29 +229,35 @@ public class AccountAccess { * Retrieve session. * @throws SessionNotFoundException */ - public boolean retrieveSession(String auth_token, boolean force) throws SessionNotFoundException { - - if (!force && this.haveSession && this.authToken.equals(auth_token)) - return true; - this.haveSession = false; + public boolean retrieveSession(String auth_token) throws SessionNotFoundException { + Log.d(Const.AUTH_TAG, "retrieveSession " + auth_token); + clearSession(); this.authToken = auth_token; - + Object resp = Utils.doRequest(conn(), SERVICE_AUTH, - METHOD_AUTH_SESSION_RETRV, authToken, new Object[] { - authToken}); + METHOD_AUTH_SESSION_RETRV, auth_token, new Object[]{ + auth_token}); if (resp != null) { OSRFObject au = (OSRFObject) resp; userID = au.getInt("id"); homeLibraryID = au.getInt("home_ou"); userName = au.getString("usrname"); //email = au.getString("email"); - this.haveSession = true; + + return true; } - return this.haveSession; + throw new SessionNotFoundException(); } - public static boolean runningOnUIThread() { - return (Looper.myLooper() == Looper.getMainLooper()); + private void clearSession() { + userID = null; + homeLibraryID = null; + userName = null; + authToken = null; + } + + public boolean reauthenticate(Activity activity) throws SessionNotFoundException { + return reauthenticate(activity, userName); } /** invalidate current auth token and get a new one @@ -266,38 +265,20 @@ public class AccountAccess { * @param activity * @return true if auth successful */ - public boolean reauthenticate(Activity activity) throws SessionNotFoundException, AuthenticatorException, OperationCanceledException, IOException { - boolean ok = false; - final AccountManager am = AccountManager.get(activity); - final String accountType = activity.getString(R.string.ou_account_type); - final Account account = new Account(userName, accountType); - am.invalidateAuthToken(accountType, authToken); - haveSession = false; - authToken = null; - if (runningOnUIThread()) - return false; - Bundle b = am.getAuthToken(account, Const.AUTHTOKEN_TYPE, null, activity, null, null).getResult(); - final String new_authToken = b.getString(AccountManager.KEY_AUTHTOKEN); - if (TextUtils.isEmpty(new_authToken)) - return false; - return retrieveSession(new_authToken, true); - } + public boolean reauthenticate(Activity activity, String user_name) throws SessionNotFoundException { + Log.d(Const.AUTH_TAG, "reauthenticate " + user_name); + AccountUtils.invalidateAuthToken(activity, authToken); + clearSession(); - public static String getLibraryUrl(Activity activity, String account_name, String account_type) { - final AccountManager am = AccountManager.get(activity); - Account account = new Account(account_name, account_type); - String library_url = am.getUserData(account, Const.KEY_LIBRARY_URL); - - // compatibility with specific apps like cwmars_app. If no library_url exists as userdata on the account, - // get it from the resources. - if (TextUtils.isEmpty(library_url)) { - library_url = activity.getString(R.string.ou_library_url); - if (!TextUtils.isEmpty(library_url)) { - am.setUserData(account, Const.KEY_LIBRARY_URL, library_url); - } + try { + String auth_token = AccountUtils.getAuthTokenForAccount(activity, user_name); + if (TextUtils.isEmpty(auth_token)) + return false; + return retrieveSession(auth_token); + } catch (Exception e) { + Log.i(Const.AUTH_TAG, "reauth exception", e); + return false; } - - return library_url; } // public void getOrgHiddentDepth() { diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountUtils.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountUtils.java new file mode 100644 index 0000000000..83971fff76 --- /dev/null +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/accountAccess/AccountUtils.java @@ -0,0 +1,74 @@ +package org.evergreen_ils.accountAccess; + +import android.accounts.*; +import android.app.Activity; +import android.os.Bundle; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import org.evergreen_ils.R; +import org.evergreen_ils.auth.Const; +import org.w3c.dom.Text; + +import java.io.IOException; + +/** + * Created by kenstir on 11/17/2015. + */ +public class AccountUtils { + + public static String getLibraryUrl(Activity activity, String account_name, String account_type) { + final AccountManager am = AccountManager.get(activity); + Account account = new Account(account_name, account_type); + String library_url = am.getUserData(account, Const.KEY_LIBRARY_URL); + + // compatibility with specific apps like cwmars_app. If no library_url exists as userdata on the account, + // get it from the resources. + if (TextUtils.isEmpty(library_url)) { + library_url = activity.getString(R.string.ou_library_url); + if (!TextUtils.isEmpty(library_url)) { + am.setUserData(account, Const.KEY_LIBRARY_URL, library_url); + } + } + + return library_url; + } + + public static void invalidateAuthToken(Activity activity, String auth_token) { + Log.i(Const.AUTH_TAG, "invalidateAuthToken "+auth_token); + final AccountManager am = AccountManager.get(activity); + final String accountType = activity.getString(R.string.ou_account_type); + am.invalidateAuthToken(accountType, auth_token); + } + + public static String getAuthTokenForAccount(Activity activity, String account_name) throws AuthenticatorException, OperationCanceledException, IOException { + Log.i(Const.AUTH_TAG, "getAuthTokenForAccount "+account_name); + if (runningOnUIThread() || TextUtils.isEmpty(account_name)) { + Log.i(Const.AUTH_TAG, "getAuthTokenForAccount returns null"); + return null; + } + final AccountManager am = AccountManager.get(activity); + final String accountType = activity.getString(R.string.ou_account_type); + final Account account = new Account(account_name, accountType); + Bundle b = am.getAuthToken(account, Const.AUTHTOKEN_TYPE, null, activity, null, null).getResult(); + final String auth_token = b.getString(AccountManager.KEY_AUTHTOKEN); + Log.i(Const.AUTH_TAG, "getAuthTokenForAccount " + account_name + " returns " + auth_token); + return auth_token; + } + + public static Bundle getAuthToken(Activity activity) throws AuthenticatorException, OperationCanceledException, IOException { + Log.i(Const.AUTH_TAG, "getAuthToken"); + if (runningOnUIThread()) + return new Bundle(); + final AccountManager am = AccountManager.get(activity); + final String accountType = activity.getString(R.string.ou_account_type); + AccountManagerFuture future = am.getAuthTokenByFeatures(accountType, Const.AUTHTOKEN_TYPE, null, activity, null, null, null, null); + Bundle bnd = future.getResult(); + Log.i(Const.AUTH_TAG, "getAuthToken returns "+bnd); + return bnd; + } + + public static boolean runningOnUIThread() { + return (Looper.myLooper() == Looper.getMainLooper()); + } +} diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/AuthenticatorActivity.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/AuthenticatorActivity.java index 6400fa2ece..a67a0bf93c 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/AuthenticatorActivity.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/AuthenticatorActivity.java @@ -285,9 +285,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { private void parseLibrariesJSON(String json) { libraries.clear(); - boolean isDebuggable = ( 0 != ( getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE ) ); - if (isDebuggable) { - Library library = new Library("https://demo.evergreencatalog.com", "Example Consortium", "00 (Example Consortium)"); + if (isDebuggable()) { + //Library library = new Library("https://demo.evergreencatalog.com", "Example Consortium", "00 (evergreencatalog.com Example Consortium)"); + Library library = new Library("https://mlnc4.mvlcstaff.org", "MVLC Demo", "00 (MVLC Demo)"); libraries.add(library); } @@ -319,4 +319,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity { } } } + + public boolean isDebuggable() { + return ( 0 != ( getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE ) ); + } } diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/Const.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/Const.java index 78e48625df..4f6f698d0e 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/Const.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/Const.java @@ -5,4 +5,5 @@ public class Const { public static final String AUTHTOKEN_TYPE = "opac"; public static final String AUTHTOKEN_TYPE_LABEL = "Online Public Access Catalog"; public static final String KEY_LIBRARY_URL = "library_url"; + public final static String AUTH_TAG = "eg_auth:"; } diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/EvergreenAuthenticator.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/EvergreenAuthenticator.java index 4009f8dd87..146c8eb057 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/EvergreenAuthenticator.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/auth/EvergreenAuthenticator.java @@ -6,20 +6,16 @@ import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; -import android.preference.PreferenceManager; -import org.evergreen_ils.globals.AppPrefs; import org.opensrf.Method; import org.opensrf.net.http.GatewayRequest; import org.opensrf.net.http.HttpConnection; import org.opensrf.net.http.HttpRequest; -import android.content.Context; import android.text.TextUtils; import android.util.Log; -import org.evergreen_ils.R; public class EvergreenAuthenticator { - private final static String TAG = "eg.auth"; + private final static String TAG = EvergreenAuthenticator.class.getSimpleName(); public final static String SERVICE_AUTH = "open-ils.auth"; public final static String METHOD_AUTH_INIT = "open-ils.auth.authenticate.init"; public final static String METHOD_AUTH_COMPLETE = "open-ils.auth.authenticate.complete"; @@ -44,7 +40,7 @@ public class EvergreenAuthenticator { return hexString.toString(); } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); + Log.d(TAG, "no MD5", e); } return ""; diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/GlobalConfigs.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/GlobalConfigs.java index f22a4a2674..d749092e20 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/GlobalConfigs.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/GlobalConfigs.java @@ -220,7 +220,7 @@ public class GlobalConfigs { }); long duration_ms = System.currentTimeMillis() - start_ms; - Log.d("init", "getOrg took "+duration_ms+"ms"); + Log.d(TAG, "getOrg took "+duration_ms+"ms"); loadedOrgTree = true; } } diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/Utils.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/Utils.java index 46b9fc2500..0e7178484d 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/Utils.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/globals/Utils.java @@ -36,6 +36,7 @@ import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.evergreen_ils.accountAccess.SessionNotFoundException; +import org.evergreen_ils.auth.Const; import org.opensrf.Method; import org.opensrf.net.http.GatewayRequest; import org.opensrf.net.http.HttpConnection; @@ -159,7 +160,7 @@ public class Utils { String textcode = getResponseTextcode(resp); if (TextUtils.equals(textcode, "NO_SESSION")) { - Log.d(TAG, textcode); + Log.d(Const.AUTH_TAG, textcode); throw new SessionNotFoundException(); } diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/LoadingTask.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/LoadingTask.java index 2c92cbf4d0..36c41d4f7c 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/LoadingTask.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/LoadingTask.java @@ -22,18 +22,17 @@ package org.evergreen_ils.views.splashscreen; import android.text.TextUtils; import org.evergreen_ils.R; import org.evergreen_ils.accountAccess.AccountAccess; +import org.evergreen_ils.accountAccess.AccountUtils; import org.evergreen_ils.accountAccess.SessionNotFoundException; import org.evergreen_ils.globals.AppPrefs; import org.evergreen_ils.globals.GlobalConfigs; import org.evergreen_ils.auth.Const; -import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerFuture; import android.app.Activity; import android.os.Bundle; import android.util.Log; -import org.w3c.dom.Text; /** This is basically the same as an AsyncTask, except that it uses * a Thread. Starting with HONEYCOMB, tasks are executed on a single thread and the 2nd @@ -44,7 +43,7 @@ import org.w3c.dom.Text; */ public class LoadingTask { private final String TAG = LoadingTask.class.getSimpleName(); - + public static final String TASK_OK = "OK"; public interface LoadingTaskListener { @@ -56,12 +55,10 @@ public class LoadingTask { // This is the listener that will be told when this task is finished private final LoadingTaskListener mListener; private Activity mCallingActivity; - private AccountManager mAccountManager; public LoadingTask(LoadingTaskListener listener, Activity callingActivity) { this.mListener = listener; this.mCallingActivity = callingActivity; - mAccountManager = AccountManager.get(callingActivity); } public void execute() { @@ -95,19 +92,17 @@ public class LoadingTask { protected String doInBackground() { final String tag ="doInBackground> "; final String accountType = mCallingActivity.getString(R.string.ou_account_type); - Log.d(TAG, tag); try { Log.d(TAG, tag+"Signing in"); publishProgress("Signing in"); - AccountManagerFuture future = mAccountManager.getAuthTokenByFeatures(accountType, Const.AUTHTOKEN_TYPE, null, mCallingActivity, null, null, null, null); - Bundle bnd = future.getResult(); + Bundle bnd = AccountUtils.getAuthToken(mCallingActivity); String auth_token = bnd.getString(AccountManager.KEY_AUTHTOKEN); String account_name = bnd.getString(AccountManager.KEY_ACCOUNT_NAME); - if (account_name == null) + if (TextUtils.isEmpty(auth_token) || TextUtils.isEmpty(account_name)) return "no account"; - String library_url = AccountAccess.getLibraryUrl(mCallingActivity, account_name, accountType); + String library_url = AccountUtils.getLibraryUrl(mCallingActivity, account_name, accountType); AppPrefs.setString(AppPrefs.LIBRARY_URL, library_url); Log.d(TAG, tag+"Loading resources from "+library_url); @@ -120,36 +115,13 @@ public class LoadingTask { // auth token zen: try once and if it fails, invalidate the token and try again boolean haveSession = false; - boolean retry = false; try { - haveSession = ac.retrieveSession(auth_token, true); + haveSession = ac.retrieveSession(auth_token); } catch (SessionNotFoundException e) { - mAccountManager.invalidateAuthToken(accountType, auth_token); - retry = true; - } - if (retry) { - // todo: replace with AccountAccess.reauthenticate? - try { - haveSession = ac.reauthenticate(mCallingActivity); - } catch (Exception e) { - Log.d(TAG, tag+"failed a 2nd time", e); - } - /* - final Account account = new Account(account_name, accountType); - future = mAccountManager.getAuthToken(account, Const.AUTHTOKEN_TYPE, null, mCallingActivity, null, null); - bnd = future.getResult(); - Log.d(TAG, tag+"bnd="+bnd); - auth_token = bnd.getString(AccountManager.KEY_AUTHTOKEN); - account_name = bnd.getString(AccountManager.KEY_ACCOUNT_NAME); - Log.d(TAG, tag+"account_name="+account_name+" token="+auth_token); - if (account_name == null) - return "no account"; try { - haveSession = ac.retrieveSession(auth_token, true); - } catch (SessionNotFoundException e) { - Log.d(TAG, tag+"failed a 2nd time", e); + haveSession = ac.reauthenticate(mCallingActivity, account_name); + } catch (SessionNotFoundException e2) { } - */ } if (!haveSession) return "no session"; diff --git a/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/SplashActivity.java b/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/SplashActivity.java index acad756bdd..fa25ae907e 100644 --- a/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/SplashActivity.java +++ b/Open-ILS/src/Android/core/src/org/evergreen_ils/views/splashscreen/SplashActivity.java @@ -81,7 +81,6 @@ public class SplashActivity extends Activity implements LoadingTaskListener { @Override public void onCreate(Bundle savedInstanceState) { - Log.d(TAG, "kcxxx: oncreate"); super.onCreate(savedInstanceState); this.mContext = this; @@ -111,7 +110,7 @@ public class SplashActivity extends Activity implements LoadingTaskListener { @Override protected void onStart() { super.onStart(); - Log.d(TAG, "kcxxx: onstart"); + Log.d(TAG, "onstart"); if (!restarted) { startTask(); } @@ -121,19 +120,19 @@ public class SplashActivity extends Activity implements LoadingTaskListener { protected void onRestart() { super.onRestart(); restarted = true; - Log.d(TAG, "kcxxx: onrestart"); + Log.d(TAG, "onrestart"); } @Override protected void onResume() { super.onResume(); - Log.d(TAG, "kcxxx: onresume"); + Log.d(TAG, "onresume"); } @Override protected void onStop() { super.onStop(); - Log.d(TAG, "kcxxx: onstop"); + Log.d(TAG, "onstop"); if (mAlertDialog != null) { mAlertDialog.dismiss(); } @@ -141,7 +140,7 @@ public class SplashActivity extends Activity implements LoadingTaskListener { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - Log.d(TAG, "kcxxx: onactivityresult: " + requestCode + " " + resultCode); + Log.d(TAG, "onactivityresult: " + requestCode + " " + resultCode); } private void startApp() { @@ -159,7 +158,6 @@ public class SplashActivity extends Activity implements LoadingTaskListener { @Override public void onProgressUpdate(String value) { - Log.d(TAG, "onProgressUpdate> " + value); mProgressText.setText(value); } @@ -167,10 +165,8 @@ public class SplashActivity extends Activity implements LoadingTaskListener { public void onPostExecute(String result) { Log.d(TAG, "onPostExecute> " + result); mTask = null; - Log.d(TAG, "progressbar...gone"); mProgressBar.setVisibility(View.GONE); if (TextUtils.equals(result, LoadingTask.TASK_OK)) { - Log.d(TAG, "startApp"); startApp(); } else { String extra_text; @@ -180,7 +176,6 @@ public class SplashActivity extends Activity implements LoadingTaskListener { extra_text = "...Cancelled"; Log.d(TAG, "progresstext += " + extra_text); mProgressText.setText(mProgressText.getText() + extra_text); - Log.d(TAG, "retrybutton...visible"); mRetryButton.setVisibility(View.VISIBLE); } } -- 2.11.0