Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements replication for metacat
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Chad Berkley
7
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2009-03-25 13:41:15 -0800 (Wed, 25 Mar 2009) $'
10
 * '$Revision: 4861 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

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

    
29
import java.io.IOException;
30
import java.io.OutputStream;
31
import java.io.PrintWriter;
32
import java.net.URI;
33
import java.net.URISyntaxException;
34
import java.security.cert.X509Certificate;
35
import java.util.Enumeration;
36
import java.util.Hashtable;
37

    
38
import javax.naming.InvalidNameException;
39
import javax.naming.ldap.LdapName;
40
import javax.naming.ldap.Rdn;
41
import javax.servlet.ServletConfig;
42
import javax.servlet.ServletException;
43
import javax.servlet.http.HttpServlet;
44
import javax.servlet.http.HttpServletRequest;
45
import javax.servlet.http.HttpServletResponse;
46

    
47
import org.apache.log4j.Logger;
48
import org.dataone.client.auth.CertificateManager;
49

    
50
import edu.ucsb.nceas.metacat.service.ServiceService;
51
import edu.ucsb.nceas.metacat.shared.ServiceException;
52

    
53
public class ReplicationServlet extends HttpServlet {
54

    
55
	private static final long serialVersionUID = -2898600143193513155L;
56

    
57
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
58
	private static Logger logMetacat = Logger.getLogger(ReplicationServlet.class);
59

    
60
	/**
61
	 * Initialize the servlet by creating appropriate database connections
62
	 */
63
	public void init(ServletConfig config) throws ServletException {
64

    
65
		try {
66
			// Register preliminary services
67
			ServiceService.registerService("ReplicationService", ReplicationService
68
					.getInstance());
69
			
70
		} catch (ServiceException se) {
71
			String errorMessage = "ReplicationServlet.init - Service problem while intializing Replication Servlet: "
72
					+ se.getMessage();
73
			logMetacat.error("ReplicationServlet.init - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
74
			logReplication.error(errorMessage);
75
			throw new ServletException(errorMessage);
76
		} 
77
	}
78

    
79
	public void destroy() {
80
		//ServiceService.
81
	}
82

    
83
	public void doGet(HttpServletRequest request, HttpServletResponse response)
84
			throws ServletException, IOException {
85
		// Process the data and send back the response
86
		handleGetOrPost(request, response);
87
	}
88

    
89
	public void doPost(HttpServletRequest request, HttpServletResponse response)
90
			throws ServletException, IOException {
91
		// Process the data and send back the response
92
		handleGetOrPost(request, response);
93
	}
94

    
95
	private void handleGetOrPost(HttpServletRequest request, HttpServletResponse response)
96
			throws ServletException, IOException {
97
		PrintWriter out = null;
98
		Hashtable<String, String[]> params = new Hashtable<String, String[]>();
99
		Enumeration<String> paramlist = request.getParameterNames();
100

    
101
		while (paramlist.hasMoreElements()) {
102
			String name = (String) paramlist.nextElement();
103
			String[] value = request.getParameterValues(name);
104
			params.put(name, value);
105
		}
106

    
107
		String action = "";
108
		if (!params.isEmpty() && params.get("action") != null) {
109
			action = ((String[]) params.get("action"))[0];
110
		}
111
		String server = null;
112

    
113
		try {
114
			// check if the server is included in the list of replicated servers
115
			server = ((String[]) params.get("server"))[0];
116

    
117
			// verify the client certificate on the request
118
			boolean isValid = false;
119
			String msg = "Client certificate is invalid";
120
			try {
121
				isValid = hasValidCertificate(request, server);
122
			} catch (Exception e) {
123
				msg = "Could not verify client certificate: " + e.getMessage();
124
				logMetacat.error(msg, e);
125
				logReplication.error(msg, e);
126
			}
127
			if (!isValid) {
128
				// send message to response
129
				out = response.getWriter();
130
				out.print("<error>");
131
				out.print(msg);
132
				out.print("</error>");
133
				out.close();
134
				return;
135
			}
136
			
137
			// we passed the test, now continue
138
			if (ReplicationService.getServerCodeForServerName(server) == 0) {
139
				logReplication.debug("ReplicationServlet.handleGetOrPost - Action \"" + action + "\" rejected for server: " + server);
140
				return;
141
			} else {
142
				logReplication.debug("ReplicationServlet.handleGetOrPost - Action \"" + action + "\" accepted for server: " + server);
143
			}
144
			
145
			// perform the correct action
146
			if (action.equals("readdata")) {
147
				OutputStream outStream = response.getOutputStream();
148
				//to get the data file.
149
				ReplicationService.handleGetDataFileRequest(outStream, params, response);
150
				outStream.close();
151
			} else if (action.equals("forcereplicatedatafile")) {
152
				//read a specific docid from remote host, and store it into local host
153
				ReplicationService.handleForceReplicateDataFileRequest(params, request);
154
			} else if (action.equals("forcereplicate")) {
155
				// read a specific docid from remote host, and store it into local host
156
				ReplicationService.handleForceReplicateRequest(params, response, request);
157
			} else if (action.equals("forcereplicatesystemmetadata")) {
158
				ReplicationService.handleForceReplicateSystemMetadataRequest(params, response, request);
159
			} else if (action.equals("forcereplicatedelete")) {
160
				// read a specific docid from remote host, and store it into local host
161
				ReplicationService.handleForceReplicateDeleteRequest(params, response, request);
162
			} else if (action.equals("update")) {
163
				// request an update list from the server
164
				ReplicationService.handleUpdateRequest(params, response);
165
			} else if (action.equals("read")) {
166
				// request a specific document from the server
167
				// note that this could be replaced by a call to metacatServlet
168
				// handleGetDocumentAction().
169
				ReplicationService.handleGetDocumentRequest(params, response);				
170
			} else if (action.equals("getlock")) {
171
				ReplicationService.handleGetLockRequest(params, response);
172
			} else if (action.equals("getdocumentinfo")) {
173
				ReplicationService.handleGetDocumentInfoRequest(params, response);
174
			} else if (action.equals("getsystemmetadata")) {
175
				ReplicationService.handleGetSystemMetadataRequest(params, response);
176
			} else if (action.equals("gettime")) {
177
				ReplicationService.handleGetTimeRequest(params, response);
178
			} else if (action.equals("getcatalog")) {
179
				ReplicationService.handleGetCatalogRequest(params, response, true);
180
			} else if (action.equals("test")) {
181
				response.setContentType("text/html");
182
				out = response.getWriter();
183
				out.println("<html><body>Test successfully</body></html>");
184
			}
185

    
186
		} catch (ServiceException e) {
187
			logMetacat.error("ReplicationServlet.handleGetOrPost - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
188
			logReplication.error("ReplicationServlet.handleGetOrPost - Error in ReplicationServlet.handleGetOrPost: " + e.getMessage());
189
		} finally {
190
			if (out != null) {
191
				out.close();
192
			}
193
		}
194
	}
195

    
196
	private boolean hasValidCertificate(HttpServletRequest request, String server) throws InvalidNameException, URISyntaxException, ServiceException {
197
		// get the certificate from the request
198
		X509Certificate certificate = CertificateManager.getInstance().getCertificate(request);
199
		if (certificate != null) {
200
			String givenSubject = CertificateManager.getInstance().getSubjectDN(certificate);
201
			logMetacat.debug("Given certificate subject: " + givenSubject);
202

    
203
			// get the CN from the DN:
204
			String givenServerCN = null;
205
			LdapName ldapName = new LdapName(givenSubject);
206
			for (Rdn rdn: ldapName.getRdns()) {
207
				if (rdn.getType().equalsIgnoreCase("CN")) {
208
					givenServerCN = (String) rdn.getValue();
209
					logMetacat.debug("Given server CN: " + givenServerCN);
210
					break;
211
				}
212
			}
213
			
214
			// check the replication table for this server
215
			int serverCode = ReplicationService.getServerCodeForServerName(server);
216
			if (serverCode != 0) {
217
				// does it match (roughly) the certificate
218
				URI serverURI = new URI("https://" + server);
219
				String serverHost = serverURI.getHost();
220
				logMetacat.debug("Checking against registerd replication server host name: " + serverHost);
221
				// remove wildcard from certificate CN if it is a wildcard certificate
222
				givenServerCN = givenServerCN.replace("*", "");
223
				// match (ends with) same certificate name (domain)?
224
				return serverHost.endsWith(givenServerCN);
225
			}
226
		}
227
 		return false;
228
	}
229
}
(7-7/7)