Android OAuth: Exception on retrieveAccessToken() - android

I'm setting up OAuth for my Android app. To test it I did the following:
Added signpost-core-1.2.1.1.jar and signpost-commonshttp4-1.2.1.1.jar to my project, added the variables "CommonsHttpOAuthConsumer consumer" and "CommonsHttpOAuthProvider provider" and did the following when the button is clicked:
consumer = new CommonsHttpOAuthConsumer("xxx", "yyy");
provider = new CommonsHttpOAuthProvider("https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize");
oauthUrl = provider.retrieveRequestToken(consumer, "myapp://twitterOauth");
persistOAuthData();
this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(oauthUrl)));
persistOAuthData() does the following:
protected void persistOAuthData()
{
try
{
FileOutputStream providerFOS = this.openFileOutput("provider.dat", MODE_PRIVATE);
ObjectOutputStream providerOOS = new ObjectOutputStream(providerFOS);
providerOOS.writeObject(this.provider);
providerOOS.close();
FileOutputStream consumerFOS = this.openFileOutput("consumer.dat", MODE_PRIVATE);
ObjectOutputStream consumerOOS = new ObjectOutputStream(consumerFOS);
consumerOOS.writeObject(this.consumer);
consumerOOS.close();
}
catch (Exception e) { }
}
So, the consumer and the provider are saved before opening the browser, like described here.
In the onResume() method I load the provider and consumer data and do the following:
Uri uri = this.getIntent().getData();
if (uri != null && uri.getScheme().equals("myapp") && uri.getHost().equals("twitterOauth"))
{
verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
if (!verifier.equals(""))
{
loadOauthData();
try
{
provider.retrieveAccessToken(consumer, verifier);
}
catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthNotAuthorizedException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
}
}
So, what works:
1) I do get a requestToken and a requestSecret.
2) I do get the oauthUrl.
3) I am directed to the browser page to authorize my app
4) I am getting redirected to my app.
5) I do get the verifier.
But calling retrieveAccessToken(consumer, verifier) fails with an OAuthCommunicationException saying "Communication with the service provider failed: null".
Does anyone know what might be the reason? Some people seem to have problems getting the requestToken, but that just works fine. I wonder if it might be a problem that my app has also included the apache-mime4j-0.6.jar and httpmime-4.0.1.jar which I need for multipart upload.

Okay, I figured it out. Maybe this is helpful to others:
First of all, you do not need to save the whole consumer and provider object. All you need to do is store the requestToken and the requestSecret. Luckily, those are Strings, so you don't need to write them to disk or anything. Just store them in the sharedPreferences or something like that.
Now, when you get redirected by the browser and your onResume() method is called, just do the following:
//The consumer object was lost because the browser got into foreground, need to instantiate it again with your apps token and secret.
consumer = new CommonsHttpOAuthConsumer("xxx", "yyy");
//Set the requestToken and the tokenSecret that you got earlier by calling retrieveRequestToken.
consumer.setTokenWithSecret(requestToken, tokenSecret);
//The provider object is lost, too, so instantiate it again.
provider = new CommonsHttpOAuthProvider("https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize");
//Now that's really important. Because you don't perform the retrieveRequestToken method at this moment, the OAuth method is not detected automatically (there is no communication with Twitter). So, the default is 1.0 which is wrong because the initial request was performed with 1.0a.
provider.setOAuth10a(true);
provider.retrieveAccessToken(consumer, verifier);
That's it, you can receive the token and the secret with getToken() and getTokenSecret(), now.

Hi Manuel i see you are avoidin the OAuthocalypse too!
heres is a good example to implement OAuth for Twitter using sharedPreferences to save requestToken and the requestSecret, like your solution.
http://github.com/brione/Brion-Learns-OAuth
by Brion Emde
heres the video
hope this helps other developers =)

Related

Connecting my app to local network using smb protocol

I'm trying to connect my Android application to my company local network (Windows) using smb protocol. The problem is I'm kinda newbie on this matter and something is missing me.
The goal is download the file AREQA.txt from the network to the device. However I don't even can verify if the code can trace the file location because the application crashes when I compile it to the device (it loads fine but crashes when I call the DownLoadF001 procedure). Here's the code:
public void DownLoadF001(View v) {
jcifs.Config.registerSmbURLHandler();
String user;
String password;
String filename;
File localFile;
SmbFile path = null;
try {
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null,"######", "********");
path = new SmbFile("smb:\\192.168.1.11/.../AREQA.txt", auth);
try {
if(path.exists()){
Toast.makeText(getApplicationContext(), "Sucesso!", Toast.LENGTH_LONG).show();
}
} catch (Exception e1) {
Toast.makeText(getApplicationContext(), e1.toString(), Toast.LENGTH_LONG).show();
}
} catch (MalformedURLException e2) {
Toast.makeText(getApplicationContext(), e2.toString(), Toast.LENGTH_LONG).show();
}
}
I already tried to remove the inside try from the main one (with all its associated code), and the application stops crashing. However, without it, I can't see if the connection is working.
EDIT: I managed to catch the error (Exception e1):
java.lang.NullPointerException: Attempt to invoke virtual method int java.lang.String.length()' on a null object reference. Any ideas to solve it?
Also, as pointed by #greenapps, I'm calling this procedure from a .xml button by onClick method.

How to store facebook profile picture into Parse user table?

I want to store the facebook profile picture into the parse user table.
Currently i'm trying this:
URL img_value = null;
try {
img_value = new URL("http://graph.facebook.com/"+user.getId()+"/picture?type=small");
} catch (MalformedURLException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Bitmap dp = BitmapFactory.decodeStream(img_value.openConnection().getInputStream());
Log.i(IntegratingFacebook.TAG, "image retrieved from facebook");
// Save the user profile info in a user property
ParseUser currentUser = ParseUser.getCurrentUser();
if(dp!=null){
ParseFile saveImageFile= new ParseFile("profilePicture.jpg",compressAndConvertImageToByteFrom(dp));
currentUser.put("profilePicture",saveImageFile);
}
currentUser.saveInBackground();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The URL is right. However dp is always null.
Therefore the image is never stored in the parse user table.
Any help is appreciated.
Your code looks correct EXCEPT for the fact that all calls to graph.facebook.com should be over SSL. switch your http to https and you should be good to go.
This is assuming that you are in a facebook callback were the user object is not a ParseUser object because FacebookUserObject.getId() and ParseUserObject.getId() will obviously return different results. If you are in a Facebook callback from a request like Request.newMeRequest() then your code will work by simply changing the protocol to https. If you are not in a facebook callback and the user object is a ParseUser object then you will want to use something like user.getString("facebookId") where facebookId is a value you've saved in a previous step (perhaps during initial registration).
The way you are going about doing it is very messy and might break sometime in the future... BUT have you ever heard of Picasso.
Make sure your URL is good (logcat), grab the picasso library for Android and change this:
Bitmap dp = BitmapFactory.decodeStream(img_value.openConnection().getInputStream());
into this ( try/catch needed )
Bitmap dp = Picasso.with(getActivity()).load(URL).get();
and you should be good to go!

Cannot create spreadsheet

Here is my code:
SpreadsheetService spreadsheet= new SpreadsheetService("v1");
spreadsheet.setProtocolVersion(SpreadsheetService.Versions.V3);
try {
spreadsheet.setUserCredentials("username", "password");
URL metafeedUrl = new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full");
SpreadsheetFeed feed = spreadsheet.getFeed(metafeedUrl, SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
for (SpreadsheetEntry service : spreadsheets) {
System.out.println(service.getTitle().getPlainText());
}
} catch (AuthenticationException e) {
e.printStackTrace();
}
But it doesn't seem to work. It always crashes in the Constructor for the Spreadsheet. I am using these libraries:
gdata-client-1.0
gdata-client-meta-1.0
gdata-core-1.0
gdata-spreadsheet-3.0
gdata-spreadsheet-meta-3.0
guava-13.0.1
Can anyone tell me what could be possibly be wrong?
It crashes in the constructor for Spreadsheet? Not SpreadsheetService? Where is an instance of Spreadsheet created? Maybe somewhere behind the scenes, I guess. Anyway, as one commenter said, check with logcat. If you have absolutely no clue where it's crashing (it should tell you, if you read the wall of text that comes up), just throw logcat absolutely everywhere possible.
static final String MESSAGE = "SPREADSHEET TEST MESSAGE:";
SpreadsheetService spreadsheet= new SpreadsheetService("v1");
Log.d(MESSAGE, "spreadsheet was created successfully.");
spreadsheet.setProtocolVersion(SpreadsheetService.Versions.V3);
Log.d(MESSAGE, "setProtocolVersion done successfully.");
try {
spreadsheet.setUserCredentials("username", "password");
Log.d(MESSAGE, "set credentials worked.");
URL metafeedUrl = new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full");
Log.d(MESSAGE, "metafeedUrl was created successfully.");
SpreadsheetFeed feed = spreadsheet.getFeed(metafeedUrl, SpreadsheetFeed.class);
Log.d(MESSAGE, "feed was created, too.");
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
Log.d(MESSAGE, "spreadsheets List was created successfully.");
for (SpreadsheetEntry service : spreadsheets) {
System.out.println(service.getTitle().getPlainText());
}
Log.d(MESSAGE, "The for-loop worked.");
} catch (AuthenticationException e) {
e.printStackTrace();
}
It looks stupid, but you can just delete all the messages once it's working. I usually only do this kind of thing if I have no clue in the name of all that is holy what's going on; it should yield more results than just staring at the screen.
Anyway, see where it fails and figure it out from there. Maybe ask a clearer question once you're better informed.

Dropbox Api AccessToken Changed

I am developing an android application that has the potential to provide large amount of statistical information. I want to save this data on my dropbox to be analyzed later.
So I used the AuthActivity to get the key and secret for my own account, which I then hardcoded to get an AcessTokenPair instance:
AcessTokenPair tokenPair = new AccessTokenPair("key", "secret");
mDBApi.getSession().setAccessTokenPair(tokenPair);
I then send the file to my dropbox using the AsyncTask below:
private class SendToDropbox extends AsyncTask<String, Void, String> {
#SuppressWarnings("deprecation")
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
String timestamp = new Date().toString();
FileInputStream inputStream = null;
DisplayMetrics dm = new DisplayMetrics();
win.getDefaultDisplay().getMetrics(dm);
double x = Math.pow(dm.widthPixels / dm.xdpi, 2);
double y = Math.pow(dm.heightPixels / dm.ydpi, 2);
double screenInches = Math.sqrt(x + y);
File sdcard = new File(Environment.getExternalStorageDirectory()
.getPath());
File session = null;
try {
session = File.createTempFile("analytics_" + timestamp, ".txt", sdcard);
if (session.exists()) {
PrintStream ps = new PrintStream(session);
ps.println("Screen Size: " + screenInches);
ps.println("Device: " + android.os.Build.MODEL);
ps.println("Carrier: " + android.os.Build.BRAND);
ps.println("Locale: " + Locale.getDefault().toString());
ps.println("OS: " + android.os.Build.VERSION.SDK);
ps.println("${EOF}");
ps.checkError();
ps.close();
inputStream = new FileInputStream(session);
com.dropbox.client2.DropboxAPI.Entry newEntry = mDBApi
.putFile("Analytics" + File.separator
+ session.getName(), inputStream,
session.length(), null, null);
if (session.delete()) {
} else {
session.deleteOnExit();
}
Log.i("DbExampleLog", "The uploaded file's rev is: "
+ newEntry.rev);
} else {
Log.e("DropBoxFile", "SD NOT MOUNTED!!");
}
} catch (DropboxUnlinkedException e) {
// User has unlinked, ask them to link again here.
Log.e("DbExampleLog", "User has unlinked.");
} catch (DropboxException e) {
Log.e("DbExampleLog", "Something went wrong while uploading.");
} catch (FileNotFoundException e) {
Log.e("DbExampleLog", "File not found.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
return null;
}
The only problem with this code is that it only works a few weeks, maybe a month before the access token changes. This means I would have to manually update the apk every few weeks, which isn't very feasible. Instead I would like to store the keys on a website or online file that I can access via http.
Are there any free programs that DO NOT require account access and allow you to upload and edit .txt files on the web?
Access tokens do not currently expire, though that may change in future. You'd need to be very careful never to unlink your app from the account used to generate the token, though, since that would invalidate the token which is hard-coded into your app.
I can't recommend this, though, for security reasons. A token embedded into your app can be discovered by someone reverse-engineering the app. And anyone with that token can not only read, but also write to the Dropbox (or App folder) to which the token has access, and by doing so they might screw up the other users of your app.
From the Dropbox Best Practices: Best Practices
Your app should take precautions in case of revoked access. Access tokens may be disabled by the user (from the account page), revoked by Dropbox administrators in cases of abuse, or simply expire over time.
In the case where a token is no longer authorized, the REST API will return an HTTP Error 401 Unauthorized response. The iOS SDK detects 401s for you and will call the sessionDidReceiveAuthorizationFailure: method on the session's delegate to notify you that the authorization was revoked. The Android, Python, Ruby, and Java SDKs will all raise an exception on server errors that you can catch and inspect. Re-authenticating is typically all that is necessary to regain access.
So the Access Token can surely change over time. You just must be flexible enough to deal with that.

Twitter4j Android FileNotFoundException by executing "getFollowersIDs" or "getDirectMessages"

I use twitter4j on my Android 1.6 phone to request user related data such as all new direct messages or follower ids. It works fine if I only request trends or other user unrelated information (trends for example) but if I try to query information such as the follower ids or new direct messages twitter4j throws an TwitterException with the following cause
java.io.FileNotFoundException: http://api.twitter.com/1/direct_messages.json
I create an instance of twitter with the following code:
TwitterFactory twitterFax = new TwitterFactory();
twitterInstance = twitterFax.getInstance(USERNAME, USER_PASSWORD);
The exception throws here:
try {
ResponseList<DirectMessage> directMessages = twitterInstance.getDirectMessages();
if(directMessages.size() > 0){
publishProgress(directMessages.toArray());
}
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Why does it not work?
The twitter API doesn't support simple authentication anymore (you also didn't verify them as well), use OAuth:
http://twitter4j.org/en/code-examples.html#oauth
Also see: Twitter4J exception on verifyCredentials

Categories

Resources