Project

General

Profile

Revision 6627

check replication table (not keystore) for trusted server host name match

View differences:

src/edu/ucsb/nceas/metacat/replication/ReplicationServlet.java
26 26

  
27 27
package edu.ucsb.nceas.metacat.replication;
28 28

  
29
import java.io.FileInputStream;
30 29
import java.io.IOException;
31
import java.io.InputStream;
32 30
import java.io.OutputStream;
33 31
import java.io.PrintWriter;
34
import java.security.KeyStore;
35
import java.security.KeyStoreException;
36
import java.security.NoSuchAlgorithmException;
37
import java.security.cert.Certificate;
38
import java.security.cert.CertificateException;
32
import java.net.URI;
33
import java.net.URISyntaxException;
39 34
import java.security.cert.X509Certificate;
40 35
import java.util.Enumeration;
41 36
import java.util.Hashtable;
42 37

  
38
import javax.naming.InvalidNameException;
39
import javax.naming.ldap.LdapName;
40
import javax.naming.ldap.Rdn;
43 41
import javax.servlet.ServletConfig;
44 42
import javax.servlet.ServletException;
45 43
import javax.servlet.http.HttpServlet;
......
50 48
import org.apache.log4j.Logger;
51 49
import org.dataone.client.auth.CertificateManager;
52 50

  
53
import edu.ucsb.nceas.metacat.properties.PropertyService;
54 51
import edu.ucsb.nceas.metacat.service.ServiceService;
55 52
import edu.ucsb.nceas.metacat.service.SessionService;
56 53
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
57 54
import edu.ucsb.nceas.metacat.shared.ServiceException;
58 55
import edu.ucsb.nceas.metacat.util.AuthUtil;
59 56
import edu.ucsb.nceas.metacat.util.SessionData;
60
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
61 57

  
62 58
public class ReplicationServlet extends HttpServlet {
63 59

  
......
121 117

  
122 118
		try {
123 119
			// check if the server is included in the list of replicated servers
120
			server = ((String[]) params.get("server"))[0];
124 121
			if (!action.equals("servercontrol") && !action.equals("stop")
125 122
					&& !action.equals("start") && !action.equals("getall")) {
126 123

  
......
128 125
				boolean isValid = false;
129 126
				String msg = "Client certificate is invalid";
130 127
				try {
131
					isValid = hasValidCertificate(request);
128
					isValid = hasValidCertificate(request, server);
132 129
				} catch (Exception e) {
133 130
					msg = "Could not verify client certificate: " + e.getMessage();
134 131
					logMetacat.error(msg, e);
......
144 141
					return;
145 142
				}
146 143
				
147
				server = ((String[]) params.get("server"))[0];
148 144
				if (ReplicationService.getServerCodeForServerName(server) == 0) {
149 145
					logReplication.debug("ReplicationServlet.handleGetOrPost - Action \"" + action + "\" rejected for server: "
150 146
							+ server);
......
270 266
		}
271 267
	}
272 268

  
273
	private boolean hasValidCertificate(HttpServletRequest request) throws KeyStoreException, PropertyNotFoundException, NoSuchAlgorithmException, CertificateException, IOException {
269
	private boolean hasValidCertificate(HttpServletRequest request, String server) throws InvalidNameException, URISyntaxException, ServiceException {
274 270
		// get the certificate from the request
275 271
		X509Certificate certificate = CertificateManager.getInstance().getCertificate(request);
276 272
		if (certificate != null) {
277 273
			String givenSubject = CertificateManager.getInstance().getSubjectDN(certificate);
278 274
			logMetacat.debug("Given certificate subject: " + givenSubject);
279 275

  
280
			// load the keystore
281
			KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
282
			InputStream is = new FileInputStream(PropertyService.getProperty("replication.keystore.file"));
283
			String password = PropertyService.getProperty("replication.keystore.password");
284
			keyStore.load(is, password.toCharArray());
276
			// get the CN from the DN:
277
			String givenServerCN = null;
278
			LdapName ldapName = new LdapName(givenSubject);
279
			for (Rdn rdn: ldapName.getRdns()) {
280
				if (rdn.getType().equalsIgnoreCase("CN")) {
281
					givenServerCN = (String) rdn.getValue();
282
					logMetacat.debug("Given server CN: " + givenServerCN);
283
					break;
284
				}
285
			}
285 286
			
286
			// this is expensive
287
			Enumeration<String> aliases = keyStore.aliases();
288
			while (aliases.hasMoreElements()) {
289
				// check that it contains our client's entry
290
				String alias = aliases.nextElement();
291
				logMetacat.debug("checking keyStore alias: " + alias);
292
				Certificate entryCertificate = keyStore.getCertificate(alias);
293
				if (entryCertificate instanceof X509Certificate) {
294
					// check the subject matches
295
					String entrySubject = CertificateManager.getInstance().getSubjectDN((X509Certificate) entryCertificate);
296
					logMetacat.debug("Entry certificate subject: " + entrySubject);
297
					if (entrySubject.equals(givenSubject)) {
298
						// TODO: additional verification
299
//						try {
300
//							certificate.verify(entryCertificate.getPublicKey());
301
//						} catch (Exception e) {
302
//							logMetacat.warn("Certificate not verifiable: " + e.getMessage(), e);
303
//							continue;
304
//						}
305
						// if we pass verification, we did it!
306
						return true;
307
					}
308
				}	
287
			// check the replication table for this server
288
			int serverCode = ReplicationService.getServerCodeForServerName(server);
289
			if (serverCode != 0) {
290
				// does it match (roughly) the certificate
291
				URI serverURI = new URI("https://" + server);
292
				String serverHost = serverURI.getHost();
293
				logMetacat.debug("Checking against registerd replication server host name: " + serverHost);
294
				// remove wildcard from certificate CN if it is a wildcard certificate
295
				givenServerCN = givenServerCN.replace("*", "");
296
				// match (ends with) same certificate name (domain)?
297
				return serverHost.endsWith(givenServerCN);
309 298
			}
310 299
		}
311 300
 		return false;

Also available in: Unified diff