How to get an OAuth Request Token for Google using java
Asked Answered
V

2

2

I'm struggling to fetch a request token from google when trying to access the APIs. I'm receiving the standard 400 response. The request i'm sending is almost identical to that generated in the OAuth playground they provide.

I'm using the anonymous secret/key and have constructed a base string as follows :

GET&https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthGetRequestToken&oauth_callback%3Dhttp%253A%252F%252Fgooglecodesamples.com%252Foauth_playground%252Findex.php%26oauth_consumer_key%3Danonymous%26oauth_nonce%3D61dddc084c4e8adfa13d1509161939b0%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1302853379%26oauth_version%3D1.0%26scope%3Dhttps%253A%252F%252Fwww.google.com%252Fcalendar%252Ffeeds%252F

To debug the request being sent I setup TCP/IP monitoring in eclipse. However this only monitors Http traffic so the follwing is a 99% reflection of what is being requested.

GET /accounts/OAuthGetRequestToken?scope=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F HTTP/1.1
Authorization: OAuth oauth_callback="http%3A%2F%2Fgooglecodesamples.com%2Foauth_playground%2Findex.php", oauth_consumer_key="anonymous", oauth_nonce="8cc04c7633db041dd0fd8e5fd0eb728e", oauth_signature="epRa5IZOA6s%2B3qhZa%2FUxuwYKnJA%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1302790583", oauth_version="1.0"
Accept: */*
User-Agent: Java/1.6.0_24
Host: localhost
Connection: keep-alive

Can you tell me what I'm doing wrong? Thanks in advance.

Below is the the only code i'm using for this.

package com.pdw.gb;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.google.gdata.util.common.util.Base64;

public class OAuthTest3 {

public static String read(String url) 
{
    StringBuffer buffer = new StringBuffer();
    try 
    {

        String[][] data = { 
                { "oauth_callback", URLEncoder.encode("http://googlecodesamples.com/oauth_playground/index.php","UTF-8") },
                { "oauth_consumer_key", "anonymous" },
                { "oauth_nonce", a64BitRandomString() },
                { "oauth_signature_method", "HMAC-SHA1" },
                { "oauth_timestamp", timeSinceEpochInMillis() },
                { "oauth_signature", "" },
                { "oauth_version", "1.0" },
                { "scope", URLEncoder.encode("https://www.google.com/calendar/feeds/","UTF-8") }
        };


        /**
         * Generation of the signature base string
         */
        String signature_base_string = "GET&"
                + URLEncoder.encode(url, "UTF-8") + "&";
        for (int i = 0; i < data.length; i++) 
        {
            // ignore the empty oauth_signature field
            if (i != 5) 
            {
                System.out.print(i);
                signature_base_string += URLEncoder.encode(data[i][0],
                        "UTF-8")
                        + "%3D"
                        + URLEncoder.encode(data[i][1], "UTF-8") + "%26";
            }
        }
        // cut the last appended %26
        signature_base_string = signature_base_string.substring(0,
                signature_base_string.length() - 3);

        /**
         * Sign the request
         */
        Mac m = Mac.getInstance("HmacSHA1");
        m.init(new SecretKeySpec("anonymous".getBytes(), "HmacSHA1"));
        m.update(signature_base_string.getBytes());
        byte[] res = m.doFinal();


        String sig = URLEncoder.encode(String.valueOf(Base64.encode(res)),"UTF8");
        data[5][1] = sig;

        /**
         * Create the header for the request
         */
        String header = "OAuth ";
        int i=0;
        for (String[] item : data) 
        {
            if (i!=7)
            {
                header += item[0] + "=\"" + item[1] + "\", ";
            }
            i++;
        }

        // cut off last appended comma
        header = header.substring(0, header.length() - 2);

        System.out.println("Signature Base String: "
                + signature_base_string);
        System.out.println("Authorization Header: " + header);
        System.out.println("Signature: " + sig);

        String charset = "UTF-8";
        URLConnection connection = new URL(url+"?scope="+URLEncoder.encode("https://www.google.com/calendar/feeds/", "UTF-8")).openConnection();
        connection.setRequestProperty("Authorization", header);
        connection.setRequestProperty("Accept", "*/*");


        BufferedReader reader = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));

        String read;
        while ((read = reader.readLine()) != null) 
        {
            buffer.append(read);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return buffer.toString();
}

public static void main(String[] args) 
{
    boolean debug=false;
    if (!debug)
    {
        System.out.println(OAuthTest3
            .read("https://www.google.com/accounts/OAuthGetRequestToken"));
    }
    else
    {
            System.out.println(OAuthTest3
                    .read("http://localhost/accounts/OAuthGetRequestToken"));
    }
}

private static String a64BitRandomString() {
    StringBuffer sb = new StringBuffer();
    Random generator = new Random();

    for (int i = 0; i < 32; i++) {
        Integer r = generator.nextInt();
        if (r < 0) {
            r = r * -1;
        }
        r = r % 16;

        sb.append(r.toHexString(r));
    }

    return sb.toString();
}

private static String timeSinceEpochInMillis() {
    Calendar c = Calendar.getInstance();
    Date date = c.getTime();
    Long time = date.getTime();
    Integer i = (int) (time/1000);
    return i.toString();
}
}
Vitalism answered 15/4, 2011 at 8:22 Comment(0)
T
2

It should be m.init(new SecretKeySpec("anonymous&".getBytes(), "HmacSHA1")); When the oauth_token_secret is empty, you still need the "&" joining the two secrets to make the complete signature key.

Tirewoman answered 17/4, 2011 at 3:59 Comment(2)
It worked! Thanks so much. So is this only when doing anonymous auth?Vitalism
no, it's used in all cases when using HMAC-SHA1 as the signing protocol.Tirewoman
O
1

I would suggest using an OAuth library for this, in order to have a higher level of abstraction.

Checkout the following blog post for an OAuth interaction using Signpost and j2se :

http://blog.doityourselfandroid.com/2010/11/08/oauth-in-java-the-signpost-library/

The blog also contains some other info regarding OAuth.

Another important thing worth mentioning is to make sure your date/time settings are setup correctly on the client. When you interact with the service provider, and you end up sending wrong timestamps, your requests will get refused.

Orthopsychiatry answered 15/4, 2011 at 8:47 Comment(1)
Thanks for the answer, I would have accepted this if I'd had time over the weekend to try it out, no doubt it would have worked. However I was intent on doing it the hard way for more transparency and a better understanding of the proccess.Vitalism

© 2022 - 2024 — McMap. All rights reserved.