0

Task
Create a one-time login feature using Android's authentication manager.

Current Process
I am currently using the Volley to read email and password from a form and send a request to a server

Required Change
To be able to create a one-time login for the use with credentials, using Android authentication manager following this post.

Question
1. My question lies in the implementation of the fetchTokenFromCredentials method under the getAuthToken of the authenticator class.

Here is the Java code snippet:

@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
throws NetworkErrorException {

    // We can add rejection of a request for a token type we
    // don't support here
    // Get the instance of the AccountManager that's making the
    // request
    final AccountManager am = AccountManager.get(mContext);

    // See if there is already an authentication token stored
    String authToken = am.peekAuthToken(account, authTokenType);

    // If we have no token, use the account credentials to fetch
    // a new one, effectively another logon
    if (TextUtils.isEmpty(authToken)) {
        final String password = am.getPassword(account);
        if (password != null) {
            authToken = fetchTokenFromCredentials(account.name, password, authTokenType)
        }
    }

    // If we either got a cached token, or fetched a new one, hand
    // it back to the client that called us.
    if (!TextUtils.isEmpty(authToken)) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
        result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
        return result;
    }

    // If we get here, then we don't have a token, and we don't have
    // a password that will let us get a new one (or we weren't able
    // to use the password we do have).  We need to fetch
    // information from the user, we do that by creating an Intent
    // to an Activity child class.
    final Intent intent = new Intent(mContext, LoginActivity.class);

    // We want to give the Activity the information we want it to
    // return to the AccountManager.  We'll cover that with the
    // KEY_ACCOUNT_AUTHENTICATOR_RESPONSE parameter.
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    // We'll also give it the parameters we've already looked up, or
    // were given.
    intent.putExtra(LoginActivity.ARG_IS_ADDING_NEW_ACCOUNT, false);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_NAME, account.name);
    intent.putExtra(LoginActivity.ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(LoginActivity.ARG_AUTH_TYPE, authTokenType);

    // Remember that we have to return a Bundle, not an Intent, but
    // we can tell the caller to run our intent to get its
    // information with the KEY_INTENT parameter in the returned
    // Bundle
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);
    return bundle;
}

Previously I was using Volley , so my implementation of fetchTokenfromCredentials was something like shown below. However, I cannot use the same implementation now because I need to 'return' an authentication string. Volley does the login asynchronously so even if i add a return type to the function below it will always return null. Question: How do i wrap around THIS situation. What alternatives can I use?

public void fetchTokenfromCredentials(String name, String password) {
    JSONObject loginObject = new JSONObject();
    try {
        loginObject.put("email", email);
        loginObject.put("password", password);
    } catch(JSONException e) {
        e.printStackTrace();
    }
    // assume predefined url and params
    JsonObjectRequest loginRequest = new HeaderRequest(Request.Method.POST, url + params, loginObject, new Response.Listener < JSONObject > () {@Override
        public void onResponse(JSONObject response) {
            try {
                JSONObject headers = response.getJSONObject("headers");
                // A simple use class that stores the id, username etc.
                user = new User(response.getInt("id"), response.getString("name"), response.getString("authentication_token"), response.getString("email"));
                // Previous code started a new main activity intent here
            } catch(JSONException e) {
                e.printStackTrace();
            }
        }
    },
    new Response.ErrorListener() {@Override
        public void onErrorResponse(VolleyError error) {
            Log.d(TAG, "Failed response");
        }
    });
    RequestQueueSingleton.getInstance(this.getApplicationContext()).addToRequestQueue(loginRequest);
}
karel
  • 5,489
  • 46
  • 45
  • 50
CoderBC
  • 1,262
  • 2
  • 13
  • 30

2 Answers2

0

You can make a synchronous, blocking request with Volley. That request will perform the network request, while blocking the thread and allow you to set a return type.

I am not fluent with Volley (Retrofit, FTW!) but I am pretty sure it's doable.

Take a look at this answer for a Synchronous request - https://stackoverflow.com/a/23808857

Shobhit
  • 647
  • 1
  • 7
  • 19
0

This is how I wrote the fetchTokensFromCredentials(email,password) function using the android Http Client Library:

URL was created using a uri builder

Uri builtUri = Uri.parse(AccountGeneral.LOGIN_QUERY).buildUpon()
        .build();
URL url = null;
try {
    url = new URL(builtUri.toString());
} catch (MalformedURLException e) {
    e.printStackTrace();
}

// Stores result of the post response
        String result = null;

        // Create a JSON object for the email and password
        JSONObject loginObject = new JSONObject();
        try{
            loginObject.put("email", email);
            loginObject.put("password", password);
        } catch(JSONException e) {
            e.printStackTrace();
        }

        // Convert JSON to String
        String data = loginObject.toString();

        // Connection parameters
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setRequestProperty("Content-Type", "application/json");
        urlConnection.setRequestProperty("Accept", "application/json");
        urlConnection.setRequestMethod("POST");

        try {

            //Start POST request - Write
            OutputStream outputStream = urlConnection.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
            writer.write(data);
            writer.close();
            outputStream.close();

            //Read response
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));

            String line = null;
            StringBuilder sb = new StringBuilder();

            while ((line = bufferedReader.readLine()) != null) {
                sb.append(line);
            }

            bufferedReader.close();
            result = sb.toString();

            return result;

        } finally {
            urlConnection.disconnect();
        }
CoderBC
  • 1,262
  • 2
  • 13
  • 30