package org.cagrid.dorian.service.federation;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.cagrid.core.common.FaultHelper;
import org.cagrid.dorian.model.exceptions.DorianInternalException;
import org.cagrid.gaards.pki.CertUtil;
import org.cagrid.tools.database.Database;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CertificateBlacklistManager {
public static final String CERTIFICATE_RENEWED = "CERTIFICATE RENEWED";
public static final String ACCOUNT_DELETED = "ACCOUNT DELETED";
public static final String COMPROMISED = "COMPROMISED";
public static final String TABLE = "certificate_blacklist";
public static final String SERIAL = "SERIAL_NUMBER";
public static final String SUBJECT = "SUBJECT";
public static final String REASON = "REASON";
public static final String CERTIFICATE = "CERTIFICATE";
private boolean dbBuilt = false;
private Database db;
private Logger log = LoggerFactory.getLogger(getClass());
public CertificateBlacklistManager(Database db) {
this.db = db;
}
public synchronized void addCertificateToBlackList(org.cagrid.dorian.common.X509Certificate cert, String reason) throws DorianInternalException {
try {
addCertificateToBlackList(CertUtil.loadCertificate(cert.getCertificateAsString()), reason);
} catch (GeneralSecurityException e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected Error");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} catch (IOException e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected Error");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public X509Certificate getCertificate(long sn) throws DorianInternalException {
buildDatabase();
Connection c = null;
X509Certificate cert = null;
try {
c = db.getConnection();
PreparedStatement s = c.prepareStatement("select " + CERTIFICATE + " from " + TABLE + " WHERE " + SERIAL + "= ?");
s.setLong(1, sn);
ResultSet rs = s.executeQuery();
if (rs.next()) {
cert = CertUtil.loadCertificate(rs.getString(CERTIFICATE));
}
rs.close();
s.close();
} catch (Exception e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "An unexpected error occurred.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} finally {
db.releaseConnection(c);
}
return cert;
}
public synchronized void addCertificateToBlackList(X509Certificate cert, String reason) throws DorianInternalException {
buildDatabase();
if (!memberOfBlackList(cert.getSerialNumber().longValue())) {
Connection c = null;
try {
c = db.getConnection();
PreparedStatement s = c.prepareStatement("INSERT INTO " + TABLE + " SET " + SERIAL + "= ?," + SUBJECT + "= ?," + REASON + "= ?," + CERTIFICATE + "= ?");
s.setLong(1, cert.getSerialNumber().longValue());
s.setString(2, cert.getSubjectDN().getName());
s.setString(3, reason);
s.setString(4, CertUtil.writeCertificate(cert));
s.executeUpdate();
s.close();
} catch (Exception e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected Error");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} finally {
db.releaseConnection(c);
}
}
}
public void removeCertificateFromBlackList(long serialNumber) throws DorianInternalException {
buildDatabase();
Connection c = null;
try {
c = db.getConnection();
PreparedStatement s = c.prepareStatement("delete from " + TABLE + " where " + SERIAL + "= ?");
s.setLong(1, serialNumber);
s.executeUpdate();
s.close();
} catch (Exception e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected Error");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} finally {
db.releaseConnection(c);
}
}
public List<Long> getBlackList() throws DorianInternalException {
buildDatabase();
List<Long> list = new ArrayList<Long>();
Connection c = null;
try {
c = db.getConnection();
PreparedStatement s = c.prepareStatement("select " + SERIAL + " from " + TABLE);
ResultSet rs = s.executeQuery();
while (rs.next()) {
list.add(Long.valueOf(rs.getLong(SERIAL)));
}
rs.close();
s.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected error encountered.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} finally {
db.releaseConnection(c);
}
return list;
}
public boolean memberOfBlackList(long id) throws DorianInternalException {
buildDatabase();
Connection c = null;
boolean exists = false;
try {
c = db.getConnection();
PreparedStatement s = c.prepareStatement("select count(*) from " + TABLE + " WHERE " + SERIAL + "= ?");
s.setLong(1, id);
ResultSet rs = s.executeQuery();
if (rs.next()) {
if (rs.getInt(1) > 0) {
exists = true;
}
}
rs.close();
s.close();
} catch (Exception e) {
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "Unexpected Database Error");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
} finally {
db.releaseConnection(c);
}
return exists;
}
public void buildDatabase() throws DorianInternalException {
if (!dbBuilt) {
try {
if (!this.db.tableExists(TABLE)) {
String certificates = "CREATE TABLE " + TABLE + " (" + SERIAL + " BIGINT PRIMARY KEY," + SUBJECT + " TEXT NOT NULL," + REASON + " VARCHAR(255) NOT NULL," + CERTIFICATE + " TEXT,"
+ "INDEX document_index (" + SERIAL + "));";
db.update(certificates);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "An unexpected database error occurred.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
this.dbBuilt = true;
}
}
public void clearDatabase() throws DorianInternalException {
buildDatabase();
try {
db.update("delete from " + TABLE);
} catch (Exception e) {
log.error(e.getMessage(), e);
DorianInternalException fault = FaultHelper.createFaultException(DorianInternalException.class, "An unexpected database error occurred.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
}