Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Experimental support for Authenticated databases #147

Open
wants to merge 1 commit into from

2 participants

@nnarhinen

This commit reads authorization info from the Servlet Request by parsing the
Authorization-header. The authorization information is then passed along to
Database to be used in indexing requests from database

This PR tries to solve issue #79

@nnarhinen nnarhinen Experimental support for Authenticated databases
This commit reads authorization info from the Servlet Request by parsing the
Authorization-header. The authorization information is then passed along to
Database to be used in indexing requests from database
14bc126
@rnewson
Owner

I think this is the wrong approach. I've sketched what I think it ought to look like here (http://friendpaste.com/1J8edQNtYJWeJpIa2hxoaV). Specifically, we teach Jetty that it needs to authenticate to couchdb. I haven't completed the CouchDBUserRealm class yet. The authenticate method would call /_session or something.

Perhaps even that is wrong, though. It would be simple to set up separate authentication for couchdb-lucene and this seems easier to reason about security issues. I find it difficult to be happy about proxying usernames and passwords back and forth like this.

@rnewson
Owner

sidenote: couchdb-lucene should be packaged as a proper WAR file, and then authenticate to it goes into web.xml, where it belongs, and becomes the deployers decision on how to secure it. If c-l also ships with a module that allows authentication against couchdb itself, then that just gives more options without forcing anyone's hand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 20, 2011
  1. @nnarhinen

    Experimental support for Authenticated databases

    nnarhinen authored
    This commit reads authorization info from the Servlet Request by parsing the
    Authorization-header. The authorization information is then passed along to
    Database to be used in indexing requests from database
This page is out of date. Refresh to see the latest.
View
28 src/main/java/com/github/rnewson/couchdb/lucene/AuthorizationInfo.java
@@ -0,0 +1,28 @@
+package com.github.rnewson.couchdb.lucene;
+
+import java.io.IOException;
+
+public class AuthorizationInfo {
+
+ private String user;
+ private String password;
+
+ public AuthorizationInfo(String auth) throws IOException {
+ if (auth.toUpperCase().startsWith("BASIC ")) { //Basic auth
+ String userpassEncoded = auth.substring(6);
+ sun.misc.BASE64Decoder dec = new sun.misc.BASE64Decoder();
+ String userpassDecoded = new String(dec.decodeBuffer(userpassEncoded));
+ String[] parts = userpassDecoded.split(":");
+ user = parts[0];
+ password = parts[1];
+ }
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+}
View
16 src/main/java/com/github/rnewson/couchdb/lucene/LuceneServlet.java
@@ -36,6 +36,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.HttpClient;
+import org.apache.http.client.HttpResponseException;
import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
@@ -153,8 +154,12 @@ private synchronized DatabaseIndexer getIndexer(final Database database)
private DatabaseIndexer getIndexer(final HttpServletRequest req)
throws IOException, JSONException {
final Couch couch = getCouch(req);
- final Database database = couch.getDatabase(new PathParts(req)
- .getDatabaseName());
+ final Database database = couch.getDatabase(new PathParts(req).getDatabaseName());
+ if (req.getHeader("Authorization") != null) {
+ AuthorizationInfo authInfo = new AuthorizationInfo(req.getHeader("Authorization"));
+ database.setUser(authInfo.getUser());
+ database.setPassword(authInfo.getPassword());
+ }
return getIndexer(database);
}
@@ -174,6 +179,13 @@ protected void doGet(final HttpServletRequest req,
IOException {
try {
doGetInternal(req, resp);
+ } catch (HttpResponseException e) {
+ if (e.getStatusCode() == 401) {
+ resp.sendError(e.getStatusCode(), e.getMessage());
+ }
+ else {
+ throw e;
+ }
} catch (final JSONException e) {
resp.sendError(500);
}
View
29 src/main/java/com/github/rnewson/couchdb/lucene/couchdb/Database.java
@@ -39,12 +39,31 @@
private final HttpClient httpClient;
private final String url;
+
+ private String user;
+ private String password;
public Database(final HttpClient httpClient, final String url) {
this.httpClient = httpClient;
this.url = url.endsWith("/") ? url : url + "/";
}
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
public boolean create() throws IOException {
return HttpUtils.put(httpClient, url, null) == 201;
}
@@ -57,20 +76,20 @@ public boolean delete() throws IOException {
final String body = HttpUtils.get(httpClient, String
.format("%s_all_docs?startkey=%s&endkey=%s&include_docs=true",
url, Utils.urlEncode("\"_design\""), Utils
- .urlEncode("\"_design0\"")));
+ .urlEncode("\"_design0\"")), user, password);
final JSONObject json = new JSONObject(body);
return toDesignDocuments(json);
}
public CouchDocument getDocument(final String id) throws IOException, JSONException {
final String response = HttpUtils.get(httpClient, url
- + Utils.urlEncode(id));
+ + Utils.urlEncode(id), user, password);
return new CouchDocument(new JSONObject(response));
}
public DesignDocument getDesignDocument(final String id) throws IOException, JSONException {
final String response = HttpUtils.get(httpClient, url
- + Utils.urlEncode(id));
+ + Utils.urlEncode(id), user, password);
return new DesignDocument(new JSONObject(response));
}
@@ -95,7 +114,7 @@ public DesignDocument getDesignDocument(final String id) throws IOException, JSO
public DatabaseInfo getInfo() throws IOException, JSONException {
return new DatabaseInfo(new JSONObject(HttpUtils.get(httpClient,
- url)));
+ url, user, password)));
}
public <T> T handleAttachment(final String doc, final String att,
@@ -108,7 +127,7 @@ public DatabaseInfo getInfo() throws IOException, JSONException {
public HttpUriRequest getChangesRequest(final UpdateSequence since)
throws IOException {
final String uri = url + "_changes?feed=continuous&heartbeat=15000&include_docs=true";
- return new HttpGet(since.appendSince(uri));
+ return HttpUtils.getHttpGetRequest(since.appendSince(uri), user, password);
}
public boolean saveDocument(final String id, final String body)
View
18 src/main/java/com/github/rnewson/couchdb/lucene/couchdb/HttpUtils.java
@@ -40,9 +40,23 @@ public static final int delete(final HttpClient httpClient, final String url) th
public static final String execute(final HttpClient httpClient, final HttpUriRequest request) throws IOException {
return httpClient.execute(request, new ErrorPreservingResponseHandler());
}
-
+
public static final String get(final HttpClient httpClient, final String url) throws IOException {
- return execute(httpClient, new HttpGet(url));
+ return get(httpClient, url, null, null);
+ }
+
+ public static final String get(final HttpClient httpClient, final String url, final String user, final String password) throws IOException {
+ return execute(httpClient, getHttpGetRequest(url, user, password));
+ }
+
+ public static final HttpGet getHttpGetRequest(final String url, final String user, final String password) {
+ HttpGet get = new HttpGet(url);
+ if (user != null && password != null) {
+ sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
+ String userInfo = user + ":" + password;
+ get.addHeader("Authorization", "Basic " + encoder.encode(userInfo.getBytes()));
+ }
+ return get;
}
public static final String post(final HttpClient httpClient, final String url, final JSONObject body) throws IOException {
Something went wrong with that request. Please try again.