Permalink
Browse files

add basic authentication for require_valid_user=true users.

  • Loading branch information...
1 parent 4bda2d7 commit 378e3224dbccddc6644228130945c35d96ba4ce9 Robert Newson committed Jul 14, 2010
View
@@ -562,3 +562,21 @@ If you recreate databases or frequently change your fulltext functions, you will
<pre>
curl -X POST http://localhost:5984/&lt;db>/_fti/_cleanup
</pre>
+
+<h1>Authentication</h1>
+
+By default couchdb-lucene does not attempt to authenticate to CouchDB. If you have set CouchDB's require_valid_user to true, you will need to modify couchdb-lucene.ini. Change the url setting to include a valid username and password. e.g, the default setting is;
+
+<pre>
+[local]
+url=http://localhost:5984/
+</pre>
+
+Change it to;
+
+<pre>
+[local]
+url=http://foo:bar@localhost:5984/
+</pre>
+
+and couchdb-lucene will authenticate to couchdb.
@@ -16,10 +16,25 @@
* limitations under the License.
*/
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Iterator;
import java.util.concurrent.TimeUnit;
+import org.apache.commons.configuration.HierarchicalINIConfiguration;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpVersion;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
@@ -29,12 +44,16 @@
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
/**
* HttpClient instances just the way we like them.
@@ -44,6 +63,33 @@
*/
public final class HttpClientFactory {
+ private static final class PreemptiveAuthenticationRequestInterceptor
+ implements HttpRequestInterceptor {
+
+ public void process(final HttpRequest request, final HttpContext context)
+ throws HttpException, IOException {
+
+ final AuthState authState = (AuthState) context
+ .getAttribute(ClientContext.TARGET_AUTH_STATE);
+ final CredentialsProvider credsProvider = (CredentialsProvider) context
+ .getAttribute(ClientContext.CREDS_PROVIDER);
+ final HttpHost targetHost = (HttpHost) context
+ .getAttribute(ExecutionContext.HTTP_TARGET_HOST);
+
+ // If not auth scheme has been initialized yet
+ if (authState.getAuthScheme() == null) {
+ AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
+ // Obtain credentials matching the target host
+ Credentials creds = credsProvider.getCredentials(authScope);
+ // If found, generate BasicScheme preemptively
+ if (creds != null) {
+ authState.setAuthScheme(new BasicScheme());
+ authState.setCredentials(creds);
+ }
+ }
+ }
+ }
+
private static class ShieldedClientConnManager implements ClientConnectionManager {
private final ClientConnectionManager delegate;
@@ -64,7 +110,10 @@ public SchemeRegistry getSchemeRegistry() {
return delegate.getSchemeRegistry();
}
- public void releaseConnection(final ManagedClientConnection conn, final long validDuration, final TimeUnit timeUnit) {
+ public void releaseConnection(
+ final ManagedClientConnection conn,
+ final long validDuration,
+ final TimeUnit timeUnit) {
delegate.releaseConnection(conn, validDuration, timeUnit);
}
@@ -73,15 +122,17 @@ public ClientConnectionRequest requestConnection(final HttpRoute route, final Ob
}
public void shutdown() {
- // SHIELDED.
- // delegate.shutdown();
+ // SHIELDED.
+ // delegate.shutdown();
}
}
- private static HttpClient instance;
+ private static DefaultHttpClient instance;
+
+ private static HierarchicalINIConfiguration INI;
- public static synchronized HttpClient getInstance() {
+ public static synchronized HttpClient getInstance() throws MalformedURLException {
if (instance == null) {
final HttpParams params = new BasicHttpParams();
// protocol params.
@@ -94,13 +145,34 @@ public static synchronized HttpClient getInstance() {
ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(1000));
final SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 5984));
+ schemeRegistry
+ .register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 5984));
final ClientConnectionManager cm = new ShieldedClientConnManager(
new ThreadSafeClientConnManager(params, schemeRegistry));
instance = new DefaultHttpClient(cm, params);
+
+ if (INI != null) {
+ final CredentialsProvider credsProvider = new BasicCredentialsProvider();
+ final Iterator<?> it = INI.getKeys();
+ while (it.hasNext()) {
+ final String key = (String) it.next();
+ if (!key.startsWith("lucene.") && key.endsWith(".url")) {
+ final URL url = new URL(INI.getString(key));
+ credsProvider.setCredentials(
+ new AuthScope(url.getHost(), url.getPort()),
+ new UsernamePasswordCredentials(url.getUserInfo()));
+ }
+ }
+ instance.setCredentialsProvider(credsProvider);
+ instance.addRequestInterceptor(new PreemptiveAuthenticationRequestInterceptor(), 0);
+ }
}
return instance;
}
+ public static void setIni(final HierarchicalINIConfiguration ini) {
+ INI = ini;
+ }
+
}
@@ -20,6 +20,7 @@
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
+import org.apache.http.client.HttpClient;
import org.apache.log4j.Logger;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Handler;
@@ -32,60 +33,60 @@
public class Main {
- private static final Logger LOG = Logger.getLogger(Main.class);
-
- /**
- * Run couchdb-lucene.
- */
- public static void main(String[] args) throws Exception {
- final HierarchicalINIConfiguration configuration = new HierarchicalINIConfiguration(
- Main.class.getClassLoader().getResource("couchdb-lucene.ini"));
- configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
-
- final File dir = new File(configuration.getString("lucene.dir",
- "indexes"));
-
- if (dir == null) {
- LOG.error("lucene.dir not set.");
- System.exit(1);
- }
- if (!dir.exists() && !dir.mkdir()) {
- LOG.error("Could not create " + dir.getCanonicalPath());
- System.exit(1);
- }
- if (!dir.canRead()) {
- LOG.error(dir + " is not readable.");
- System.exit(1);
- }
- if (!dir.canWrite()) {
- LOG.error(dir + " is not writable.");
- System.exit(1);
- }
- LOG.info("Index output goes to: " + dir.getCanonicalPath());
-
- final Server server = new Server();
- final SelectChannelConnector connector = new SelectChannelConnector();
- connector.setHost(configuration.getString("lucene.host", "localhost"));
- connector.setPort(configuration.getInt("lucene.port", 5985));
-
- LOG.info("Accepting connections with " + connector);
-
- server.setConnectors(new Connector[] { connector });
- server.setStopAtShutdown(true);
- server.setSendServerVersion(false);
-
- final LuceneServlet servlet = new LuceneServlet(HttpClientFactory.getInstance(), dir, configuration);
-
- final Context context = new Context(server, "/", Context.NO_SESSIONS
- | Context.NO_SECURITY);
- context.addServlet(new ServletHolder(servlet), "/*");
- context.addFilter(new FilterHolder(new GzipFilter()), "/*",
- Handler.DEFAULT);
- context.setErrorHandler(new JSONErrorHandler());
- server.setHandler(context);
-
- server.start();
- server.join();
- }
+ private static final Logger LOG = Logger.getLogger(Main.class);
+
+ /**
+ * Run couchdb-lucene.
+ */
+ public static void main(String[] args) throws Exception {
+ final HierarchicalINIConfiguration configuration = new HierarchicalINIConfiguration(
+ Main.class.getClassLoader().getResource("couchdb-lucene.ini"));
+ configuration.setReloadingStrategy(new FileChangedReloadingStrategy());
+
+ final File dir = new File(configuration.getString("lucene.dir", "indexes"));
+
+ if (dir == null) {
+ LOG.error("lucene.dir not set.");
+ System.exit(1);
+ }
+ if (!dir.exists() && !dir.mkdir()) {
+ LOG.error("Could not create " + dir.getCanonicalPath());
+ System.exit(1);
+ }
+ if (!dir.canRead()) {
+ LOG.error(dir + " is not readable.");
+ System.exit(1);
+ }
+ if (!dir.canWrite()) {
+ LOG.error(dir + " is not writable.");
+ System.exit(1);
+ }
+ LOG.info("Index output goes to: " + dir.getCanonicalPath());
+
+ final Server server = new Server();
+ final SelectChannelConnector connector = new SelectChannelConnector();
+ connector.setHost(configuration.getString("lucene.host", "localhost"));
+ connector.setPort(configuration.getInt("lucene.port", 5985));
+
+ LOG.info("Accepting connections with " + connector);
+
+ server.setConnectors(new Connector[]{connector});
+ server.setStopAtShutdown(true);
+ server.setSendServerVersion(false);
+
+ HttpClientFactory.setIni(configuration);
+ final HttpClient httpClient = HttpClientFactory.getInstance();
+
+ final LuceneServlet servlet = new LuceneServlet(httpClient, dir, configuration);
+
+ final Context context = new Context(server, "/", Context.NO_SESSIONS | Context.NO_SECURITY);
+ context.addServlet(new ServletHolder(servlet), "/*");
+ context.addFilter(new FilterHolder(new GzipFilter()), "/*", Handler.DEFAULT);
+ context.setErrorHandler(new JSONErrorHandler());
+ server.setHandler(context);
+
+ server.start();
+ server.join();
+ }
}

0 comments on commit 378e322

Please sign in to comment.