浏览代码

Implemented hot-reloadable CRL

tags/v1.2.0
James Moger 11 年前
父节点
当前提交
6db4261a98

+ 7
- 33
src/com/gitblit/GitBlitServer.java 查看文件

@@ -44,7 +44,6 @@ import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.ssl.SslConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -426,53 +425,28 @@ public class GitBlitServer {
private static Connector createSSLConnector(String certAlias, File keyStore, File clientTrustStore,
String storePassword, File caRevocationList, boolean useNIO, int port,
boolean requireClientCertificates) {
SslContextFactory sslContext = new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH);
GitblitSslContextFactory factory = new GitblitSslContextFactory(certAlias,
keyStore, clientTrustStore, storePassword, caRevocationList);
SslConnector connector;
if (useNIO) {
logger.info("Setting up NIO SslSelectChannelConnector on port " + port);
SslSelectChannelConnector ssl = new SslSelectChannelConnector(sslContext);
SslSelectChannelConnector ssl = new SslSelectChannelConnector(factory);
ssl.setSoLingerTime(-1);
if (requireClientCertificates) {
sslContext.setNeedClientAuth(true);
factory.setNeedClientAuth(true);
} else {
sslContext.setWantClientAuth(true);
factory.setWantClientAuth(true);
}
ssl.setThreadPool(new QueuedThreadPool(20));
connector = ssl;
} else {
logger.info("Setting up NIO SslSocketConnector on port " + port);
SslSocketConnector ssl = new SslSocketConnector(sslContext);
SslSocketConnector ssl = new SslSocketConnector(factory);
connector = ssl;
}
// disable renegotiation unless this is a patched JVM
boolean allowRenegotiation = false;
String v = System.getProperty("java.version");
if (v.startsWith("1.7")) {
allowRenegotiation = true;
} else if (v.startsWith("1.6")) {
// 1.6.0_22 was first release with RFC-5746 implemented fix.
if (v.indexOf('_') > -1) {
String b = v.substring(v.indexOf('_') + 1);
if (Integer.parseInt(b) >= 22) {
allowRenegotiation = true;
}
}
}
if (allowRenegotiation) {
logger.info(" allowing SSL renegotiation on Java " + v);
sslContext.setAllowRenegotiate(allowRenegotiation);
}
sslContext.setKeyStorePath(keyStore.getAbsolutePath());
sslContext.setKeyStorePassword(storePassword);
sslContext.setTrustStore(clientTrustStore.getAbsolutePath());
sslContext.setTrustStorePassword(storePassword);
sslContext.setCrlPath(caRevocationList.getAbsolutePath());
if (!StringUtils.isEmpty(certAlias)) {
logger.info(" certificate alias = " + certAlias);
sslContext.setCertAlias(certAlias);
}
connector.setPort(port);
connector.setMaxIdleTime(30000);
return connector;
}

+ 94
- 0
src/com/gitblit/GitblitSslContextFactory.java 查看文件

@@ -0,0 +1,94 @@
/*
* Copyright 2012 gitblit.com.
*
* 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.gitblit;
import java.io.File;
import java.security.KeyStore;
import java.security.cert.CRL;
import java.util.Collection;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.utils.StringUtils;
/**
* Special SSL context factory that configures Gitblit GO and replaces the
* primary trustmanager with a GitblitTrustManager.
*
* @author James Moger
*/
public class GitblitSslContextFactory extends SslContextFactory {
private static final Logger logger = LoggerFactory.getLogger(GitblitSslContextFactory.class);
private final File caRevocationList;
public GitblitSslContextFactory(String certAlias, File keyStore, File clientTrustStore,
String storePassword, File caRevocationList) {
super(keyStore.getAbsolutePath());
this.caRevocationList = caRevocationList;
// disable renegotiation unless this is a patched JVM
boolean allowRenegotiation = false;
String v = System.getProperty("java.version");
if (v.startsWith("1.7")) {
allowRenegotiation = true;
} else if (v.startsWith("1.6")) {
// 1.6.0_22 was first release with RFC-5746 implemented fix.
if (v.indexOf('_') > -1) {
String b = v.substring(v.indexOf('_') + 1);
if (Integer.parseInt(b) >= 22) {
allowRenegotiation = true;
}
}
}
if (allowRenegotiation) {
logger.info(" allowing SSL renegotiation on Java " + v);
setAllowRenegotiate(allowRenegotiation);
}
if (!StringUtils.isEmpty(certAlias)) {
logger.info(" certificate alias = " + certAlias);
setCertAlias(certAlias);
}
setKeyStorePassword(storePassword);
setTrustStore(clientTrustStore.getAbsolutePath());
setTrustStorePassword(storePassword);
logger.info(" keyStorePath = " + keyStore.getAbsolutePath());
logger.info(" trustStorePath = " + clientTrustStore.getAbsolutePath());
logger.info(" crlPath = " + caRevocationList.getAbsolutePath());
}
@Override
protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls)
throws Exception {
TrustManager[] managers = super.getTrustManagers(trustStore, crls);
X509TrustManager delegate = (X509TrustManager) managers[0];
GitblitTrustManager root = new GitblitTrustManager(delegate, caRevocationList);
// replace first manager with the GitblitTrustManager
managers[0] = root;
return managers;
}
}

+ 125
- 0
src/com/gitblit/GitblitTrustManager.java 查看文件

@@ -0,0 +1,125 @@
/*
* Copyright 2012 gitblit.com.
*
* 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.gitblit;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.concurrent.atomic.AtomicLong;
import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* GitblitTrustManager is a wrapper trust manager that hot-reloads a local file
* CRL and enforces client certificate revocations. The GitblitTrustManager
* also implements fuzzy revocation enforcement in case of issuer mismatch BUT
* serial number match. These rejecions are specially noted in the log.
*
* @author James Moger
*/
public class GitblitTrustManager implements X509TrustManager {
private static final Logger logger = LoggerFactory.getLogger(GitblitTrustManager.class);
private final X509TrustManager delegate;
private final File caRevocationList;
private final AtomicLong lastModified = new AtomicLong(0);
private volatile X509CRL crl;
public GitblitTrustManager(X509TrustManager delegate, File crlFile) {
this.delegate = delegate;
this.caRevocationList = crlFile;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
X509Certificate cert = chain[0];
if (isRevoked(cert)) {
String message = MessageFormat.format("Rejecting revoked certificate {0,number,0} for {1}",
cert.getSerialNumber(), cert.getSubjectDN().getName());
logger.warn(message);
throw new CertificateException(message);
}
delegate.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
delegate.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return delegate.getAcceptedIssuers();
}
protected boolean isRevoked(X509Certificate cert) {
if (!caRevocationList.exists()) {
return false;
}
read();
if (crl.isRevoked(cert)) {
// exact cert is revoked
return true;
}
X509CRLEntry entry = crl.getRevokedCertificate(cert.getSerialNumber());
if (entry != null) {
logger.warn("Certificate issuer does not match CRL issuer, but serial number has been revoked!");
logger.warn(" cert issuer = " + cert.getIssuerX500Principal());
logger.warn(" crl issuer = " + crl.getIssuerX500Principal());
return true;
}
return false;
}
protected synchronized void read() {
if (lastModified.get() == caRevocationList.lastModified()) {
return;
}
logger.info("Reloading CRL from " + caRevocationList.getAbsolutePath());
InputStream inStream = null;
try {
inStream = new FileInputStream(caRevocationList);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL list = (X509CRL)cf.generateCRL(inStream);
crl = list;
lastModified.set(caRevocationList.lastModified());
} catch (Exception e) {
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (Exception e) {
}
}
}
}
}

正在加载...
取消
保存