views:

2876

answers:

6

How can I specify the username and password for making Basic-Auth requests with App Engine's URLFetch service (in Java)?

It seems I can set HTTP headers:

URL url = new URL("http://www.example.com/comment");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("X-MyApp-Version", "2.7.3");

What are the appropriate headers for Basic-Auth?

+4  A: 

You set up an Authenticator before you call openConnection() like this,

Authenticator.setDefault(new Authenticator() {
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(username, password.toCharArray());
    }
});

Since there is only one global default authenticator, this doesn't really work well when you have multiple users doing the URLFetch in multiple threads. I would use Apache HttpClient if that's the case.

EDIT: I was wrong. App Engine doesn't allow Authenticator. Even if it's allowed, we would have the multi-thread issue with a global authenticator instance. Even though you can't create threads, your requests may still get served in different threads. So we just add the header manually using this function,

import com.google.appengine.repackaged.com.google.common.util.Base64;
    /**
     * Preemptively set the Authorization header to use Basic Auth.
     * @param connection The HTTP connection
     * @param username Username
     * @param password Password
     */
    public static void setBasicAuth(HttpURLConnection connection,
      String username, String password) {
     StringBuilder buf = new StringBuilder(username);
     buf.append(':');
     buf.append(password);
     byte[] bytes = null;
     try {
      bytes = buf.toString().getBytes("ISO-8859-1");
     } catch (java.io.UnsupportedEncodingException uee) {
      assert false;
     }

        String header = "Basic " + Base64.encode(bytes);
     connection.setRequestProperty("Authorization", header);
    }
ZZ Coder
There is only a single thread on App Engine ... (by the way, is there any documentation that this is guaranteed to be the case?)
Thilo
We had some problem with this, I thought it was threading. I will check with the person who implemented this when I get back to office next week.
ZZ Coder
Just talked with the guy who ported our app to Google. See my edits.
ZZ Coder
+1  A: 

There is a wrapper on Apache HttpClient for App Engine

please go through the post http://esxx.blogspot.com/2009/06/using-apaches-httpclient-on-google-app.html

http://peterkenji.blogspot.com/2009/08/using-apache-httpclient-4-with-google.html

Rahul Garg
Hope this helps you :)
Rahul Garg
You are my hero. Thank you!
Adrian Petrescu
+10  A: 

This is a basic auth header over http:

Authorization: Basic base64 encoded(username:password)

eg:

GET /private/index.html HTTP/1.0
Host: myhost.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

You will need to do this:

URL url = new URL("http://www.example.com/comment");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization",
"Basic "+codec.encodeBase64String(("username:password").getBytes());

And to do that you will want to get a base64 codec api, like the Apache Commons Codec

Zombies
This is what I ended up doing. And since I put username:password as a property in appengine-web.xml, I just put the encoded version directly in there, so I do not even need a codec. (You can use the openssl commandline: echo -n "username:password" | openssl enc -base64 )
Thilo
+1 this also solved a problem I was about to have with HTTP Authentication. Thanks. Oh, and getBytes() needs another ) to close setRequestProperty.
Chris Kaminski
+1  A: 

Note on the first answer: setRequestProperty should get the property name without the colon ("Authorization" rather than "Authorization:").

Boaz S
Nice catch, I edited the answer.
Luke Francl
A: 

very useful information

Nanaji
+2  A: 

For those interested in doing this in Python (as I was), the code looks like this:

result = urlfetch.fetch("http://www.example.com/comment",
                        headers={"Authorization": 
                                 "Basic %s" % base64.encode("username:pass")})
Luke Francl
I believe the code should be as follows:result = urlfetch.fetch( "http://yourserver.com/page/init.php, headers = { "Authorization": "Basic %s" % base64.encodestring("username:password")[:-1]});
mbmccormick