27

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?

2
  • 1
    Is this really an App Engine question, then? Just look up the HTTP RFCs to see how to do basic auth (hint - 'Authorization'). Commented Aug 27, 2009 at 15:54
  • 3
    I was hoping that there might be a convenience wrapper for App Engine similar to Apache HttpClient so that I do not have to set (and base64-encode) the Authorization header manually. Commented Aug 27, 2009 at 22:38

6 Answers 6

30
+100

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

Sign up to request clarification or add additional context in comments.

2 Comments

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 )
+1 this also solved a problem I was about to have with HTTP Authentication. Thanks. Oh, and getBytes() needs another ) to close setRequestProperty.
14

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.b64encode("username:pass")})

2 Comments

I believe the code should be as follows: result = urlfetch.fetch( "yourserver.com/page/init.php, headers = { "Authorization": "Basic %s" % base64.encodestring("username:password")[:-1] });
Updated to use base64.b64encode. I know it works because it's what I was actually using in my real code.
6

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);
    }

3 Comments

There is only a single thread on App Engine ... (by the way, is there any documentation that this is guaranteed to be the case?)
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.
Just talked with the guy who ported our app to Google. See my edits.
4

Using HttpURLConnection gave me some problems (for some reason the server I was trying to connect to didn't accept auth credentials), and finally I realized that it's actually much easier to do using GAE's low-level URLFetch API (com.google.appengine.api.urlfetch) like so:

URL fetchurl = new URL(url);

String nameAndPassword = credentials.get("name")+":"+credentials.get("password");
String authorizationString = "Basic " + Base64.encode(nameAndPassword.getBytes());

HTTPRequest request = new HTTPRequest(fetchurl);
request.addHeader(new HTTPHeader("Authorization", authorizationString));

HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(request);
System.out.println(new String(response.getContent()));

This worked.

1 Comment

This should be the accepted answer, you can also set the timeout: FetchOptions fetchOptions = FetchOptions.Builder.withDeadline(10); HTTPRequest req = new HTTPRequest( fetchurl, HTTPMethod.GET, fetchOptions);
3

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

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.