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
			if (!action.equals("servercontrol") && !action.equals("stop")
121
					&& !action.equals("start") && !action.equals("getall")) {
122

    
123
				server = ((String[]) params.get("server"))[0];
124

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

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

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

    
193
			}// else
194

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

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

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

    
277
			// get the CN from the DN:
278
			String givenServerCN = null;
279
			LdapName ldapName = new LdapName(givenSubject);
280
			for (Rdn rdn: ldapName.getRdns()) {
281
				if (rdn.getType().equalsIgnoreCase("CN")) {
282
					givenServerCN = (String) rdn.getValue();
283
					logMetacat.debug("Given server CN: " + givenServerCN);
284
					break;
285
				}
286
			}
287
			
288
			// check the replication table for this server
289
			int serverCode = ReplicationService.getServerCodeForServerName(server);
290
			if (serverCode != 0) {
291
				// does it match (roughly) the certificate
292
				URI serverURI = new URI("https://" + server);
293
				String serverHost = serverURI.getHost();
294
				logMetacat.debug("Checking against registerd replication server host name: " + serverHost);
295
				// remove wildcard from certificate CN if it is a wildcard certificate
296
				givenServerCN = givenServerCN.replace("*", "");
297
				// match (ends with) same certificate name (domain)?
298
				return serverHost.endsWith(givenServerCN);
299
			}
300
		}
301
 		return false;
302
	}
303
}
(8-8/8)