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.MetaCatServlet;
51
import edu.ucsb.nceas.metacat.service.ServiceService;
52
import edu.ucsb.nceas.metacat.shared.ServiceException;
53

    
54
public class ReplicationServlet extends HttpServlet {
55

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

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

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

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

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

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

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

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

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

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

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

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

    
208
		} catch (ServiceException e) {
209
			logMetacat.error("ReplicationServlet.handleGetOrPost - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
210
			logReplication.error("ReplicationServlet.handleGetOrPost - Error in ReplicationServlet.handleGetOrPost: " + e.getMessage());
211
		} finally {
212
			if (out != null) {
213
				out.close();
214
			}
215
		}
216
	}
217

    
218
	private boolean hasValidCertificate(HttpServletRequest request, String server) throws InvalidNameException, URISyntaxException, ServiceException {
219
		// get the certificate from the request
220
		X509Certificate certificate = CertificateManager.getInstance().getCertificate(request);
221
		if (certificate != null) {
222
			String givenSubject = CertificateManager.getInstance().getSubjectDN(certificate);
223
			logMetacat.info("Given client's certificate subject: " + givenSubject);
224

    
225
			// get the CN from the DN:
226
			String givenServerCN = null;
227
			LdapName ldapName = new LdapName(givenSubject);
228
			for (Rdn rdn: ldapName.getRdns()) {
229
				if (rdn.getType().equalsIgnoreCase("CN")) {
230
					givenServerCN = (String) rdn.getValue();
231
					logMetacat.debug("Given server CN: " + givenServerCN);
232
					break;
233
				}
234
			}
235
			
236
			// check the replication table for this server
237
			int serverCode = ReplicationService.getServerCodeForServerName(server);
238
			if (serverCode != 0) {
239
				// does it match (roughly) the certificate
240
				URI serverURI = new URI("https://" + server);
241
				String serverHost = serverURI.getHost();
242
				logMetacat.debug("Checking against registerd replication server host name: " + serverHost);
243
				// remove wildcard from certificate CN if it is a wildcard certificate
244
				givenServerCN = givenServerCN.replace("*", "");
245
				// match (ends with) same certificate name (domain)?
246
				return serverHost.endsWith(givenServerCN);
247
			}
248
		} else {
249
		    String error = "ReplicationServlet.hasValidCertifcate - the client certificate is null. This means somehow the client certificate wasn't passed to Metacat!";
250
		    logMetacat.error(error);
251
		    throw new ServiceException(error);
252
		}
253
 		return false;
254
	}
255
}
(7-7/7)