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

Last change on this file since 33713 was 33713, checked in by kjdon, 4 years ago

refactoring LibraryServlet. runSecurityChecks was happening too late. it was doing login/logout but we had already checked login status before to fill in userContext, so userContext was not getting correct values for username. made several small methods out of runSecurityChecks, so they can be called at an appropriate time. userContext now holds all the info that userInformation does. can we get rid of userInformation and get everything to use userContext instead?

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