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
import javax.servlet.http.HttpSession;
47

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

    
51
import edu.ucsb.nceas.metacat.service.ServiceService;
52
import edu.ucsb.nceas.metacat.service.SessionService;
53
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
54
import edu.ucsb.nceas.metacat.shared.ServiceException;
55
import edu.ucsb.nceas.metacat.util.AuthUtil;
56
import edu.ucsb.nceas.metacat.util.SessionData;
57

    
58
public class ReplicationServlet extends HttpServlet {
59

    
60
	private static final long serialVersionUID = -2898600143193513155L;
61

    
62
	private static Logger logReplication = Logger.getLogger("ReplicationLogging");
63
	private static Logger logMetacat = Logger.getLogger(ReplicationServlet.class);
64

    
65
	/**
66
	 * Initialize the servlet by creating appropriate database connections
67
	 */
68
	public void init(ServletConfig config) throws ServletException {
69

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

    
84
	public void destroy() {
85
		//ServiceService.
86
	}
87

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

    
94
	public void doPost(HttpServletRequest request, HttpServletResponse response)
95
			throws ServletException, IOException {
96
		// Process the data and send back the response
97
		handleGetOrPost(request, response);
98
	}
99

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

    
106
		while (paramlist.hasMoreElements()) {
107
			String name = (String) paramlist.nextElement();
108
			String[] value = request.getParameterValues(name);
109
			params.put(name, value);
110
		}
111

    
112
		String action = "";
113
		if (!params.isEmpty() && params.get("action") != null) {
114
			action = ((String[]) params.get("action"))[0];
115
		}
116
		String server = null;
117

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

    
124
				// verify the client certificate on the request
125
				boolean isValid = false;
126
				String msg = "Client certificate is invalid";
127
				try {
128
					isValid = hasValidCertificate(request, server);
129
				} catch (Exception e) {
130
					msg = "Could not verify client certificate: " + e.getMessage();
131
					logMetacat.error(msg, e);
132
					logReplication.error(msg, e);
133
				}
134
				if (!isValid) {
135
					// send message to response
136
					out = response.getWriter();
137
					out.print("<error>");
138
					out.print(msg);
139
					out.print("</error>");
140
					out.close();
141
					return;
142
				}
143
				
144
				if (ReplicationService.getServerCodeForServerName(server) == 0) {
145
					logReplication.debug("ReplicationServlet.handleGetOrPost - Action \"" + action + "\" rejected for server: "
146
							+ server);
147
					return;
148
				} else {
149
					logReplication.debug("ReplicationServlet.handleGetOrPost - Action \"" + action + "\" accepted for server: "
150
							+ server);
151
				}
152
				
153
			} else {
154
				// start, stop, getall and servercontrol need to check if user is administor
155
				HttpSession sess = request.getSession(true);
156
				SessionData sessionData = null;
157
				String sess_id = "";
158
				String username = "";
159
				String[] groupnames = { "" };
160

    
161
				if (params.containsKey("sessionid")) {
162
					sess_id = ((String[]) params.get("sessionid"))[0];
163
					logReplication.info("ReplicationServlet.handleGetOrPost - in has sessionid " + sess_id);
164
					if (SessionService.getInstance().isSessionRegistered(sess_id)) {
165
						logReplication.info("ReplicationServlet.handleGetOrPost - find the id " + sess_id + " in hash table");
166
						sessionData = SessionService.getInstance().getRegisteredSession(sess_id);
167
					}
168
				}
169
				if (sessionData == null) {
170
					sessionData = new SessionData(sess.getId(), 
171
							(String) sess.getAttribute("username"), 
172
							(String[]) sess.getAttribute("groups"),
173
							(String) sess.getAttribute("password"), 
174
							(String) sess.getAttribute("name"));
175
				}
176

    
177
				username = sessionData.getUserName();
178
				logReplication.warn("ReplicationServlet.handleGetOrPost - The user name from session is: " + username);
179
				groupnames = sessionData.getGroupNames();
180
				if (!AuthUtil.isAdministrator(username, groupnames)) {
181
					out = response.getWriter();
182
					out.print("<error>");
183
					out.print("The user \"" + username
184
							+ "\" is not authorized for this action.");
185
					out.print("</error>");
186
					out.close();
187
					logReplication.warn("ReplicationServlet.handleGetOrPost - The user \"" + username
188
							+ "\" is not authorized for this action: " + action);
189
					return;
190
				}
191

    
192
			}// else
193

    
194
			if (action.equals("readdata")) {
195
				OutputStream outStream = response.getOutputStream();
196
				//to get the data file.
197
				ReplicationService.handleGetDataFileRequest(outStream, params, response);
198
				outStream.close();
199
			} else if (action.equals("forcereplicatedatafile")) {
200
				//read a specific docid from remote host, and store it into local host
201
				ReplicationService.handleForceReplicateDataFileRequest(params, request);
202
			} else if (action.equals("stop")) {
203
				// stop the replication server
204
				ReplicationService.getInstance().stopReplication();
205
				out = response.getWriter();
206
				out.println("Replication Handler Stopped");
207
			} else if (action.equals("start")) {
208
				ReplicationService.getInstance().startReplication(params);
209
				out = response.getWriter();
210
				out.println("Replication Handler Started");
211
			} else if (action.equals("getall")) {
212
				ReplicationService.getInstance().runOnce();
213
				response.setContentType("text/html");
214
				out = response.getWriter();
215
				out.println("<html><body>\"Get All\" Done</body></html>");
216
			} else if (action.equals("forcereplicate")) {
217
				// read a specific docid from remote host, and store it into
218
				// local host
219
				ReplicationService.handleForceReplicateRequest(params, response,
220
						request);
221
			} else if (action.equals("forcereplicatesystemmetadata")) {
222
				ReplicationService.handleForceReplicateSystemMetadataRequest(params, response,
223
						request);
224
			} else if (action.equals("forcereplicatedelete")) {
225
				// read a specific docid from remote host, and store it into
226
				// local host
227
				ReplicationService.handleForceReplicateDeleteRequest(params,
228
						response, request);
229
			} else if (action.equals("update")) {
230
				// request an update list from the server
231
				ReplicationService.handleUpdateRequest(params, response);
232
			} else if (action.equals("read")) {
233
				// request a specific document from the server
234
				// note that this could be replaced by a call to metacatServlet
235
				// handleGetDocumentAction().
236
				ReplicationService.handleGetDocumentRequest(params, response);				
237
			} else if (action.equals("getlock")) {
238
				ReplicationService.handleGetLockRequest(params, response);
239
			} else if (action.equals("getdocumentinfo")) {
240
				ReplicationService.handleGetDocumentInfoRequest(params, response);
241
			} else if (action.equals("getsystemmetadata")) {
242
				ReplicationService.handleGetSystemMetadataRequest(params, response);
243
			} else if (action.equals("gettime")) {
244
				ReplicationService.handleGetTimeRequest(params, response);
245
			} else if (action.equals("getcatalog")) {
246
				ReplicationService.handleGetCatalogRequest(params, response, true);
247
			} else if (action.equals("servercontrol")) {
248
				ReplicationService.handleServerControlRequest(params, response);
249
			} else if (action.equals("test")) {
250
				response.setContentType("text/html");
251
				out = response.getWriter();
252
				out.println("<html><body>Test successfully</body></html>");
253
			}
254

    
255
		} catch (ServiceException e) {
256
			logMetacat.error("ReplicationServlet.handleGetOrPost - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
257
			logReplication.error("ReplicationServlet.handleGetOrPost - Error in ReplicationServlet.handleGetOrPost: " + e.getMessage());
258
		} catch (MetacatUtilException mue) {
259
			logMetacat.error("ReplicationServlet.handleGetOrPost - " + ReplicationService.METACAT_REPL_ERROR_MSG);                         
260
			logReplication.error("ReplicationServlet.handleGetOrPost - Metacat utility error in ReplicationServlet.handleGetOrPost: "
261
							+ mue.getMessage());
262
		} finally {
263
			if (out != null) {
264
				out.close();
265
			}
266
		}
267
	}
268

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

    
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
			}
286
			
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);
298
			}
299
		}
300
 		return false;
301
	}
302
}
(8-8/8)