Merge changes I8596041e,I373db466
* changes: Extract a minimal interface for contactstore connections Initialize BouncyCastleProvider when checking for PGP.
This commit is contained in:
@@ -34,6 +34,7 @@ import com.google.gerrit.server.config.CanonicalWebUrlModule;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrlProvider;
|
||||
import com.google.gerrit.server.config.GerritGlobalModule;
|
||||
import com.google.gerrit.server.config.MasterNodeStartup;
|
||||
import com.google.gerrit.server.contact.HttpContactStoreConnection;
|
||||
import com.google.gerrit.server.git.PushReplication;
|
||||
import com.google.gerrit.server.git.WorkQueue;
|
||||
import com.google.gerrit.server.mail.SmtpEmailSender;
|
||||
@@ -253,6 +254,7 @@ public class Daemon extends SiteProgram {
|
||||
modules.add(sysInjector.getInstance(GitOverHttpModule.class));
|
||||
modules.add(sshInjector.getInstance(WebSshGlueModule.class));
|
||||
modules.add(CacheBasedWebSession.module());
|
||||
modules.add(HttpContactStoreConnection.module());
|
||||
if (sshd) {
|
||||
modules.add(sshInjector.getInstance(ProjectQoSFilter.Module.class));
|
||||
}
|
||||
|
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2011 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.contact;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/** Single connection to a {@link ContactStore}. */
|
||||
public interface ContactStoreConnection {
|
||||
public static interface Factory {
|
||||
/**
|
||||
* Open a new connection to a {@link ContactStore}.
|
||||
*
|
||||
* @param url contact store URL.
|
||||
* @return a new connection to the store.
|
||||
*
|
||||
* @throws IOException the URL couldn't be opened.
|
||||
*/
|
||||
ContactStoreConnection open(URL url) throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a blob of contact data in the store.
|
||||
*
|
||||
* @param body protocol-specific body data.
|
||||
*
|
||||
* @throws IOException an error occurred storing the contact data.
|
||||
*/
|
||||
public void store(byte[] body) throws IOException;
|
||||
}
|
@@ -22,25 +22,30 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.ProvisionException;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.Security;
|
||||
|
||||
/** Creates the {@link ContactStore} based on the configuration. */
|
||||
public class ContactStoreProvider implements Provider<ContactStore> {
|
||||
private final Config config;
|
||||
private final SitePaths site;
|
||||
private final SchemaFactory<ReviewDb> schema;
|
||||
private final ContactStoreConnection.Factory connFactory;
|
||||
|
||||
@Inject
|
||||
ContactStoreProvider(@GerritServerConfig final Config config,
|
||||
final SitePaths site, final SchemaFactory<ReviewDb> schema) {
|
||||
final SitePaths site, final SchemaFactory<ReviewDb> schema,
|
||||
final ContactStoreConnection.Factory connFactory) {
|
||||
this.config = config;
|
||||
this.site = site;
|
||||
this.schema = schema;
|
||||
this.connFactory = connFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,12 +73,14 @@ public class ContactStoreProvider implements Provider<ContactStore> {
|
||||
throw new ProvisionException("PGP public key file \""
|
||||
+ pubkey.getAbsolutePath() + "\" not found");
|
||||
}
|
||||
return new EncryptedContactStore(storeUrl, storeAPPSEC, pubkey, schema);
|
||||
return new EncryptedContactStore(storeUrl, storeAPPSEC, pubkey, schema,
|
||||
connFactory);
|
||||
}
|
||||
|
||||
private static boolean havePGP() {
|
||||
try {
|
||||
Class.forName(PGPPublicKey.class.getName());
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
return true;
|
||||
} catch (NoClassDefFoundError noBouncyCastle) {
|
||||
return false;
|
||||
|
@@ -37,7 +37,6 @@ import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
import org.eclipse.jgit.util.IO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -47,7 +46,6 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
@@ -70,13 +68,16 @@ class EncryptedContactStore implements ContactStore {
|
||||
private final SecureRandom prng;
|
||||
private final URL storeUrl;
|
||||
private final String storeAPPSEC;
|
||||
private final ContactStoreConnection.Factory connFactory;
|
||||
|
||||
EncryptedContactStore(final URL storeUrl, final String storeAPPSEC,
|
||||
final File pubKey, final SchemaFactory<ReviewDb> schema) {
|
||||
final File pubKey, final SchemaFactory<ReviewDb> schema,
|
||||
final ContactStoreConnection.Factory connFactory) {
|
||||
this.storeUrl = storeUrl;
|
||||
this.storeAPPSEC = storeAPPSEC;
|
||||
this.schema = schema;
|
||||
this.dest = selectKey(readPubRing(pubKey));
|
||||
this.connFactory = connFactory;
|
||||
|
||||
final String prngName = "SHA1PRNG";
|
||||
try {
|
||||
@@ -157,33 +158,7 @@ class EncryptedContactStore implements ContactStore {
|
||||
}
|
||||
u.put("account_id", String.valueOf(account.getId().get()));
|
||||
u.put("data", encStr);
|
||||
final byte[] body = u.toString().getBytes("UTF-8");
|
||||
|
||||
final HttpURLConnection c = (HttpURLConnection) storeUrl.openConnection();
|
||||
c.setRequestMethod("POST");
|
||||
c.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded; charset=UTF-8");
|
||||
c.setDoOutput(true);
|
||||
c.setFixedLengthStreamingMode(body.length);
|
||||
final OutputStream out = c.getOutputStream();
|
||||
out.write(body);
|
||||
out.close();
|
||||
|
||||
if (c.getResponseCode() == 200) {
|
||||
final byte[] dst = new byte[2];
|
||||
final InputStream in = c.getInputStream();
|
||||
try {
|
||||
IO.readFully(in, dst, 0, 2);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
if (dst[0] != 'O' || dst[1] != 'K') {
|
||||
throw new IOException("Store failed: " + c.getResponseCode());
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Store failed: " + c.getResponseCode());
|
||||
}
|
||||
|
||||
connFactory.open(storeUrl).store(u.toString().getBytes("UTF-8"));
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot store encrypted contact information", e);
|
||||
throw new ContactInformationStoreException(e);
|
||||
|
@@ -0,0 +1,74 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.google.gerrit.server.contact;
|
||||
|
||||
import static com.google.inject.Scopes.SINGLETON;
|
||||
|
||||
import com.google.gerrit.server.contact.ContactStoreConnection;
|
||||
import com.google.gerrit.server.contact.HttpContactStoreConnection;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.FactoryProvider;
|
||||
|
||||
import org.eclipse.jgit.util.IO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/** {@link ContactStoreConnection} with an underlying {@HttpURLConnection}. */
|
||||
public class HttpContactStoreConnection implements ContactStoreConnection {
|
||||
public static Module module() {
|
||||
return new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ContactStoreConnection.Factory.class)
|
||||
.toProvider(FactoryProvider.newFactory(
|
||||
ContactStoreConnection.Factory.class,
|
||||
HttpContactStoreConnection.class))
|
||||
.in(SINGLETON);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final HttpURLConnection conn;
|
||||
|
||||
@Inject
|
||||
HttpContactStoreConnection(@Assisted final URL url) throws IOException {
|
||||
final URLConnection urlConn = url.openConnection();
|
||||
if (!(urlConn instanceof HttpURLConnection)) {
|
||||
throw new IllegalArgumentException("Non-HTTP URL not supported: " + urlConn);
|
||||
}
|
||||
conn = (HttpURLConnection) urlConn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(final byte[] body) throws IOException {
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type",
|
||||
"application/x-www-form-urlencoded; charset=UTF-8");
|
||||
conn.setDoOutput(true);
|
||||
conn.setFixedLengthStreamingMode(body.length);
|
||||
final OutputStream out = conn.getOutputStream();
|
||||
out.write(body);
|
||||
out.close();
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException("Connection failed: " + conn.getResponseCode());
|
||||
}
|
||||
final byte[] dst = new byte[2];
|
||||
final InputStream in = conn.getInputStream();
|
||||
try {
|
||||
IO.readFully(in, dst, 0, 2);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
if (dst[0] != 'O' || dst[1] != 'K') {
|
||||
throw new IOException("Store failed: " + dst[0] + dst[1]);
|
||||
}
|
||||
}
|
||||
}
|
@@ -25,6 +25,7 @@ import com.google.gerrit.server.config.GerritGlobalModule;
|
||||
import com.google.gerrit.server.config.GerritServerConfigModule;
|
||||
import com.google.gerrit.server.config.MasterNodeStartup;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.contact.HttpContactStoreConnection;
|
||||
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
|
||||
import com.google.gerrit.server.git.PushReplication;
|
||||
import com.google.gerrit.server.git.WorkQueue;
|
||||
@@ -208,6 +209,7 @@ public class WebAppInitializer extends GuiceServletContextListener {
|
||||
modules.add(sysInjector.getInstance(GitOverHttpModule.class));
|
||||
modules.add(sshInjector.getInstance(WebSshGlueModule.class));
|
||||
modules.add(CacheBasedWebSession.module());
|
||||
modules.add(HttpContactStoreConnection.module());
|
||||
return sysInjector.createChildInjector(modules);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user