source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/LibraryServlet.java@ 36879

Last change on this file since 36879 was 36879, checked in by anupama, 18 months ago

GS3 shouldn't allow system commands to go through unless it's either from the same PC (IP) as the GS3 server machine (so cmdline building and activate.pl work), or the user is administrator, or the system command is a collection-level command and the user has permissions for this or all collections. If not the case, the user will be asked to login.

  • Property svn:keywords set to Author Date Id Revision
File size: 50.0 KB
Line 
1/*
2 * LibraryServlet.java
3 * Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20package org.greenstone.gsdl3;
21
22import java.io.File;
23import java.io.IOException;
24import java.io.PrintWriter;
25import java.io.Serializable;
26import java.lang.reflect.Type;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Enumeration;
30import java.util.HashMap;
31import java.util.Hashtable;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35
36import javax.servlet.ServletConfig;
37import javax.servlet.ServletContext;
38import javax.servlet.ServletException;
39import javax.servlet.http.Cookie;
40import javax.servlet.http.HttpServletRequest;
41import javax.servlet.http.HttpServletResponse;
42import javax.servlet.http.HttpSession;
43import javax.servlet.http.HttpSessionBindingEvent;
44import javax.servlet.http.HttpSessionBindingListener;
45
46import org.apache.commons.fileupload.FileItem;
47import org.apache.commons.fileupload.disk.DiskFileItemFactory;
48import org.apache.commons.fileupload.servlet.ServletFileUpload;
49import org.apache.commons.lang3.StringUtils;
50import org.apache.log4j.Logger;
51import org.greenstone.gsdl3.action.PageAction;
52import org.greenstone.gsdl3.comms.Communicator;
53import org.greenstone.gsdl3.comms.SOAPCommunicator;
54import org.greenstone.gsdl3.core.DefaultReceptionist;
55import org.greenstone.gsdl3.core.MessageRouter;
56import org.greenstone.gsdl3.core.Receptionist;
57import org.greenstone.gsdl3.service.Authentication;
58import org.greenstone.gsdl3.util.Dictionary;
59import org.greenstone.gsdl3.util.GSConstants;
60import org.greenstone.gsdl3.util.GSParams;
61import org.greenstone.gsdl3.util.GSXML;
62import org.greenstone.gsdl3.util.UserContext;
63import org.greenstone.gsdl3.util.XMLConverter;
64import org.greenstone.util.GlobalProperties;
65import org.json.JSONObject;
66import org.w3c.dom.Document;
67import org.w3c.dom.Element;
68import org.w3c.dom.Node;
69import org.w3c.dom.NodeList;
70
71import com.google.gson.Gson;
72import com.google.gson.reflect.TypeToken;
73
74/**
75 * a servlet to serve the greenstone library - we are using servlets instead of
76 * cgi
77 * the init method is called only once - the first time the servlet classes
78 * are loaded. Each time a request comes in to the servlet, the session() method
79 * is called in a new thread (calls doGet/doPut etc) takes the a=p&p=home type
80 * args and builds a simple request to send to its receptionist, which returns a
81 * result in html, cos output=html is set in the request
82 *
83 * 18/Jul/07 xiao modify to make the cached parameters collection-specific. Most
84 * of the work is done in doGet(), except adding an inner class
85 * UserSessionCache.
86 *
87 * @see Receptionist
88 */
89public class LibraryServlet extends BaseGreenstoneServlet
90{
91 protected static final String LOGIN_MESSAGE_PARAM = "loginMessage";
92 protected static final String REDIRECT_URL_PARAM = "redirectURL";
93 /** the receptionist to send messages to */
94 protected Receptionist recept = null;
95
96 /** We record the library name for later */
97 protected String library_name = null;
98 /** Whether or not client-side XSLT support should be exposed */
99 protected boolean supports_client_xslt = false;
100
101 /**
102 * the default language - is specified by setting a servlet param, otherwise
103 * DEFAULT_LANG is used
104 */
105 protected String default_lang = null;
106 /**
107 * The default default - used if a default lang is not specified in the
108 * servlet params
109 */
110 protected final String DEFAULT_LANG = "en";
111
112 /**
113 * the cgi stuff - the Receptionist can add new args to this
114 *
115 * its used by the servlet to determine what args to save,
116 * and to set default values
117 */
118 protected GSParams gs_params = null;
119
120 /**
121 * a hash that contains all the active session IDs mapped to the cached
122 * items It is updated whenever the whole site or a particular collection is
123 * reconfigured using the command a=s&sa=c or a=s&sa=c&c=xxx It is in the
124 * form: sid -> (UserSessionCache object)
125 */
126 protected Hashtable<String, UserSessionCache> session_ids_table = new Hashtable<String, UserSessionCache>();
127
128 /**
129 * the maximum interval that the cached info remains in session_ids_table
130 * (in seconds) This is set in web.xml
131 */
132 protected int session_expiration = 1800;
133
134 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
135
136 /** initialise the servlet */
137 public void init(ServletConfig config) throws ServletException
138 {
139 // always call super.init;
140 super.init(config);
141 // disable preferences - does this work anyway??
142 //System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
143
144 // Look through all the init params
145 // these are the ones we are expecting
146 String interface_name = null;
147 String useXslt = null;
148 String sess_expire = null;
149 String site_name = null;
150 String recept_name = null;
151
152 // may have these instead of site_name
153 String remote_site_name = null;
154 String remote_site_type = null;
155 String remote_site_address = null;
156
157 // the stored config params
158 HashMap<String, Object> config_params = new HashMap<String, Object>();
159 Enumeration<String> params = config.getInitParameterNames();
160 while (params.hasMoreElements()) {
161 String name = params.nextElement();
162 String value = config.getInitParameter(name);
163 if (name.equals(GSConstants.LIBRARY_NAME)) {
164 library_name = value;
165 } else if (name.equals(GSConstants.INTERFACE_NAME)) {
166 interface_name = value;
167 } else if (name.equals(GSConstants.USE_CLIENT_SIDE_XSLT)) {
168 useXslt = value;
169 } else if (name.equals(GSConstants.DEFAULT_LANG)) {
170 this.default_lang = value;
171 } else if (name.equals(GSXML.SESSION_EXPIRATION)) {
172 sess_expire = value;
173 } else if (name.equals(GSConstants.SITE_NAME)) {
174 site_name = value;
175 } else if (name.equals(GSConstants.REMOTE_SITE_NAME)) {
176 remote_site_name = value;
177 } else if (name.equals(GSConstants.REMOTE_SITE_TYPE)) {
178 remote_site_type = value;
179 } else if (name.equals(GSConstants.REMOTE_SITE_ADDRESS)) {
180 remote_site_address = value;
181 } else if (name.equals(GSConstants.RECEPTIONIST_CLASS)) {
182 recept_name = value;
183 } else {
184 // If there is a param we are not expecting, just add to the list. That way users can add new servlet params which will go through to the XML source without modifying code.
185 config_params.put(name, value);
186 }
187 }
188 if (library_name == null || interface_name == null) {
189
190 // must have these
191 System.err.println("initialisation parameters not all set!");
192 System.err.println(" you must have libraryname and interfacename");
193 System.exit(1);
194 }
195
196 // If we don't have a site, then we must be using a Communicator, and all the remote params must be set
197 if (site_name == null && (remote_site_name == null || remote_site_type == null || remote_site_address == null)) {
198
199 System.err.println("initialisation paramters not all set!");
200 System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
201 System.exit(1);
202 }
203
204 supports_client_xslt = useXslt != null && useXslt.equals("true");
205 if (sess_expire != null && !sess_expire.equals(""))
206 {
207 this.session_expiration = Integer.parseInt(sess_expire);
208 }
209 if (this.default_lang == null)
210 {
211 // choose english
212 this.default_lang = DEFAULT_LANG;
213 }
214
215 config_params.put(GSConstants.LIBRARY_NAME, library_name);
216 config_params.put(GSConstants.INTERFACE_NAME, interface_name);
217 config_params.put(GSConstants.USE_CLIENT_SIDE_XSLT, supports_client_xslt);
218
219 if (site_name != null)
220 {
221 config_params.put(GSConstants.SITE_NAME, site_name);
222 }
223
224 // the receptionist -the servlet will talk to this
225 if (recept_name == null)
226 {
227 this.recept = new DefaultReceptionist();
228 }
229 else
230 {
231 try
232 {
233 this.recept = (Receptionist) Class.forName("org.greenstone.gsdl3.core." + recept_name).getDeclaredConstructor().newInstance();
234 }
235 catch (Exception e)
236 { // cant use this new one, so use normal one
237 System.err.println("LibraryServlet configure exception when trying to use a new Receptionist " + recept_name + ": " + e.getMessage());
238 e.printStackTrace();
239 this.recept = new DefaultReceptionist();
240 }
241 }
242 this.recept.setConfigParams(config_params);
243
244 // the params arg thingy
245
246 String params_name = (String) config.getInitParameter("params_class");
247 if (params_name == null)
248 {
249 this.gs_params = new GSParams();
250 }
251 else
252 {
253 try
254 {
255 this.gs_params = (GSParams) Class.forName("org.greenstone.gsdl3.util." + params_name).getDeclaredConstructor().newInstance();
256 }
257 catch (Exception e)
258 {
259 System.err.println("LibraryServlet configure exception when trying to use a new params thing " + params_name + ": " + e.getMessage());
260 e.printStackTrace();
261 this.gs_params = new GSParams();
262 }
263 }
264
265 // the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to the Receptionist, and the servlet never talks to it again directly.
266 if (site_name != null)
267 {
268 String mr_name = (String) config.getInitParameter("messagerouter_class");
269 MessageRouter message_router = null;
270 if (mr_name == null)
271 { // just use the normal MR
272 message_router = new MessageRouter();
273 }
274 else
275 { // try the specified one
276 try
277 {
278 message_router = (MessageRouter) Class.forName("org.greenstone.gsdl3.core." + mr_name).getDeclaredConstructor().newInstance();
279 }
280 catch (Exception e)
281 { // cant use this new one, so use normal one
282 System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter " + mr_name + ": " + e.getMessage());
283 e.printStackTrace();
284 message_router = new MessageRouter();
285 }
286 }
287
288 message_router.setSiteName(site_name);
289 message_router.setLibraryName(library_name);
290 message_router.setParams(this.gs_params);
291 message_router.configure();
292 this.recept.setMessageRouter(message_router);
293 }
294 else
295 {
296 // TODO: what do we do about params here?
297 // talking to a remote site, create a communicator
298 Communicator communicator = null;
299 // we need to create the XML to configure the communicator
300 Document doc = XMLConverter.newDOM();
301 Element site_elem = doc.createElement(GSXML.SITE_ELEM);
302 site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
303 site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
304 site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
305
306 if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA))
307 {
308 communicator = new SOAPCommunicator();
309 }
310 else
311 {
312 System.err.println("LibraryServlet.init Error: invalid Communicator type: " + remote_site_type);
313 System.exit(1);
314 }
315
316 if (!communicator.configure(site_elem))
317 {
318 System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
319 System.exit(1);
320 }
321 this.recept.setMessageRouter(communicator);
322 }
323
324 // pass params to the receptionist
325 this.recept.setParams(this.gs_params);
326 this.recept.configure();
327
328 //Allow the message router and the document to be accessed from anywhere in this servlet context
329 this.getServletContext().setAttribute(library_name+"Router", this.recept.getMessageRouter());
330 }
331
332 private void logUsageInfo(HttpServletRequest request, Map<String, String[]> queryMap)
333 {
334 String usageInfo = "";
335
336 //session-info: get params stored in the session
337 HttpSession session = request.getSession(true);
338 Enumeration attributeNames = session.getAttributeNames();
339 while (attributeNames.hasMoreElements())
340 {
341 String name = (String) attributeNames.nextElement();
342 usageInfo += name + "=" + session.getAttribute(name) + " ";
343 }
344
345 String queryParamStr = "";
346 if (queryMap != null)
347 {
348 Iterator<String> queryIter = queryMap.keySet().iterator();
349 while (queryIter.hasNext()) {
350 String q = queryIter.next();
351 String[] vals = queryMap.get(q);
352 queryParamStr += q +"="+StringUtils.join(vals, ",")+" ";
353 }
354 }
355 //logged info = general-info + session-info
356 usageInfo = request.getServletPath() + " " + //serlvet
357 "[" + queryParamStr.trim()+"]"+" " + // query map params
358 "session:[" + usageInfo.trim() + "]" + " " + // params stored in a session
359 request.getRemoteAddr() + " " + //remote address
360 request.getRequestedSessionId() + " " + //session id
361 request.getHeader("user-agent") + " "; //the remote brower info
362
363 logger.info(usageInfo);
364
365 }
366
367 public class UserSessionCache implements HttpSessionBindingListener
368 {
369 String session_id = "";
370
371 /**
372 * a hash that maps the session ID to a hashtable that maps the
373 * coll_name to its parameters coll_name -> Hashtable (param_name ->
374 * param_value)
375 */
376 protected Hashtable<String, Hashtable<String, String>> coll_name_params_table = null;
377
378 public UserSessionCache(String id, Hashtable<String, Hashtable<String, String>> table)
379 {
380 session_id = id;
381 coll_name_params_table = (table == null) ? new Hashtable() : table;
382 }
383
384 protected void cleanupCache(String coll_name)
385 {
386 if (coll_name_params_table.containsKey(coll_name))
387 {
388 coll_name_params_table.remove(coll_name);
389 }
390 }
391
392 protected Hashtable<String, Hashtable<String, String>> getParamsTable()
393 {
394 return coll_name_params_table;
395 }
396
397 public void valueBound(HttpSessionBindingEvent event)
398 {
399 // Do nothing
400 }
401
402 // if session cache id removed from session, this triggers this valueUnbound method on the value=this object
403 public void valueUnbound(HttpSessionBindingEvent event)
404 {
405 if (session_ids_table.containsKey(session_id))
406 {
407 session_ids_table.remove(session_id);
408 }
409 }
410
411 public int tableSize()
412 {
413 return (coll_name_params_table == null) ? 0 : coll_name_params_table.size();
414 }
415 }
416
417 public void destroy()
418 {
419 recept.cleanUp();
420 }
421
422 public void doGetOrPost(HttpServletRequest request, HttpServletResponse response, Map<String, String[]> queryMap) throws ServletException, IOException
423 {
424 logUsageInfo(request, queryMap);
425
426 if (processRedirectRequest(request, response, queryMap)) {
427 // this method will do the redirect if needed and return true if it has
428 // done so.
429 // e.g. el=direct/framed&rl=0&href=http://newurl.com
430 return;
431 }
432
433 // Nested Diagnostic Configurator to identify the client for
434 HttpSession session = request.getSession(true);
435 session.setMaxInactiveInterval(session_expiration);
436 String uid = session.getId();
437 request.setCharacterEncoding("UTF-8");
438 response.setContentType("text/html;charset=UTF-8");
439 PrintWriter out = response.getWriter();
440
441 String lang = getFirstParam(GSParams.LANGUAGE, queryMap);
442 if (lang == null || lang.equals(""))
443 {
444 // try the session cached lang
445 lang = (String) session.getAttribute(GSParams.LANGUAGE);
446 if (lang == null || lang.equals(""))
447 {
448 // still not set, use the default
449 lang = this.default_lang;
450 }
451 }
452
453 // set the lang in the session
454 session.setAttribute(GSParams.LANGUAGE, lang);
455
456 String output = getFirstParam(GSParams.OUTPUT, queryMap);
457 if (output == null || output.equals(""))
458 {
459 output = "html"; // uses html by default
460 }
461
462 String requestedURL = request.getRequestURL().toString();
463 String baseURL = "";
464 //logger.error("requested URL = "+requestedURL);
465 if (requestedURL.indexOf(library_name) != -1)
466 {
467 // we need to work out the baseURL and set it
468 baseURL = requestedURL;
469 int protocol_boundary_pos = baseURL.indexOf("://");
470 if (protocol_boundary_pos>=1) {
471 baseURL = baseURL.substring(protocol_boundary_pos+1); // change things like http:// or https:// to //
472 }
473 // The baseURL is everything up to the library_name.
474 // eg https://community.greenstone.org/greenstone3/library/collection/twso/page/about
475 // baseURL is //community.greenstone.org/greenstone3
476 // Issues: the library_name may occur in more than one place - eg if its part of the domain name mylibrary.heritage.nz/greenstone3/library
477 // or if a collection name is the same as the library name eg localhost:8585/greenstone3/twso/collection/twso/page/about.
478 // So can't just use teh first or last occurrence. Look for /library-name, and check its not the first position (eg //library.nzdl.org/greenstone3/library)
479 int library_name_index = baseURL.indexOf("/"+library_name);
480 if (library_name_index == 1) {
481 // we have library name at the start of the url - need to use the second one
482 library_name_index = baseURL.indexOf("/"+library_name, 2);
483 }
484 baseURL = baseURL.substring(0, library_name_index+1);
485 //logger.error("new base url = "+baseURL);
486
487 }
488
489 String fullURL;
490 if (request.getQueryString() != null)
491 {
492 fullURL = requestedURL + "?" + request.getQueryString();
493 }
494 else
495 {
496 fullURL = requestedURL;
497 }
498
499 UserContext userContext = new UserContext();
500 userContext.setLanguage(lang);
501 userContext.setUserID(uid);
502
503 if (!processLoginChanges(request, userContext, out, baseURL, queryMap, lang, output)) {
504 // any invalid login attempt will redirect to a new login page and return false
505 return;
506 }
507
508
509 if (request.getAuthType() != null)
510 {
511 // sets username, groups etc into usercontext
512 updateUserContextWithAuthenticatedInfo(request, userContext);
513 }
514
515 // If server output, force a switch to traditional interface
516 //output = (output.equals("server")) ? "html" : output;
517
518 // Force change the output mode if client-side XSLT is supported - server vs. client
519 // BUT only if the library allows client-side transforms
520 if (supports_client_xslt)
521 {
522 // MUST be done before the xml_message is built
523 Cookie[] cookies = request.getCookies();
524 Cookie xsltCookie = null;
525
526 // The client has cookies enabled and a value set - use it!
527 if (cookies != null)
528 {
529 for (Cookie c : cookies)
530 {
531 if (c.getName().equals("supportsXSLT"))
532 {
533 xsltCookie = c;
534 break;
535 }
536 }
537 output = (xsltCookie != null && xsltCookie.getValue().equals("true") && output.equals("html")) ? "xsltclient" : output;
538 }
539 }
540
541
542 String action = getFirstParam(GSParams.ACTION, queryMap);
543 String subaction = getFirstParam(GSParams.SUBACTION, queryMap);
544 String collection = getFirstParam(GSParams.COLLECTION, queryMap);
545 String document = getFirstParam(GSParams.DOCUMENT, queryMap);
546 String service = getFirstParam(GSParams.SERVICE, queryMap);
547 String specified_cache_key = getFirstParam(GSParams.CACHE_KEY, queryMap);
548
549 if (collection != null && !collection.equals("")) {
550 //is this user allowed to access this collection/document?
551 if (!runCollectionSecurityCheck(request, userContext, out, baseURL, collection, document, lang, output)) {
552 return;
553 }
554 }
555 // We clean up the cache session_ids_table if system
556 // commands are issued, and also don't need to do caching for these request requests
557 boolean should_cache = true;
558 if (action != null && action.equals(GSParams.SYSTEM_ACTION)
559 && !subaction.equals(GSXML.SYSTEM_TYPE_PING)
560 && !subaction.equals(GSXML.SYSTEM_TYPE_AUTHENTICATED_PING)) // don't 'clean' anything on a mere ping
561 {
562 should_cache = false;
563
564 // System commands now need to be logged in/have permissions
565 // like configuring, activation and deactivation
566 if(!configureSecurityCheck(request, userContext, out, baseURL, lang, output, queryMap)) {
567 return;
568 }
569
570 // we may want to remove all collection cache info, or just a specific collection
571 boolean clean_all = true;
572 String clean_collection = null;
573 // system commands are to activate/deactivate stuff
574 // collection param is in the sc parameter.
575 // don't like the fact that it is hard coded here
576 String coll = getFirstParam(GSParams.SYSTEM_CLUSTER, queryMap);
577 if (coll != null && !coll.equals(""))
578 {
579 clean_all = false;
580 clean_collection = coll;
581 }
582 else
583 {
584 // check other system types
585 if (subaction.equals("a") || subaction.equals("d"))
586 {
587 String module_name = getFirstParam("sn", queryMap);
588 if (module_name != null && !module_name.equals(""))
589 {
590 clean_all = false;
591 clean_collection = module_name;
592 }
593 }
594 }
595 if (clean_all)
596 {
597 // TODO
598 session_ids_table = new Hashtable<String, UserSessionCache>();
599 session.removeAttribute(GSParams.USER_SESSION_CACHE); // triggers valueUnbound(), which removes the session id from the session_ids_table
600 }
601 else
602 {
603 // just clean up info for clean_collection
604 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(session_ids_table.values());
605 for (int i = 0; i < cache_list.size(); i++)
606 {
607 UserSessionCache cache = cache_list.get(i);
608 cache.cleanupCache(clean_collection);
609 }
610
611 }
612 }
613
614 // cache_key is the collection name, or service name
615 String cache_key = specified_cache_key;
616 if (cache_key == null || cache_key.equals(""))
617 {
618 cache_key = collection;
619 }
620 if (cache_key == null || cache_key.equals(""))
621 {
622 cache_key = service;
623 }
624
625 //clear the collection-specific cache in the session, since we have no way to know whether this page is
626 //about the same collection as the last page or not.
627 Enumeration attributeNames = session.getAttributeNames();
628 while (attributeNames.hasMoreElements())
629 {
630 String name = (String) attributeNames.nextElement();
631 if (!name.equals(GSParams.USER_SESSION_CACHE) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT) && !this.gs_params.isGlobal(name))
632 {
633 session.removeAttribute(name);
634 }
635 }
636
637 UserSessionCache session_cache = null;
638 Hashtable<String, Hashtable<String, String>> param_table = null;
639 Hashtable<String, String> table = null;
640 boolean new_table = false;
641 String sid = session.getId();
642 boolean new_session = false;
643 if (!session_ids_table.containsKey(sid)) {
644 new_session = true;
645 }
646 if (should_cache == true && cache_key != null && !cache_key.equals(""))
647 {
648 if (!new_session)
649 {
650 session_cache = session_ids_table.get(sid);
651 param_table = session_cache.getParamsTable();
652 if (param_table.containsKey(cache_key))
653 {
654 table = param_table.get(cache_key);
655 }
656 else
657 {
658 table = new Hashtable<String, String>();
659 param_table.put(cache_key, table);
660 new_table = true;
661 }
662 }
663 else
664 {
665
666 param_table = new Hashtable<String, Hashtable<String, String>>();
667 table = new Hashtable<String, String>();
668 param_table.put(cache_key, table);
669 session_cache = new UserSessionCache(sid, param_table);
670 session_ids_table.put(sid, session_cache);
671 session.setAttribute(GSParams.USER_SESSION_CACHE, session_cache);
672 new_table = true;
673 }
674
675 }
676
677 // here we add in default params values if need be - if we have a new session, or if we have a new table
678 // in an existing session
679 // don't override any existing values
680 if (new_session || new_table) {
681
682 Iterator i = this.gs_params.getParamsWithDefaults().iterator();
683 while (i.hasNext()) {
684 String p = (String)i.next();
685 String v = this.gs_params.getParamDefault(p);
686 if (this.gs_params.isGlobal(p)) {
687 //need to add in to session unless its already there
688 if (session.getAttribute(p) == null) {
689 session.setAttribute(p, v);
690 }
691 } else {
692 // add to table unless its already there
693 if (new_table && !table.containsKey(p)) {
694 table.put(p,v);
695 }
696 }
697
698 }
699 }
700
701 // the request to the receptionist
702 Document msg_doc = XMLConverter.newDOM();
703 Element xml_message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
704 Element xml_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
705 xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
706
707 xml_message.appendChild(xml_request);
708
709 if (request.getAuthType() != null) {
710 // lots of classes are using the <userInformation> element. But all its info is now in userContext, so maybe we can get rid of this one day?
711 appendUserInformation(xml_request, userContext);
712 }
713
714 if (action == null || action.equals(""))
715 {
716 // display the home page - the default page
717 xml_request.setAttribute(GSXML.ACTION_ATT, "p");
718 xml_request.setAttribute(GSXML.SUBACTION_ATT, PageAction.HOME_PAGE);
719 }
720 else
721 {
722 xml_request.setAttribute(GSXML.ACTION_ATT, action);
723 if (subaction != null)
724 {
725 xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
726 }
727 }
728
729 // create the param list for the greenstone request - includes
730 // the params from the current request and any others from the saved session
731 Element xml_param_list = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
732 xml_request.appendChild(xml_param_list);
733
734 if (queryMap.containsKey("s1.collection") || queryMap.containsKey("s1.group")){
735 table.remove("s1.collection");
736 table.remove("s1.group");
737 }
738 for (String name : queryMap.keySet())
739 {
740 if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT))
741 {// we have already dealt with these
742
743 String value = "";
744 String[] values = queryMap.get(name);
745 value = values[0];
746 if (values.length > 1)
747 {
748 for (int i = 1; i < values.length; i++)
749 {
750 value += "," + values[i];
751 }
752 }
753 // if we need to save the value, then add it to the session/cache table.
754 // otherwise add directly to the paramList
755 if (this.gs_params.shouldSave(name)) {
756 if (this.gs_params.isGlobal(name) || table == null) {
757 session.setAttribute(name, value);
758 } else {
759 table.put(name, value);
760 }
761 }
762 else
763 {
764 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
765 param.setAttribute(GSXML.NAME_ATT, name);
766 param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
767 if (this.gs_params.isSensitive(name)) {
768 param.setAttribute(GSXML.SENSITIVE_ATT, "true");
769 }
770 xml_param_list.appendChild(param);
771
772 }
773 }
774 }
775 //put everything in the table into the session
776 if (table != null)
777 {
778 Enumeration<String> keys = table.keys();
779 while (keys.hasMoreElements())
780 {
781 String name = keys.nextElement();
782 session.setAttribute(name, table.get(name));
783 }
784 }
785
786 // put in all the params from the session cache
787 Enumeration params = session.getAttributeNames();
788 while (params.hasMoreElements())
789 {
790 String name = (String) params.nextElement();
791 if (!name.equals(GSParams.USER_SESSION_CACHE) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
792 {
793
794 // lang and uid are stored but we dont want it in the param list cos its already in the request
795 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
796 param.setAttribute(GSXML.NAME_ATT, name);
797 String value = GSXML.xmlSafe((String) session.getAttribute(name));
798
799 // ugly hack to undo : escaping
800 value = StringUtils.replace(value, "%3A", "\\:");
801 param.setAttribute(GSXML.VALUE_ATT, value);
802 xml_param_list.appendChild(param);
803 }
804 }
805
806
807 if (output.equals("json"))
808 {
809 response.setContentType("application/json");
810 }
811 else if (!output.equals("html") && !output.equals("server") && !output.equals("xsltclient"))
812 {
813 response.setContentType("text/xml"); // for now use text
814 }
815
816 //Add custom HTTP headers if requested
817 String httpHeadersParam = getFirstParam(GSParams.HTTP_HEADER_FIELDS, queryMap);
818 if (httpHeadersParam != null && httpHeadersParam.length() > 0)
819 {
820 Gson gson = new Gson();
821 Type type = new TypeToken<List<Map<String, String>>>()
822 {
823 }.getType();
824 List<Map<String, String>> httpHeaders = gson.fromJson(httpHeadersParam, type);
825 if (httpHeaders != null && httpHeaders.size() > 0)
826 {
827
828 for (int j = 0; j < httpHeaders.size(); j++)
829 {
830 Map nameValueMap = httpHeaders.get(j);
831 String name = (String) nameValueMap.get("name");
832 String value = (String) nameValueMap.get("value");
833
834 if (name != null && value != null)
835 {
836 response.setHeader(name, value);
837 }
838 }
839 }
840 }
841
842
843 xml_request.setAttribute("remoteAddress", request.getRemoteAddr());
844 xml_request.setAttribute("fullURL", fullURL.replace("&", "&amp;"));
845 xml_request.setAttribute("baseURL", baseURL);
846
847// logger.error("about to process this message");
848 // logger.error(XMLConverter.getPrettyString(xml_message));
849 Node xml_result = this.recept.process(xml_message);
850 encodeURLs(xml_result, response);
851
852 String xml_string = XMLConverter.getPrettyString(xml_result);
853
854 if (output.equals("json"))
855 {
856 try
857 {
858 JSONObject json_obj = org.json.XML.toJSONObject(xml_string);
859
860 out.println(json_obj.toString());
861 }
862 catch (Exception e)
863 {
864 e.printStackTrace();
865 out.println("Error: failed to convert output XML to JSON format");
866 }
867 }
868 else
869 {
870 out.println(xml_string);
871 }
872
873 displaySize(session_ids_table);
874 }
875
876 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
877 {
878 doGetOrPost(request, response, request.getParameterMap());
879 } //end of doGet(HttpServletRequest, HttpServletResponse)
880
881 private boolean processRedirectRequest(HttpServletRequest request, HttpServletResponse response, Map<String, String[]> queryMap) throws IOException
882 {
883 if (queryMap != null)
884 {
885 Iterator<String> queryIter = queryMap.keySet().iterator();
886 boolean redirect = false;
887 String href = null;
888 String rl = null;
889 String el = null;
890 String collection = null;
891
892 while (queryIter.hasNext())
893 {
894 String q = queryIter.next();
895 if (q.equals(GSParams.COLLECTION))
896 {
897 collection = queryMap.get(q)[0];
898 }
899 else if (q.equals(GSParams.EXTERNAL_LINK_TYPE))
900 {
901 el = queryMap.get(q)[0];
902 }
903 else if (q.equals(GSParams.HREF))
904 {
905 href = queryMap.get(q)[0];
906 href = StringUtils.replace(href, "%2f", "/");
907 href = StringUtils.replace(href, "%7e", "~");
908 href = StringUtils.replace(href, "%3f", "?");
909 href = StringUtils.replace(href, "%3A", "\\:");
910 }
911 else if (q.equals(GSParams.RELATIVE_LINK))
912 {
913 rl = queryMap.get(q)[0];
914 }
915 }
916
917 //if query_string contains "el=direct", an href is specified, and its not a relative link, then the web page will be redirected to the external URl, otherwise a greenstone page with an external URL will be displayed
918 //"rl=0" this is an external link
919 //"rl=1" this is an internal link
920 if ((href != null) && (rl.equals("0")))
921 {// This is an external link,
922
923 if (el.equals("framed"))
924 {
925 // framed means we are linking to an external page inside our greenstone page
926 HttpSession session = request.getSession();
927 ServletContext context = session.getServletContext();
928 String new_url = context.getContextPath()+"/"+ library_name+"?a=p&sa=html&url="+href;
929 if (collection != null && !collection.equals("")) {
930 new_url += "&c="+collection;
931 }
932 response.sendRedirect(new_url);
933 }
934 else
935 {
936 // el = '' or direct
937 //the web page is re-directed to the external URL (&el=&rl=0&href="http://...")
938 response.sendRedirect(href);
939 }
940 return true;
941 }
942 }
943 return false;
944 }
945
946 private void generateLoginPage(String redirect_url_string, String error_message, UserContext userContext, PrintWriter out, String baseURL, String output) {
947
948 Document loginPageDoc = XMLConverter.newDOM();
949 Element loginPageMessage = loginPageDoc.createElement(GSXML.MESSAGE_ELEM);
950 Element loginPageRequest = GSXML.createBasicRequest(loginPageDoc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
951 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
952 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
953 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, output);
954 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
955
956 loginPageMessage.appendChild(loginPageRequest);
957
958 Element paramList = loginPageDoc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
959 loginPageRequest.appendChild(paramList);
960
961 Element messageParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
962 messageParam.setAttribute(GSXML.NAME_ATT, LOGIN_MESSAGE_PARAM);
963 messageParam.setAttribute(GSXML.VALUE_ATT, error_message);
964 paramList.appendChild(messageParam);
965
966 Element urlParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
967 urlParam.setAttribute(GSXML.NAME_ATT, REDIRECT_URL_PARAM);
968
969 if (redirect_url_string.matches("^[a-z]+://.*$")) {
970 int protocol_boundary_pos = redirect_url_string.indexOf("://");
971 redirect_url_string = redirect_url_string.substring(protocol_boundary_pos+1); // change things like http:// or https:// to //
972 }
973
974 urlParam.setAttribute(GSXML.VALUE_ATT, redirect_url_string);
975 paramList.appendChild(urlParam);
976
977 Node loginPageResponse = this.recept.process(loginPageMessage);
978 out.println(XMLConverter.getPrettyString(loginPageResponse));
979 }
980
981 private boolean processLoginChanges(HttpServletRequest request, UserContext userContext, PrintWriter out, String baseURL, Map<String, String[]> queryMap, String lang, String output) throws ServletException {
982
983 //Check if we need to login or logout
984 String username = getFirstParam(GSParams.USERNAME, queryMap);
985 String password = getFirstParam(GSParams.PASSWORD, queryMap);
986 String logout = getFirstParam(GSParams.LOGOUT, queryMap);
987
988 if (logout != null)
989 {
990 request.logout();
991 }
992
993 if (username != null && password != null)
994 {
995 //We are changing to another user, so log out first
996 if (request.getAuthType() != null)
997 {
998 request.logout();
999 }
1000
1001 //This try/catch block catches when the login request fails (e.g. The user enters an incorrect password).
1002 try
1003 {
1004 //Try a global login first
1005 password = Authentication.hashPassword(password);
1006 request.login(username, password);
1007 }
1008 catch (Exception ex)
1009 {
1010 try
1011 {
1012 //If the global login fails then try a site-level login
1013 String siteName = (String) this.recept.getConfigParams().get(GSConstants.SITE_NAME);
1014 request.login(siteName + "-" + username, password);
1015
1016 }
1017 catch (Exception exc)
1018 {
1019 //The user entered in either the wrong username or the wrong password
1020
1021 HttpSession session = request.getSession();
1022 ServletContext context = session.getServletContext();
1023 String redirect_url_string = request.getRequestURI().replaceFirst(context.getContextPath() + "/", "");
1024
1025 if ((request.getQueryString() != null) && (request.getQueryString().length() > 0))
1026 {
1027 redirect_url_string += "?" + request.getQueryString().replace("&", "&amp;");
1028 }
1029
1030 generateLoginPage(redirect_url_string, getTextString("auth.error.un_or_pw_err", lang), userContext, out, baseURL, output);
1031 return false;
1032 }
1033 }
1034 }
1035 return true;
1036
1037
1038 }
1039
1040 private void updateUserContextWithAuthenticatedInfo(HttpServletRequest request, UserContext userContext)
1041 {
1042
1043 //Get the username
1044 String user_name = request.getUserPrincipal().getName();
1045 userContext.setUsername(user_name);
1046
1047 //Get the groups for the user
1048 Document msg_doc = XMLConverter.newDOM();
1049 Element userInfoMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1050 Element userInfoRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_PROCESS, "GetUserInformation", userContext);
1051 userInfoMessage.appendChild(userInfoRequest);
1052
1053 Element paramList = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1054 userInfoRequest.appendChild(paramList);
1055 paramList.appendChild(GSXML.createParameter(msg_doc, GSXML.USERNAME_ATT, user_name));
1056
1057 Element userInfoResponseMessage = (Element) this.recept.process(userInfoMessage);
1058 Element userInfoResponse = (Element) GSXML.getChildByTagName(userInfoResponseMessage, GSXML.RESPONSE_ELEM);
1059 Element respParamList = (Element) GSXML.getChildByTagName(userInfoResponse, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1060
1061 if (respParamList != null)
1062 {
1063 HashMap<String, Serializable> params = GSXML.extractParams(respParamList, false);
1064 String groups = (String) params.get("groups");
1065 String editEnabled = (String) params.get("editEnabled");
1066 userContext.setGroups(groups.split(","));
1067 userContext.setEditEnabled((editEnabled != null) ? editEnabled : "false");
1068 }
1069 }
1070
1071 private void appendUserInformation(Element xml_request, UserContext userContext)
1072 {
1073 Element userInformation = xml_request.getOwnerDocument().createElement(GSXML.USER_INFORMATION_ELEM);
1074 userInformation.setAttribute(GSXML.USERNAME_ATT, userContext.getUsername());
1075
1076
1077 userInformation.setAttribute(GSXML.GROUPS_ATT, userContext.getGroupsString());
1078 userInformation.setAttribute(GSXML.EDIT_ENABLED_ATT, userContext.getEditEnabled());
1079 xml_request.appendChild(userInformation);
1080 }
1081
1082 /**
1083 * request.getRemoteAddr() returns the IP of the client *or* of a proxy.
1084 * We want the client IP, so we can check if it's truly local or not, since proxies can be
1085 * local, thus masking a client connecting from an external IP.
1086 * The following code is from
1087 * https://www.javaprogramto.com/2020/11/how-to-get-client-ip-address-in-java.html
1088 */
1089 public String getClientIpAddress(HttpServletRequest request)
1090 {
1091 final String[] VALID_IP_HEADER_CANDIDATES = {
1092 "X-Forwarded-For",
1093 "Proxy-Client-IP",
1094 "WL-Proxy-Client-IP",
1095 "HTTP_X_FORWARDED_FOR",
1096 "HTTP_X_FORWARDED",
1097 "HTTP_X_CLUSTER_CLIENT_IP",
1098 "HTTP_CLIENT_IP",
1099 "HTTP_FORWARDED_FOR",
1100 "HTTP_FORWARDED",
1101 "HTTP_VIA",
1102 "REMOTE_ADDR"
1103 };
1104
1105
1106 for (String header : VALID_IP_HEADER_CANDIDATES) {
1107 String ipAddress = request.getHeader(header);
1108 if (ipAddress != null && ipAddress.length() != 0 && !"unknown".equalsIgnoreCase(ipAddress)) {
1109 return ipAddress;
1110 }
1111 }
1112 return request.getRemoteAddr(); // fallback to whatever is the incoming IP (could be proxy)
1113 }
1114
1115
1116 private void debugCheckAgainstRegex() {
1117
1118 // Load the global.properties file, get the tomcat.server.IPregex and check for any of it
1119 // matching against the local IP
1120 String tomcatServerIPregex = GlobalProperties.getProperty("tomcat.server.IPregex", "");
1121
1122 logger.info("@@@ tomcatServerIPregex: " + tomcatServerIPregex);
1123
1124 String[] testIPs = {"127.0.0.1", "::1", "0:0:0:0:0:0:0:1", "0:0:0:0:0:0:0:1%3"};
1125
1126 //if(ipOfClient.equals(request.getLocalAddr()) || ipOfClient.equals("127.0.0.1")
1127 // || ipOfClient.equals("::1") || ipOfClient.startsWith("0:0:0:0:0:0:0:1")) {
1128
1129 for(String testIP : testIPs) {
1130 if(testIP.matches(tomcatServerIPregex)) {
1131 logger.info("testIP " + testIP + " matches regex.");
1132 } else {
1133 logger.info("testIP " + testIP + " DOESN'T match regex.");
1134 }
1135 }
1136 }
1137
1138
1139 /**
1140 * Clients on the same machine as the GS3 server can reconfigure and activate/deactivate,
1141 * Users in the administrator group also have the right to do such system commands.
1142 * For collection-level system commands, users with permissions to edit all collections or
1143 * the specific collection have a right to activate/deactivate a collection.
1144 * Useful links:
1145 * https://stackoverflow.com/questions/13563351/how-to-restrict-acces-to-specific-servlet-by-ip-via-container-configuration
1146 * https://stackoverflow.com/questions/35015514/restricting-access-to-localhost-for-java-servlet-endpoint
1147 * Reverse of: https://stackoverflow.com/questions/2539461/how-to-access-java-servlet-running-on-my-pc-from-outside
1148 */
1149 private boolean configureSecurityCheck(HttpServletRequest request, UserContext userContext,
1150 PrintWriter out, String baseURL, String lang,
1151 String output, Map<String, String[]> queryMap)
1152 {
1153 // if request emanates on same machine as GS server/from local machine, let it go through
1154 String ipOfClient = getClientIpAddress(request); //request.getRemoteAddr();
1155 logger.info("@@@ Request local IP: " + request.getLocalAddr());
1156 logger.info("@@@ Client/remote IP: " + ipOfClient);
1157
1158 //debugCheckAgainstRegex();
1159
1160 //if(ipOfClient.equals(request.getLocalAddr()) || ipOfClient.equals("127.0.0.1")
1161 // || ipOfClient.equals("::1") || ipOfClient.startsWith("0:0:0:0:0:0:0:1")) {
1162 // return true;
1163 //}
1164
1165 // Load the global.properties file, get the tomcat.server.IPregex and check for any of it
1166 // matching against the local IP
1167 String tomcatServerIPregex = GlobalProperties.getProperty("tomcat.server.IPregex", "");
1168 if(ipOfClient.equals(request.getLocalAddr()) || ipOfClient.matches(tomcatServerIPregex)) {
1169 return true;
1170 }
1171
1172 // TODO: Want regex for localhost situations and then make it a property in build.props
1173 // In build.props: comment, you might like to leave the IP of your server machine
1174 // at the end of the line
1175 // Check with another machine: browser, retest cmdline and activate.pl
1176 // Final phase is testing with apache set up
1177
1178 // if we have sc=colname, user needs to be colname-|all-collection-editor
1179 // if we have st=collection&sn=colname, same as above
1180 // otherwise user needs to be administrator
1181
1182 // We can have MODULE_TYPE=collection And MODULE_NAME=collname,
1183 // OR SYSTEM_CLUSTER=collname
1184 // If none of these specified, then assume the user should be administrator
1185 // If not a collection level operation, the user should be administrator
1186
1187 String coll = null;
1188 String module_type = getFirstParam(GSParams.SYSTEM_MODULE_TYPE, queryMap);
1189 if(module_type != null && module_type.equals("collection")) {
1190 // To deactivate demo:library?excerptid=gs_content&a=s&sa=d&sc=lucene-jdbm-demo
1191 coll = getFirstParam(GSParams.SYSTEM_MODULE_NAME, queryMap);
1192 } else {
1193 // To reconfigure demo: library?excerptid=gs_content&a=s&sa=c&sc=lucene-jdbm-demo
1194 coll = getFirstParam(GSParams.SYSTEM_CLUSTER, queryMap);
1195 if (coll != null && coll.equals("")) {
1196 coll = null;
1197 }
1198 }
1199 String collname_editor = (coll == null) ? null : (coll+"-collections-editor");
1200
1201 for (String group : userContext.getGroups()) {
1202
1203 // if user is admin, all is good: they can do reconfigure (on service, collection or
1204 // any module) or activate/deactivate a collection or any module
1205 if (group.equals("administrator")) {
1206 return true;
1207 }
1208
1209 // if collection level operation, user must have permissions for the collection
1210 // so the user must be in at least one of all-|personal-|collname-collections-editor
1211 if (coll != null) { // collname_editor won't be null
1212 if(group.equals("all-collections-editor") || group.equals(collname_editor)) {
1213 return true; // do we add || group.equals("personal-collections-editor")?
1214 }
1215 }
1216
1217 }
1218
1219 errorAndLoginPage(request, userContext, out, baseURL, lang, output);
1220 return false;
1221 }
1222
1223 private boolean runCollectionSecurityCheck(HttpServletRequest request, UserContext userContext, PrintWriter out, String baseURL, String collection, String document, String lang, String output) {
1224
1225 //Get the security info for this collection
1226 Document msg_doc = XMLConverter.newDOM();
1227 Element securityMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1228 Element securityRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_SECURITY, collection, userContext);
1229 securityMessage.appendChild(securityRequest);
1230 if (document != null && !document.equals(""))
1231 {
1232 securityRequest.setAttribute(GSXML.NODE_OID, document);
1233 }
1234
1235 Element securityResponse = (Element) GSXML.getChildByTagName(this.recept.process(securityMessage), GSXML.RESPONSE_ELEM);
1236 if (securityResponse == null)
1237 {
1238 return false;
1239 }
1240
1241 // Groups mentioned in collectionConfig.xml's Security element, se_groups
1242 ArrayList<String> se_groups = GSXML.getGroupsFromSecurityResponse(securityResponse);
1243
1244 //If guests are not allowed to access this page then check to see if the user is in a group that is allowed to access the page
1245 if (!se_groups.contains(""))
1246 {
1247 boolean found = false;
1248 for (String se_group : se_groups)
1249 {
1250 if (request.isUserInRole(se_group))
1251 {
1252 found = true;
1253 break;
1254 }
1255 }
1256
1257 //The current user is not allowed to access the page so produce a login page
1258 if (!found)
1259 {
1260 errorAndLoginPage(request, userContext, out, baseURL, lang, output);
1261 return false;
1262 }
1263 }
1264 return true;
1265 }
1266
1267
1268 private void errorAndLoginPage(HttpServletRequest request, UserContext userContext,
1269 PrintWriter out, String baseURL, String lang, String output)
1270 {
1271 String error_message = "";
1272 if (request.getAuthType() == null)
1273 {
1274 error_message = getTextString("auth.error.login", lang);
1275 }
1276 else
1277 {
1278 error_message = getTextString("auth.error.incorrect_login", lang);
1279 }
1280
1281 HttpSession session = request.getSession();
1282 ServletContext context = session.getServletContext();
1283 String redirect_url_string = request.getRequestURI().replaceFirst(context.getContextPath() + "/", "");
1284
1285 if (request.getQueryString() != null && request.getQueryString().length() > 0)
1286 {
1287 redirect_url_string += "?" + request.getQueryString().replace("&", "&amp;");
1288 }
1289
1290 generateLoginPage(redirect_url_string, error_message, userContext, out, baseURL, output);
1291 }
1292
1293
1294 private String getTextString(String key, String lang) {
1295 return Dictionary.getTextString(key, lang, null, null, null, null, null);
1296
1297 }
1298 //a debugging method
1299 private void displaySize(Hashtable<String, UserSessionCache> table)
1300 {
1301 if (table == null)
1302 {
1303 //logger.info("cached table is null");
1304 return;
1305 }
1306 if (table.size() == 0)
1307 {
1308 //logger.info("cached table size is zero");
1309 return;
1310 }
1311 int num_cached_coll = 0;
1312 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(table.values());
1313 for (int i = 0; i < cache_list.size(); i++)
1314 {
1315 num_cached_coll += cache_list.get(i).tableSize();
1316 }
1317 //logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
1318 }
1319
1320 /** merely a debugging method! */
1321 private String tableToString(Hashtable<String, Hashtable<String, String>> table)
1322 {
1323 String str = "";
1324 Enumeration<String> keys = table.keys();
1325 while (keys.hasMoreElements())
1326 {
1327 String name = keys.nextElement();
1328 str += name + ", ";
1329 }
1330 return str;
1331 }
1332
1333 /**
1334 * this goes through each URL and adds in a session id if needed-- its
1335 * needed if the browser doesn't accept cookies also escapes things if
1336 * needed
1337 */
1338 protected void encodeURLs(Node dataNode, HttpServletResponse response)
1339 {
1340 if (dataNode == null)
1341 {
1342 return;
1343 }
1344
1345 Element data = null;
1346
1347 short nodeType = dataNode.getNodeType();
1348 if (nodeType == Node.DOCUMENT_NODE)
1349 {
1350 Document docNode = (Document) dataNode;
1351 data = docNode.getDocumentElement();
1352 }
1353 else
1354 {
1355 data = (Element) dataNode;
1356 }
1357
1358 if (data != null)
1359 {
1360
1361 // get all the <a> elements
1362 NodeList hrefs = data.getElementsByTagName("a");
1363 // Instead of calculating each iteration...
1364 int hrefscount = hrefs.getLength();
1365
1366 for (int i = 0; hrefs != null && i < hrefscount; i++)
1367 {
1368 Element a = (Element) hrefs.item(i);
1369 // ugly hack to get rid of : in the args - interferes with session handling
1370 String href = a.getAttribute("href");
1371 if (!href.equals(""))
1372 {
1373 if (href.indexOf("?") != -1)
1374 {
1375 String[] parts = StringUtils.split(href, "\\?", -1);
1376 if (parts.length == 1)
1377 {
1378 parts[0] = StringUtils.replace(parts[0], ":", "%3A");
1379 href = "?" + parts[0];
1380 }
1381 else
1382 {
1383 parts[1] = StringUtils.replace(parts[1], ":", "%3A");
1384 href = parts[0] + "?" + parts[1];
1385 }
1386
1387 }
1388 a.setAttribute("href", response.encodeURL(href));
1389 }
1390 }
1391
1392 // now find any submit bits - get all the <form> elements
1393 NodeList forms = data.getElementsByTagName("form");
1394 int formscount = forms.getLength();
1395 for (int i = 0; forms != null && i < formscount; i++)
1396 {
1397 Element form = (Element) forms.item(i);
1398 form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
1399 }
1400 // are these the only cases where URLs occur??
1401 // we should only do this for greenstone urls?
1402 }
1403
1404 }
1405
1406 protected String getFirstParam(String name, Map<String, String[]> map)
1407 {
1408 String[] val = map.get(name);
1409 if (val == null || val.length == 0)
1410 {
1411 return null;
1412 }
1413
1414 return val[0];
1415 }
1416
1417 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
1418 {
1419 //Check if we need to process a file upload
1420 if (ServletFileUpload.isMultipartContent(request))
1421 {
1422 DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
1423
1424 int sizeLimit = System.getProperties().containsKey("servlet.upload.filesize.limit") ? Integer.parseInt(System.getProperty("servlet.upload.filesize.limit")) : 100 * 1024 * 1024;
1425
1426 File tempDir = new File(GlobalProperties.getGSDL3Home() + File.separator + "tmp");
1427 if (!tempDir.exists())
1428 {
1429 tempDir.mkdirs();
1430 }
1431
1432 //We want all files to be stored on disk (hence the 0)
1433 fileItemFactory.setSizeThreshold(0);
1434 fileItemFactory.setRepository(tempDir);
1435
1436 ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
1437 uploadHandler.setFileSizeMax(sizeLimit);
1438
1439 HashMap<String, String[]> queryMap = new HashMap<String, String[]>();
1440 try
1441 {
1442 List items = uploadHandler.parseRequest(request);
1443 Iterator iter = items.iterator();
1444 while (iter.hasNext())
1445 {
1446 FileItem current = (FileItem) iter.next();
1447 if (current.isFormField())
1448 {
1449 queryMap.put(current.getFieldName(), new String[] { current.getString() });
1450 }
1451 else if (current.getName() != null && !current.getName().equals(""))
1452 {
1453 File file = new File(tempDir, current.getName());
1454 current.write(file);
1455
1456 queryMap.put("md___ex.Filesize", new String[] { "" + file.length() });
1457 queryMap.put("md___ex.Filename", new String[] { "" + current.getName() });
1458 }
1459 }
1460 }
1461 catch (Exception e)
1462 {
1463 e.printStackTrace();
1464 }
1465
1466 doGetOrPost(request, response, queryMap);
1467 }
1468 else
1469 {
1470 doGetOrPost(request, response, request.getParameterMap());
1471 }
1472 }
1473}
Note: See TracBrowser for help on using the repository browser.