Search code examples
javaandroidauthenticationcouchdbhttp-authentication

Cannot add user to database/_security in CouchDB using HTTP PUT


The problem

In my Android app, I am trying to add a user to the /_security document of my CouchDB database via HTTP PUT. If I am trying to do this by authenticating my admin user using Cookie-authentication or by simply inserting the admin data into the url like in the following, I receive an error.

URL on which the PUT is directed (if not using Cookie-authentication):

http://admin_name:admin_password@url:port/databasename/_security

Error I receive in both cases:

Authentication error: Unable to respond to any of these challenges: {} {"error":"unauthorized","reason":"You are not a db or server admin."}

If I am doing this via command-line using curl, the user is inserted without any problems:

~$ curl -X PUT http://admin:pw@ip:port/databasename/_security -d '{"admins":{"names":[],"roles":[]},"members":{"names":["participant_1"],"roles":[]}}'

> {"ok":true}

My aproach

As soon as I authenticate using the "Authorization" option in one of my HTTP PUT's headers, athentication is no problem anymore.

private boolean putJSONWithAuthentication(String userName, String password, String json, String url) {

    // url = http://url:port/databasename/_security
    // json = {"admins":{"names":[],"roles":[]},"members":{"names":["participant_1"],"roles":[]}}
    HttpClient client = new DefaultHttpClient();
    HttpPut put = new HttpPut(url);

    String authenticationData = userName+":"+password;
    String encoding = Base64.encodeToString(authenticationData.getBytes(Charset.forName("utf-8")), Base64.DEFAULT);

    try {
        StringEntity stringEntity = new StringEntity(json,"utf-8");
        put.setEntity(stringEntity);
        put.setHeader("Content-type", "application/json; charset=utf-8");
        put.setHeader("Accept", "application/json");
        put.setHeader("Authorization", "Basic " + encoding);

        HttpResponse response = client.execute(put);
        BufferedReader rd     = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line = "";
        while ((line = rd.readLine()) != null) {
            System.out.println(line);
        }
        return true;

    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }       
}

However, I am receiving this error:

> {"error":"bad_request","reason":"invalid_json"}

If I am inserting my user-JSON as a usual document using the above method, e.g., to http://url:port/databasename/new_document, the JSON is inserted without any errors. Consequently, I guess the JSON string should be formatted correctly.

Thus, my questions is, what am I missing here? It seems like I cannot authenticate and put data in the request body at once. How do I correctly insert a user to the /_security document of a database from code?


Solution

  • Instead of creating the basic auth header manually, can you try create it using UsernamePasswordCredentials, e.g.

    HttpPut put = new HttpPut(url);
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password);
    put.addHeader( BasicScheme.authenticate(creds,"US-ASCII",false) );
    ...
    HttpResponse response = client.execute(put);