Google OAuth Java client and Twitter API - java

I'm having issues invoking twitter REST API using Google OAuth Java Client. I'm able to do the first steps correctly:
Set the authorization URL,
Get the temporary token,
Generate the final token.
Then the OAuth Javadoc says:
Use the stored access token to authorize HTTP requests to protected
resources by setting the OAuthParameters.token and using
OAuthParameters as the HttpRequestInitializer.
It's in this step that I have issues. First of all if I only set the OAuthParameters.token value I'll get a null exception because the signer isn't set so what I presently have is:
OAuthHmacSigner signer = new OAuthHmacSigner();
signer.clientSharedSecret=TWITTER_CONSUMER_SECRET;
String oauthToken = req.getParameter("oauth_token");
String oauthVerifier = req.getParameter("oauth_verifier");
OAuthGetAccessToken accessTokenRequest = new OAuthGetAccessToken(TWITTER_ACESS_TOKEN_URL);
accessTokenRequest.consumerKey=TWITTER_CONSUMER_KEY;
accessTokenRequest.signer=signer;
accessTokenRequest.transport=HTTP_TRANSPORT;
accessTokenRequest.temporaryToken=oauthToken;
accessTokenRequest.verifier=oauthVerifier;
OAuthCredentialsResponse credentials = accessTokenRequest.execute();
String token = credentials.token;
OAuthParameters params = new OAuthParameters();
params.token=token;
params.version="1.0";
params.consumerKey=TWITTER_CONSUMER_KEY;
params.signer=signer;
HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(params);
HttpResponse twResponse = requestFactory.buildGetRequest(new GenericUrl("https://api.twitter.com/1.1/account/verify_credentials.json")).execute();
The result is always:
WARNING: Authentication error: Unable to respond to any of these
challenges: {} com.google.api.client.http.HttpResponseException: 401
OK {"errors":[{"message":"Could not authenticate you","code":32}]}
If I try the Authorization header given by Twitter OAuth tool through a REST Chrome extension tool it works perfectly so it's not an account issue. When I change it for the Authorization header value computed by the Google OAuth Java client library it doesn't work.
I don't get what I'm doing wrong.
Solution: Follow the tutorial in the link provided by #Arkanon, I missed refreshing the signer token secrete through:
signer.tokenSharedSecret

I just modified the code on this page about using google-oauth-java-client to send a request to Twitter and it worked fine once I replaced the relevant block with this:
while (currentLine.equalsIgnoreCase("n")) {
System.out.println("Enter the verification PIN provided by Twitter:");
currentLine = in.readLine();
}
and then added the following to the accessToken object:
accessToken.verifier = currentLine;
Once the PIN provided by the Twitter site is typed into the Java console and you hit Enter, the process completes and the protected resource can be accessed and the desired JSON response is received.
The only other changes I made to that code were to provide the Twitter constants as follows:
private static final String CONSUMER_KEY =
"enter-your-consumer-key-here";
private static final String CONSUMER_SECRET =
"enter-your-consumer-secret-here";
private static final String PROTECTED_SERVICE_URL =
"https://api.twitter.com/1.1/statuses/home_timeline.json";
private static final String REQUEST_TOKEN_URL =
"https://api.twitter.com/oauth/request_token";
private static final String AUTHORIZE_URL =
"https://api.twitter.com/oauth/authenticate";
private static final String ACCESS_TOKEN_URL =
"https://api.twitter.com/oauth/access_token";
Maybe this is not the exact same process you're hoping to achieve, but hopefully the code on that page will help you to spot anything you might have misunderstood. (And I agree that the documentation for the Google libraries is not all it could be.)

Related

Format of private blob storage url, for GET file. Rest API

Microsoft states that getting a Blob is just a normal http get https://myaccount.blob.core.windows.net/mycontainer/myblob. But how do I format the string when I have an account + shared key?
I know there is an Azure SDK, but i'm creating an "add-on" to an existing java ee system, and cannot run in Azure, so I'm using REST Api. This is what i've tried so far:
String account = "myaccount";
String key = "243fedfsdf23f4f";
String protocol = "http";
String storageConnectionString = String.format("DefaultEndpointsProtocol=%s;AccountName=%s;AccountKey=%s", protocol, account, key);
System.out.println(storageConnectionString);
URL url = new URL("https://mysite.azureweb.com/myfile.txt");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn.getResponseCode() != 200) {
throw new IOException(conn.getResponseMessage());
}
// Buffer the result into a string
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
conn.disconnect();
The string probably needs some Base64 encoding?
Update
The Http request looks like GET https://myAccount.blob.core.windows.net/myDir/myfile.txt HTTP/1.1
x-ms-date: Thu, 01 Oct 2015 12:56:11 GMT
x-ms-version: 2015-02-21
Authorization: SharedKey myAccount:asdfkjsladjfsdf827fhwf298f924f92723dfh23f273f2h7h4f
Host: myAccount.blob.core.windows.net
I "just" need to package this into a request to get a file in /mydir/myfile.txt
There are two access types for Azure Storage. One via Shared Keys and other other one via Shared Access Signatures.
Shared Keys give access to the whole storage account. Per storage account you have two shared keys and they are both equal. Usually you never give your shared keys away. Typically you only use them on the server side not in apps on the client side.
You only want to give someone access to a single file. Therefor using shared keys would be the wrong solution.
Shared Access Signatures give you the possibility to create a (REST) request, that is limited to certain files or containers. You can choose the privileges like write, read, delete etc. And you define a timeframe where the access is valid. For Shared Access Signatures you have two options: a) ad-hoc and b) policy-based. Ad-hoc Shared Access Signatures cannot be easily revoked (you could delete the file or invalidate the shared key which you used to create the Shared Access Signature). Policy-based Shared Access Signatures can easily be revoked by deleting the policy.
If you do not want to use the Azure SDK, you can create your own Shared Access Signatures. How to construct them is explained in the following link:
Constructing a Service SAS
There are also samples.
Service SAS Examples
Your file is stored in a BLOB. So you have to use the service BLOB. On the samples page you find the following BLOB sample.
signedstart=2013-08-16
signedexpiry=2013-08-17
signedresource=c
signedpermissions=r
signature=dD80ihBh5jfNpymO5Hg1IdiJIEvHcJpCMiCMnN/RnbI=
signedidentifier=YWJjZGVmZw==
signedversion=2013-08-15
responsecontent-disposition=file; attachment
responsecontent-type=binary
StringToSign = r + \n
2013-08-16 + \n
2013-08-17 + \n
/myaccount/pictures + \n
YWJjZGVmZw== + \n
2013-08-15 + \n
+ \n
file; attachment + \n
+ \n
+ \n
binary
HMAC-SHA256(URL.Decode(UTF8.Encode(StringToSign))) = a39+YozJhGp6miujGymjRpN8tsrQfLo9Z3i8IRyIpnQ=
Finally you get a URL for your REST request.
GET https://myaccount.blob.core.windows.net/pictures/profile.jpg?sv=2013-08-15&st=2013-08-16&se=2013-08-17&sr=c&sp=r&rscd=file;%20attachment&rsct=binary &sig=YWJjZGVmZw%3d%3d&sig=a39%2BYozJhGp6miujGymjRpN8tsrQfLo9Z3i8IRyIpnQ%3d HTTP/1.1
Have a look on the two pages for the full explanation.
There is a simple way to generate the SAS for getting files in the private container by using the Azure Storage SDK.
Following the sample code below to generat the SAS key and format the URL:
String accountName = "<your_account_name>";
String accountKey = "<your_account_key>";
String containerName = "<your_private_container_name>";
String blobFileName = "<your_blob_file_name>";
String storageConnectionString = String.format("DefaultEndpointsProtocol=%s;AccountName=%s;AccountKey=%s", "https", accountName, accountKey);
CloudStorageAccount account = CloudStorageAccount.parse(storageConnectionString);
CloudBlobClient blobClient = account.createCloudBlobClient();
CloudBlobContainer container = blobClient.getContainerReference(containerName);
CloudBlockBlob blob = container.getBlockBlobReference(blobFileName);
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.setTime(new Date());
policy.setSharedAccessStartTime(calendar.getTime());
calendar.add(Calendar.HOUR, 1);
policy.setSharedAccessExpiryTime(calendar.getTime());
policy.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ));
String sas = blob.generateSharedAccessSignature(policy, null);
System.out.println(sas)
String urlstr = String.format("https://%s.blob.core.windows.net/%s/%s?%s", accountName, containerName, blobFileName, sas);
System.out.println(urlstr);
For details, you can refer to the doc https://msdn.microsoft.com/en-us/library/hh875756.aspx.

prevent redirect on result

Is it possible to prevent or stop the redirect in the answer retrieved from an OAuthRequest.send()? Would I use OAuthRequest.addHeader(), and if so, what key and value should I use?
Here is the google groups answer to the question for the problem that I'm having: answer.
Thanks
final OAuthService service =
new ServiceBuilder().provider(TumblrApi.class)
.apiKey(Tumblr.CONSUMER_KEY).apiSecret(Tumblr.CONSUMER_SECRET)
.debug().build();
// Step 5
final OAuthRequest request = new OAuthRequest(Verb.GET, methodUrl);
request.addQuerystringParameter("api_key", Tumblr.CONSUMER_KEY);
service.signRequest(accessToken, request); // the access token from step 4
final Response response = request.send();

post message on twitter wall using java

i was create twitter API key, secret key, access token, access token secret key... then i was tried to post simple text on twitter wall by using java... i was used twitter4j API for this... But its not working properly.. i got this error when i run my program.. "** 401:Authentication credentials (https://dev.twitter.com/pages/auth) were missing or incorrect. Ensure that you have set valid consumer key/secret, access token/secret, and the system clock is in sync.**"....and my code is..
static String consumerKeyStr = "";
static String consumerSecretStr = "";
static String accessTokenStr = "";
static String accessTokenSecretStr = "";
public String postSomething() throws Exception
{
Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerKeyStr, consumerSecretStr);
AccessToken accessToken = new AccessToken(accessTokenStr,
accessTokenSecretStr);
twitter.setOAuthAccessToken(accessToken);
twitter.updateStatus("Post using Twitter4J Again");
System.out.println("Successfully updated the status in Twitter.");
return "success";
}

I am not able to get signature from java sever side(java servlet)

I take the signature on the server side(java servlet) to pass it to the html client.
This is the code:
Cloudinary cloudinary = new Cloudinary(Cloudinary.asMap("cloud_name", "dvg8fiorp", "api_key", "742866863611915", "api_secret", "zF-GJqVyWjih_MqQGsYeSOVVmJ8"));
String timestamp = (new Long(System.currentTimeMillis() / 1000L)).toString();
Map<String, Object> params = new HashMap<String, Object>();
Map options = Cloudinary.emptyMap();
boolean returnError = Cloudinary.asBoolean(options.get("return_error"), false);
String apiKey = Cloudinary.asString(options.get("api_key"), cloudinary.getStringConfig("api_key"));
if (apiKey == null)
throw new IllegalArgumentException("Must supply api_key");
String apiSecret = Cloudinary.asString(options.get("api_secret"), cloudinary.getStringConfig("api_secret"));
if (apiSecret == null)
throw new IllegalArgumentException("Must supply api_secret");
params.put("callback", "http://localhost:8080/SimpleServlet/js/cloudinary_js/html/cloudinary_cors.html");
params.put("timestamp", timestamp);
String expected_signature = cloudinary.apiSignRequest(params, apiSecret);
Unfortunately, the last line of code fail and i don't know how get signature to pass it to html client
First, note that your API Secret Should not be publicly revealed. I strongly advise that you generate a new pair or API key and secret from your Security settings page (https://cloudinary.com/console/settings/security).
Second, this actually generated the correct signature, I managed to have successful uploads with it.
In order to further understand the issue:
What kind of an error response did you get?
Please share your upload request code.
This is the server's response:
java.lang.NoSuchMethodError: org.apache.commons.lang.StringUtils.join(Ljava/util/Collection;Ljava/lang/String;)Ljava/lang/String;
com.cloudinary.Cloudinary.apiSignRequest(Cloudinary.java:93)
us.souther.simple.UploadServersideServlet

Twitter API status update always returns "Incorrect signature"

I'm using Signpost as OAuth implementation for posting to Twitter. And implemented the GoogleAppEngineOAuthConsumer and GoogleAppEngineOAuthProvider classes, but since they're pretty trivial, so I'm not providing their sources here (yet).
Here's my authentication part, which seems to work just fine.
LoginServlet.java:
// fetching the request token
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
OAuthProvider provider = new GoogleAppEngineOAuthProvider(REQUEST_TOKEN_URL, ACCESS_TOKEN_URL, AUTHORIZATION_URL);
String redirectUrl = provider.retrieveRequestToken(consumer, CALLBACK_URL);
// cache the request token and request token secret
response.sendRedirect(redirectUrl);
CallbackServlet.java
// fetching the access token
String verifier = (String) req.getParameter("oauth_verifier");
// retrieve request token and request token secret from cache
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
OAuthProvider provider = new GoogleAppEngineOAuthProvider(REQUEST_TOKEN_URL,
consumer.setTokenWithSecret(token, tokenSecret);
provider.setOAuth10a(true);
provider.retrieveAccessToken(consumer, verifier);
// store access token and access token secret
And here's the actual problematic part.
TweetServlet.java
OAuthConsumer consumer = new GoogleAppEngineOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
// retrieve access token and access token secret from storage
consumer.setTokenWithSecret(accessToken, accessTokenSecret);
final HTTPRequest updateStatus = new HTTPRequest(new URL("http://api.twitter.com/1/statuses/update.json"), HTTPMethod.POST);
updateStatus.setPayload(("status=" + URLEncoder.encode(message, "UTF-8")).getBytes());
consumer.sign(updateStatus);
logger.debug(new String(URLFetchServiceFactory.getURLFetchService().fetch(updateStatus).getContent()));
Each and every time it results: {"request":"/1/statuses/update.json","error":"Incorrect signature"}.
I was able to solve this by myself. The problem was that I wasn't setting a Content-Type header to the request, so the signing didn't sign the parameters and it resulted the invalid signature. Once I set it to application/x-www-form-urlencoded it started working.
final HTTPRequest updateStatus = new HTTPRequest(new URL("http://api.twitter.com/1/statuses/update.json"), HTTPMethod.POST);
updateStatus.addHeader(new HTTPHeader("Content-Type", "application/x-www-form-urlencoded"));

Categories

Resources