dimanche 19 mai 2013

Sample Android OAuth client

OAuth is the Internet protocol that gives you an authorized access to resources on the Internet without grating user credentials. It has been deployed by many services like Twitter, Google, Yahoo or LinkedIn. And there are some libraries / code snippet in most every programming language that implement OAuth, but it is still hard to get it work (at least on Android).
Here is a sample code snippets based on the Signpost library that uses a custom WebView to intercept HTTP calls and handle them.
First the OAuthHelper.java the helper class:
private Context mContext;
private OAuthConsumer mConsumer;
private OAuthProvider mProvider;
private String mCallbackUrl;
private SharedPreferences mSettings;
private OAuthListener mListener;

public OAuthHelper(Context context, String consumerKey, String consumerSecret) {
   if ((consumerKey == null || "".equals(consumerKey)) && (consumerSecret == null || "".equals(consumerSecret))) {
      throw new IllegalArgumentException("You must specify your \"consumer Key\" and your \"consumer Secret\" when instantiating a OAuthHelper object");
   }
   mContext = context;
   mConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
   mProvider = new CommonsHttpOAuthProvider(QypeConstants.REQUEST_TOKEN_URL, QypeConstants.ACCESS_TOKEN_URL, QypeConstants.AUTHORIZE_URL);
   mProvider.setOAuth10a(true);
   mCallbackUrl = QypeConstants.REDIRECT_URI;
     
   mSettings = context.getSharedPreferences(QypeConstants.PREFS_NAME, 0);
}

public void authorize(OAuthListener listener) 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException, OAuthExpectationFailedException, OAuthCommunicationException {

   mListener = listener;
   OAuthLoginDialog oauthDialog = new OAuthLoginDialog(mContext, this);
   oauthDialog.loadUrl(getRequestToken());
   oauthDialog.show();
}

public String getRequestToken() 
   throws OAuthMessageSignerException, OAuthNotAuthorizedException,
   OAuthExpectationFailedException, OAuthCommunicationException {
   String authUrl = mProvider.retrieveRequestToken(mConsumer, mCallbackUrl);
   return authUrl;  
}

public String[] getVerifier(String uriString) {       
   return getVerifier(Uri.parse(uriString));
}

public String[] getVerifier(Uri uri) {
   // extract the token if it exists     
   if (uri == null) {
      return null;
   }
   String token = uri.getQueryParameter("oauth_token");
   String verifier = uri.getQueryParameter("oauth_verifier");
   return new String[] { token, verifier };
}

public String[] getAccessToken() {
   String access_token = mSettings.getString(ACCESS_TOKEN, null);
   String secret_token = mSettings.getString(SECRET_TOKEN, null);
   if(access_token==null || secret_token==null)
      return null;
   return new String[] {access_token, secret_token};
}

public void getAccessToken(final String verifier) {
   new Thread(new Runnable() {   
      public void run() {
         try {
            mProvider.retrieveAccessToken(mConsumer, verifier);
            mSettings.edit().putString(ACCESS_TOKEN, mConsumer.getToken()).commit();
            mSettings.edit().putString(SECRET_TOKEN, mConsumer.getTokenSecret()).commit();
            mListener.onOAuthComplete();     
         }catch(Exception e) {            
            e.printStackTrace();
         }
      }
   }).run();
}

public String request(String url) {
   String content = null;
   try {
       String accessToken[] = getAccessToken();
       mConsumer.setTokenWithSecret(accessToken[0], accessToken[1]);   
       HttpGet request = new HttpGet(url);
       // sign the request
       mConsumer.sign(request);
       // send the request
       HttpClient httpClient = new DefaultHttpClient();
       HttpResponse response = httpClient.execute(request);   
       content = EntityUtils.toString(response.getEntity());
   } catch (Exception e) {
       e.printStackTrace(); 
   }
   return content;
}
Second, the OAuthLoginDialog.java that will be used to intercept HTTP call back url
public class OAuthLoginDialog extends Dialog {
   private WebView mWebView;
   private OAuthHelper mHelper;

   public OAuthLoginDialog(Context context, OAuthHelper helper) {
      super(context);
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      setContentView(R.layout.login_dialog);

      LayoutParams params = getWindow().getAttributes();
      params.height = LayoutParams.MATCH_PARENT;
      params.width = LayoutParams.MATCH_PARENT;
      getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);

      mHelper = helper;

      init();
   }
   private void init() {
      mWebView = (WebView) findViewById(R.id.webView);
      mWebView.getSettings().setJavaScriptEnabled(true);

      mWebView.setWebViewClient(new WebViewClient() {
         @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {}
         @Override public void onPageStarted(WebView view, String url, Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
             progressBar.setVisibility(View.VISIBLE);
             if(url.startsWith(REDIRECT_URI)) {
                if(mHelper.getAccessToken() == null) {
                   String[] token = mHelper.getVerifier(url);
                   mHelper.getAccessToken(token[1]);
                }     
                mWebView.clearCache(true);
                dismiss();
             } 
         }

         @Override public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             progressBar.setVisibility(View.GONE);
         }

      });

   }
 
   public void loadUrl(String url) {
      mWebView.loadUrl(url);
   }
}
Third, the OAuth listener interface
public interface OAuthListener {
   // Called when the user is logged to the server
   public void onOAuthComplete();
   // Called when the user has canceled the login process
   public void onOAuthCancel();
   // Called when the login process has failed
   public void onOAuthError(int errorCode, String description, String failingUrl);
}
Finally, this is the code used to initiate an OAuth connection
OAuthHelper mHelper = new OAuthHelper(mContext, API_KEY, API_SECRET);
mHelper.authorize(new OAuthListener() {    
   public void onOAuthError(int errorCode, String description, String failingUrl) {}
   public void onOAuthComplete() {
      String testUrl = "http://sample_url_for_oauth_authorization/";
      mHelper.request(testUrl)
   }    
   public void onOAuthCancel() {}
});  
More resources can be found here implementing client side OAuth for android (it uses intent filter instead of a custom dialog) and here a sample OAuth for twitter.

Get the code for a sample project on Github.

Aucun commentaire:

Enregistrer un commentaire