source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/Authentication.java@ 35303

Last change on this file since 35303 was 35303, checked in by anupama, 3 years ago
  1. In trying to hunt down where UserTermInfo's toString() and UserQueryResult's toString() get called and what value for groups they need to be displaying (expandedGroups or compactedGroups which is closest to user-entered data), found that UserQueryResult.users was public, despite there being a method getUserTerms() that returns this. So made it a private member and updated code to call the method at all times. In the end I didn't locate anywhere in the code that the aforementioned toString() methods got called, DerbyWrapper.java's db2txt() methods print out the fields direct from the DB in their own formatting, and is called by userDB2txt.java. At the moment, the code is set to print out the expandedGroups for the groups value of any UserTermInfo. 2. Fixed a bug due to oversight in UserTermInfo.java's compactGroups(String groups) and expandedGroups(String groups) to handle when groups is null. Returning empty string then, also used to initialise the compactedGroups and expandedGroups member vars.
File size: 47.0 KB
Line 
1package org.greenstone.gsdl3.service;
2
3import java.io.File;
4import java.io.Serializable;
5import java.math.BigInteger;
6import java.sql.SQLException;
7import java.util.ArrayList;
8import java.util.HashMap;
9import java.util.UUID;
10import java.util.Vector;
11import java.util.regex.Pattern;
12
13// for verifying recaptcha
14import java.io.BufferedReader;
15import java.io.DataOutputStream;
16import java.io.IOException;
17import java.io.InputStreamReader;
18import java.io.StringReader;
19import java.net.URL;
20import javax.net.ssl.HttpsURLConnection;
21// https://developer.android.com/reference/org/json/JSONObject.html
22// https://developer.android.com/reference/org/json/JSONArray.html
23import org.json.JSONArray;
24import org.json.JSONException;
25import org.json.JSONObject;
26
27import org.apache.commons.codec.digest.DigestUtils;
28import org.greenstone.gsdl3.util.DerbyWrapper;
29import org.greenstone.gsdl3.util.GSXML;
30import org.greenstone.gsdl3.util.UserQueryResult;
31import org.greenstone.gsdl3.util.UserTermInfo;
32import org.greenstone.gsdl3.util.XMLConverter;
33import org.greenstone.util.GlobalProperties;
34
35import org.w3c.dom.Document;
36import org.w3c.dom.Element;
37import org.w3c.dom.NodeList;
38
39public class Authentication extends ServiceRack
40{
41 //Some useful constants
42 protected static final int USERNAME_MIN_LENGTH = 2;
43 protected static final int USERNAME_MAX_LENGTH = 30;
44 protected static final int PASSWORD_MIN_LENGTH = 3;
45 protected static final int PASSWORD_MAX_LENGTH = 64;
46
47 //Error codes
48 public static final int NO_ERROR = 0;
49 protected static final int ERROR_NOT_LOGGED_IN = -1;
50 protected static final int ERROR_ADMIN_NOT_LOGGED_IN = -2;
51 protected static final int ERROR_COULD_NOT_GET_USER_INFO = -3;
52 protected static final int ERROR_USERNAME_NOT_SPECIFIED = -4;
53 protected static final int ERROR_USER_NOT_FOUND = -5;
54 protected static final int ERROR_USER_NOT_AUTHORISED = -6;
55 protected static final int ERROR_INVALID_USERNAME = -7;
56 protected static final int ERROR_USER_ALREADY_EXISTS = -8;
57 protected static final int ERROR_PASSWORD_NOT_ENTERED = -9;
58 protected static final int ERROR_PASSWORD_TOO_SHORT = -10;
59 protected static final int ERROR_PASSWORD_TOO_LONG = -11;
60 protected static final int ERROR_PASSWORD_USES_ILLEGAL_CHARACTERS = -12;
61 protected static final int ERROR_INCORRECT_PASSWORD = -13;
62 protected static final int ERROR_ADDING_USER = -14;
63 protected static final int ERROR_REMOVING_USER = -15;
64 protected static final int ERROR_CAPTCHA_FAILED = -16;
65 protected static final int ERROR_CAPTCHA_MISSING = -17;
66 protected static final int ERROR_CONNECTION_FAILED = -18;
67 protected static final int ERROR_MISSING_PARAMS = -19;
68 protected static final int ERROR_SOMETHING_WRONG = -20;
69
70 // recaptcha
71 protected static final HashMap<Integer, String> _errorKeyMap;
72 static
73 {
74 //Corresponding error message keys for looking up in ServiceRack dictionary
75 HashMap<Integer, String> errorKeyMap = new HashMap<Integer, String>();
76 errorKeyMap.put(ERROR_NOT_LOGGED_IN, "auth.error.not_logged_in");
77 errorKeyMap.put(ERROR_ADMIN_NOT_LOGGED_IN, "auth.error.admin_not_logged_in");
78 errorKeyMap.put(ERROR_COULD_NOT_GET_USER_INFO, "auth.error.could_not_get_user_info");
79 errorKeyMap.put(ERROR_USERNAME_NOT_SPECIFIED, "auth.error.username_not_specified");
80 errorKeyMap.put(ERROR_USER_NOT_FOUND, "auth.error.user_not_found");
81 errorKeyMap.put(ERROR_USER_NOT_AUTHORISED, "auth.error.not_authorised");
82 errorKeyMap.put(ERROR_INVALID_USERNAME, "auth.error.invalid_username");
83 errorKeyMap.put(ERROR_USER_ALREADY_EXISTS, "auth.error.user_already_exists");
84 errorKeyMap.put(ERROR_PASSWORD_NOT_ENTERED, "auth.error.no_password");
85 errorKeyMap.put(ERROR_PASSWORD_TOO_SHORT, "auth.error.password_too_short");
86 errorKeyMap.put(ERROR_PASSWORD_TOO_LONG, "auth.error.password_too_long");
87 errorKeyMap.put(ERROR_PASSWORD_USES_ILLEGAL_CHARACTERS, "auth.error.password_illegal_chars");
88 errorKeyMap.put(ERROR_INCORRECT_PASSWORD, "auth.error.incorrect_password");
89 errorKeyMap.put(ERROR_ADDING_USER, "auth.error.add_user_error");
90 errorKeyMap.put(ERROR_REMOVING_USER, "auth.error.remove_user_error");
91 errorKeyMap.put(ERROR_CAPTCHA_FAILED, "auth.error.captcha_failed");
92 errorKeyMap.put(ERROR_CAPTCHA_MISSING, "auth.error.captcha_missing");
93 errorKeyMap.put(ERROR_CONNECTION_FAILED, "auth.error.connection_failed");
94
95 errorKeyMap.put(ERROR_MISSING_PARAMS, "auth.error.missing_params"); // ???
96 errorKeyMap.put(ERROR_SOMETHING_WRONG, "auth.error.something_wrong");
97 _errorKeyMap = errorKeyMap;
98 }
99
100 //Admin-required operations
101 protected static final String LIST_USERS = "ListUsers";
102 protected static final String PERFORM_ADD = "PerformAdd";
103 protected static final String PERFORM_EDIT = "PerformEdit";
104 protected static final String ADD_USER = "AddUser";
105 protected static final String EDIT_USER = "EditUser";
106 protected static final String PERFORM_DELETE_USER = "PerformDeleteUser";
107
108 protected static final ArrayList<String> _adminOpList;
109 static
110 {
111 ArrayList<String> opList = new ArrayList<String>();
112 opList.add(LIST_USERS);
113 opList.add(PERFORM_ADD);
114 opList.add(PERFORM_EDIT);
115 opList.add(ADD_USER);
116 opList.add(EDIT_USER);
117 opList.add(PERFORM_DELETE_USER);
118
119 _adminOpList = opList;
120 }
121
122 //User-required operations
123 protected static final String ACCOUNT_SETTINGS = "AccountSettings";
124 protected static final String PERFORM_ACCOUNT_EDIT = "PerformAccEdit";
125 protected static final String PERFORM_RESET_PASSWORD = "PerformResetPassword";
126 protected static final String PERFORM_CHANGE_PASSWORD = "PerformChangePassword";
127 protected static final String PERFORM_RETRIEVE_PASSWORD = "PerformRetrievePassword";
128 protected static final ArrayList<String> _userOpList;
129 static
130 {
131 ArrayList<String> opList = new ArrayList<String>();
132 opList.add(ACCOUNT_SETTINGS);
133 opList.add(PERFORM_ACCOUNT_EDIT);
134 opList.add(PERFORM_RESET_PASSWORD);
135 opList.add(PERFORM_CHANGE_PASSWORD);
136 opList.add(PERFORM_RETRIEVE_PASSWORD);
137 opList.addAll(_adminOpList);
138 _userOpList = opList;
139 }
140
141 //Other operations
142 protected static final String REGISTER = "Register"; // displays the register page
143 protected static final String PERFORM_REGISTER = "PerformRegister"; // performs the registration action
144 protected static final String LOGIN = "Login";
145 protected static final String BLANK = "Info"; // a dummy page just for showing an error message
146
147 //the services on offer
148 public static final String AUTHENTICATION_SERVICE = "Authentication";
149 protected static final String GET_USER_INFORMATION_SERVICE = "GetUserInformation";
150 protected static final String CHANGE_USER_EDIT_MODE_SERVICE = "ChangeUserEditMode";
151 protected static final String REMOTE_AUTHENTICATION_SERVICE = "RemoteAuthentication";
152
153 protected static boolean _derbyWrapperDoneForcedShutdown = false;
154
155 // some XML strings
156 protected static final String RECAPTCHA_ELEM = "recaptcha";
157 protected static final String SITE_KEY = "site_key";
158 protected static final String SECRET_KEY = "secret_key";
159 protected static final String OPERATIONS = "operations";
160 protected static final String OPERATION = "operation";
161 protected static final String USERNAME = "username";
162 protected static final String PASSWORD = "password";
163 protected static final String COLLECTION = "collection";
164 protected static final String GROUPS = "groups";
165 protected static final String COMPACTED_GROUPS = "compacted_groups";
166 protected static final String EXPANDED_GROUPS = "expanded_groups";
167 protected static final String STATUS = "status";
168 protected static final String RECAPTCHA_KEY = "recaptcha_key";
169 protected static final String COMMENT = "comment";
170 protected static final String EMAIL = "email";
171
172 // cgi params
173 protected static final String USERNAME_PARAM = "username";
174 protected static final String PREV_USERNAME_PARAM = "prevUsername";
175 protected static final String NEW_USERNAME_PARAM = "newUsername";
176 protected static final String PASSWORD_PARAM = "password";
177 protected static final String OLD_PASSWORD_PARAM = "oldPassword";
178 protected static final String NEW_PASSWORD_PARAM = "newPassword";
179 protected static final String GROUPS_PARAM = "groups";
180 protected static final String ENABLED_PARAM = "enabled";
181 protected static final String COMMENT_PARAM = "comment";
182 protected static final String STATUS_PARAM = "status";
183 protected static final String EMAIL_PARAM = "email";
184 protected static final String NEW_EMAIL_PARAM = "newEmail";
185 protected static final String ACCOUNT_STATUS_PARAM = "accountstatus";
186 protected static final String EDIT_ENABLED_PARAM = "editEnabled";
187 protected static final String AUTHPAGE_PARAM = "authpage";
188 public static final String RECAPTCHA_RESPONSE_PARAM = "g-recaptcha-response";
189
190 protected String _recaptchaSiteKey = null;
191 protected String _recaptchaSecretKey = null;
192 protected static ArrayList<String> _recaptchaOpList = null;
193 /** constructor */
194 public Authentication()
195 {
196 }
197
198 public void cleanUp()
199 {
200 super.cleanUp();
201
202 if (!_derbyWrapperDoneForcedShutdown)
203 {
204
205 // This boolean is used to ensure we always shutdown the derby server, even if it is never
206 // used by the Authentication server. This is because the Tomcat greenstone3.xml
207 // config file also specifies a connection to the database, which can result in the
208 // server being initialized when the servlet is first accessed. Note also,
209 // Authentication is a ServiceRack, meaning cleanUp() is called for each service
210 // supported, however we only need to shutdown the Derby server once. Again
211 // this boolean variable helps achieve this.
212
213 logger.info("Authentication Service performing forced shutdown of Derby Server ...");
214
215 DerbyWrapper.shutdownDatabaseServer();
216 _derbyWrapperDoneForcedShutdown = true;
217 }
218 }
219
220 public boolean configure(Element info, Element extra_info)
221 {
222 logger.info("Configuring Authentication...");
223 this.config_info = info;
224
225 // set up Authentication service info - for now just has name and type
226 Element authentication_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
227 authentication_service.setAttribute(GSXML.TYPE_ATT, "authen");
228 authentication_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
229 this.short_service_info.appendChild(authentication_service);
230
231 Element getUserInformation_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
232 getUserInformation_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
233 getUserInformation_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
234 this.short_service_info.appendChild(getUserInformation_service);
235
236 Element changeEditMode_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
237 changeEditMode_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
238 changeEditMode_service.setAttribute(GSXML.NAME_ATT, CHANGE_USER_EDIT_MODE_SERVICE);
239 this.short_service_info.appendChild(changeEditMode_service);
240
241 Element remoteAuthentication_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
242 remoteAuthentication_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
243 remoteAuthentication_service.setAttribute(GSXML.NAME_ATT, REMOTE_AUTHENTICATION_SERVICE);
244 this.short_service_info.appendChild(remoteAuthentication_service);
245
246 DerbyWrapper.createDatabaseIfNeeded();
247
248 NodeList recaptchaElems = info.getElementsByTagName(RECAPTCHA_ELEM);
249 for (int i = 0; i < recaptchaElems.getLength(); i++)
250 {
251 Element currentElem = (Element) recaptchaElems.item(i);
252 if (currentElem.getAttribute(GSXML.NAME_ATT).equals(SITE_KEY))
253 {
254 if (!currentElem.getAttribute(GSXML.VALUE_ATT).equals(""))
255 {
256 _recaptchaSiteKey = currentElem.getAttribute(GSXML.VALUE_ATT);
257 }
258 }
259 else if (currentElem.getAttribute(GSXML.NAME_ATT).equals(SECRET_KEY))
260 {
261 if (!currentElem.getAttribute(GSXML.VALUE_ATT).equals(""))
262 {
263 _recaptchaSecretKey = currentElem.getAttribute(GSXML.VALUE_ATT);
264 }
265 }
266 else if (currentElem.getAttribute(GSXML.NAME_ATT).equals(OPERATIONS))
267 {
268 _recaptchaOpList = new ArrayList<String>();
269 String value = currentElem.getAttribute(GSXML.VALUE_ATT);
270 String[] ops = value.split(",");
271 for (int j=0; j<ops.length; j++) {
272 if (!ops[j].equals("")) {
273 _recaptchaOpList.add(ops[j]); /// value checking?
274 }
275 }
276 }
277
278 }
279 // check recaptcha
280 if (_recaptchaSecretKey == null || _recaptchaSecretKey.length() == 0 || _recaptchaSiteKey == null || _recaptchaSiteKey.length() == 0) {
281 _recaptchaSecretKey = null;
282 _recaptchaSiteKey = null;
283 _recaptchaOpList = null;
284 }
285
286 // while all of our params are "not saved" for the session, a few of them are also sensitive, so should not be listed in the page response XML
287 this.sensitive_params.add(PASSWORD_PARAM);
288 this.sensitive_params.add(NEW_PASSWORD_PARAM);
289 this.sensitive_params.add(OLD_PASSWORD_PARAM);
290 this.sensitive_params.add(RECAPTCHA_RESPONSE_PARAM);
291
292
293
294 return true;
295 }
296
297 public String getRecaptchaSiteKey() {
298 return _recaptchaSiteKey;
299 }
300
301 public String getRecaptchaSecretKey() {
302
303 return _recaptchaSecretKey;
304 }
305 protected Element getServiceDescription(Document doc, String service_id, String lang, String subset)
306 {
307
308 Element authen_service = doc.createElement(GSXML.SERVICE_ELEM);
309
310 if (service_id.equals(AUTHENTICATION_SERVICE))
311 {
312 authen_service.setAttribute(GSXML.TYPE_ATT, "authen");
313 authen_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
314 }
315 else if (service_id.equals(GET_USER_INFORMATION_SERVICE))
316 {
317 authen_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
318 authen_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
319 }
320 else if (service_id.equals(CHANGE_USER_EDIT_MODE_SERVICE))
321 {
322 authen_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
323 authen_service.setAttribute(GSXML.NAME_ATT, CHANGE_USER_EDIT_MODE_SERVICE);
324 }
325 else if (service_id.equals(REMOTE_AUTHENTICATION_SERVICE))
326 {
327 authen_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
328 authen_service.setAttribute(GSXML.NAME_ATT, REMOTE_AUTHENTICATION_SERVICE);
329 }
330 else
331 {
332 return null;
333 }
334
335 if (service_id.equals(AUTHENTICATION_SERVICE) && (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER)))
336 {
337 authen_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(service_id, lang)));
338 authen_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(service_id, lang)));
339 }
340 return authen_service;
341 }
342
343 protected String getServiceName(String service_id, String lang)
344 {
345 return getTextString(service_id + ".name", lang);
346 }
347
348 protected String getServiceSubmit(String service_id, String lang)
349 {
350 return getTextString(service_id + ".submit", lang);
351 }
352
353 protected String getServiceDescription(String service_id, String lang)
354 {
355 return getTextString(service_id + ".description", lang);
356 }
357 protected String getErrorTextString(int error_code, String lang) {
358 return getTextString(_errorKeyMap.get(error_code), lang);
359
360 }
361 public static String getErrorKey(int error_code) {
362
363 return _errorKeyMap.get(error_code);
364 }
365 protected Element processChangeUserEditMode(Element request)
366 {
367 // Create a new (empty) result message
368 Document result_doc = XMLConverter.newDOM();
369 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
370
371 result.setAttribute(GSXML.FROM_ATT, CHANGE_USER_EDIT_MODE_SERVICE);
372 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
373
374 Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
375 if (paramList == null)
376 {
377 logger.error("ChangeUserEditMode request has no param list!!");
378 return result;
379 }
380
381 HashMap<String, Serializable> params = GSXML.extractParams(paramList, true);
382
383 String username = (String) params.get(USERNAME_PARAM);
384 String editMode = (String) params.get(ENABLED_PARAM);
385
386 if (!editMode.toLowerCase().equals("true") && !editMode.toLowerCase().equals("false"))
387 {
388 editMode = "false";
389 }
390
391 DerbyWrapper dw = openDatabase();
392 dw.addUserData(username, "USER_EDIT_ENABLED", editMode);
393 dw.closeDatabase();
394
395 return result;
396 }
397
398 /**
399 * This method replaces the gliserver.pl code for authenticating a user against the derby database
400 * gliserver.pl needed to instantiate its own JVM to access the derby DB, but the GS3 already has
401 * the Derby DB open and 2 JVMs are not allowed concurrent access to an open embedded Derby DB.
402 * Gliserver.pl now goes through this method (via ServletRealmCheck.java), thereby using the same
403 * connection to the DerbyDB. This method reproduces the same behaviour as gliserver.pl used to,
404 * by returning the user_groups on successful authentication, else returns the specific
405 * "Authentication failed" messages that gliserver.pl would produce.
406 * http://remote-host-name:8383/greenstone3/library?a=s&sa=authenticated-ping&excerptid=gs_content&un=admin&pw=<PW>&col=demo
407 */
408 protected Element processRemoteAuthentication(Element request) {
409 //logger.info("*** Authentication::processRemoteAuthentication");
410
411 String message = "";
412
413 Element system = (Element) GSXML.getChildByTagName(request, GSXML.REQUEST_TYPE_SYSTEM);
414 String username = system.hasAttribute(USERNAME) ? system.getAttribute(USERNAME) : "";
415 String password = system.hasAttribute(PASSWORD) ? system.getAttribute(PASSWORD) : "";
416
417
418 // If we're not editing a collection then the user doesn't need to be in a particular group
419 String collection = system.hasAttribute(COLLECTION) ? system.getAttribute(COLLECTION) : "";
420
421
422 if(username.equals("") || password.equals("")) {
423 message = "Authentication failed: no (username or) password specified.";
424 //logger.error("*** Remote login failed. No username or pwd provided");
425 }
426 else {
427 String storedPassword = retrieveDataForUser(username, PASSWORD);
428 if(storedPassword != null && (password.equals(storedPassword) || hashPassword(password).equals(storedPassword))) {
429
430 // gliserver.pl used to return the groups when authentication succeeded
431 String groups = retrieveDataForUser(username, EXPANDED_GROUPS); //comma-separated list
432
433 if(collection.equals("")) {
434 message = groups;
435 } else {
436
437 if(groups.indexOf("all-collections-editor") != -1) { // Does this user have access to all collections?
438 message = groups;
439 } else if(groups.indexOf("personal-collections-editor") != -1 && collection.startsWith(username+"-")) { // Does this user have access to personal collections, and is this one?
440 message = groups;
441 } else if(groups.indexOf(collection+"-collection-editor") != -1) { // Does this user have access to this collection?
442 message = groups;
443 }
444 else {
445 message = "Authentication failed: user is not in the required group.";
446 //logger.error("*** Remote login failed. Groups did not match for the collection specified");
447 }
448 }
449
450 } else {
451
452 if(storedPassword == null) {
453 message = "Authentication failed: no account for user '" + username + "'";
454 //logger.error("*** Remote login failed. User not found or password not set for user.");
455 } else {
456 message = "Authentication failed: incorrect password.";
457 //logger.error("*** Remote login failed. Password did not match for user");
458 }
459 }
460 }
461 Document result_doc = XMLConverter.newDOM();
462 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
463 result.setAttribute(GSXML.FROM_ATT, REMOTE_AUTHENTICATION_SERVICE);
464 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
465 Element s = GSXML.createTextElement(result_doc, GSXML.STATUS_ELEM, message);
466 result.appendChild(s);
467 return result;
468 }
469
470 protected Element processGetUserInformation(Element request)
471 {
472 // Create a new (empty) result message
473 Document result_doc = XMLConverter.newDOM();
474 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
475
476 result.setAttribute(GSXML.FROM_ATT, GET_USER_INFORMATION_SERVICE);
477 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
478
479 String lang = request.getAttribute(GSXML.LANG_ATT);
480 Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
481 if (paramList == null)
482 {
483 logger.error("GetUserInformation request has no param list");
484 return result;
485 }
486
487 HashMap<String, Serializable> params = GSXML.extractParams(paramList, true);
488
489 String username = (String) params.get(USERNAME_PARAM);
490
491 if (username == null)
492 {
493 GSXML.addError(result, getErrorTextString(ERROR_USERNAME_NOT_SPECIFIED, lang));
494 return result;
495 }
496
497 DerbyWrapper derbyWrapper = openDatabase();
498
499 UserQueryResult userQueryResult = derbyWrapper.findUser(username);
500 String editEnabled = derbyWrapper.getUserData(username, "USER_EDIT_ENABLED");
501
502 Vector<UserTermInfo> terms = userQueryResult.getUserTerms();
503
504 if (terms.size() == 0)
505 {
506 GSXML.addError(result, getErrorTextString(ERROR_USER_NOT_FOUND, lang));
507 return result;
508 }
509
510 UserTermInfo userInfo = terms.get(0);
511 Element userInfoList = result_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
512 result.appendChild(userInfoList);
513
514 Element usernameField = GSXML.createParameter(result_doc, USERNAME_PARAM, userInfo.getUsername());
515 Element passwordField = GSXML.createParameter(result_doc, PASSWORD_PARAM, userInfo.getPassword());
516 Element groupsField = GSXML.createParameter(result_doc, GROUPS_PARAM, userInfo.getExpandedGroups()); // used by LibraryServlet that calls the containing method
517 Element accountStatusField = GSXML.createParameter(result_doc, ACCOUNT_STATUS_PARAM, userInfo.getAccountStatus());
518 Element commentField = GSXML.createParameter(result_doc, COMMENT_PARAM, userInfo.getComment());
519
520 if (editEnabled != null)
521 {
522 Element editEnabledElem = GSXML.createParameter(result_doc, EDIT_ENABLED_PARAM, editEnabled);
523 userInfoList.appendChild(editEnabledElem);
524 }
525
526 userInfoList.appendChild(usernameField);
527 userInfoList.appendChild(passwordField);
528 userInfoList.appendChild(groupsField);
529 userInfoList.appendChild(accountStatusField);
530 userInfoList.appendChild(commentField);
531
532 derbyWrapper.closeDatabase();
533
534 return result;
535 }
536
537 protected Element processAuthentication(Element request)
538 {
539 checkAdminUserExists();
540
541 // Create a new (empty) result message
542 Document result_doc = XMLConverter.newDOM();
543 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
544 result.setAttribute(GSXML.FROM_ATT, AUTHENTICATION_SERVICE);
545 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
546
547 // Create an Authentication node put into the result
548 Element authenNode = result_doc.createElement(GSXML.AUTHEN_NODE_ELEM);
549 result.appendChild(authenNode);
550 result.appendChild(getCollectList(result_doc, this.site_home + File.separatorChar + "collect"));
551
552 // Create a service node added into the Authentication node
553 Element serviceNode = result_doc.createElement(GSXML.SERVICE_ELEM);
554 authenNode.appendChild(serviceNode);
555
556 // Get the parameters of the request
557 String lang = request.getAttribute(GSXML.LANG_ATT);
558 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
559 if (param_list == null)
560 {
561 serviceNode.setAttribute(OPERATION, BLANK);
562 logger.error("Authentication request has no param list");
563 return result; // Return the empty result
564 }
565 HashMap<String, Serializable> paramMap = GSXML.extractParams(param_list, false);
566 String op = (String) paramMap.get(AUTHPAGE_PARAM);
567 serviceNode.setAttribute(OPERATION, op);
568
569 String username = null;
570 String groups = null;
571
572 Element userInformation = (Element) GSXML.getChildByTagName(request, GSXML.USER_INFORMATION_ELEM);
573 if (userInformation != null)
574 {
575 username = userInformation.getAttribute(GSXML.USERNAME_ATT);
576 groups = userInformation.getAttribute(GSXML.GROUPS_ATT);
577 }
578 logger.debug("username="+username+", groups = "+groups);
579 logger.debug("expandedGroups would be: "+UserTermInfo.expandGroups(groups));
580 logger.debug("compactedGroups would be: "+UserTermInfo.compactGroups(groups));
581
582 if ((userInformation == null || username == null) && _userOpList.contains(op))
583 {
584 // its an operation that requires the user to be logged on - direct them to login page
585 serviceNode.setAttribute(OPERATION, LOGIN);
586 if (_recaptchaOpList != null && _recaptchaOpList.contains(LOGIN)) {
587 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
588 }
589 GSXML.addError(result, getErrorTextString(ERROR_NOT_LOGGED_IN, lang));
590 return result;
591 }
592
593 if (_adminOpList.contains(op) && (groups == null || !groups.matches(".*\\badministrator\\b.*")))
594 {
595 // actually, the user needs to be an admin user and they are not
596 serviceNode.setAttribute(OPERATION, LOGIN);
597 if (_recaptchaOpList != null && _recaptchaOpList.contains(LOGIN)) {
598 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
599 }
600 GSXML.addError(result, getErrorTextString(ERROR_ADMIN_NOT_LOGGED_IN, lang));
601 return result;
602 }
603
604 if (_recaptchaOpList != null && _recaptchaOpList.contains(op)) {
605 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
606 }
607
608 if (op.equals(LIST_USERS))
609 {
610 int error = addUserInformationToNode(null, serviceNode);
611 if (error != NO_ERROR)
612 {
613 serviceNode.setAttribute(OPERATION, BLANK);
614 GSXML.addError(result, getErrorTextString(error, lang));
615 }
616 return result;
617
618 }
619
620 if (op.equals(PERFORM_ADD))
621 {
622 String newUsername = (String) paramMap.get(USERNAME_PARAM);
623 String newPassword = (String) paramMap.get(PASSWORD_PARAM);
624 String newGroups = (String) paramMap.get(GROUPS_PARAM);
625 String newStatus = (String) paramMap.get(STATUS_PARAM);
626 String newComment = (String) paramMap.get(COMMENT_PARAM);
627 String newEmail = (String) paramMap.get(EMAIL_PARAM);
628
629 if (_recaptchaOpList != null && _recaptchaOpList.contains(ADD_USER)) {
630 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
631 }
632 //Check the given user name
633 int error;
634 if (checkUserExists(newUsername)) {
635 error = ERROR_USER_ALREADY_EXISTS;
636 } else {
637 error = checkUsername(newUsername);
638 }
639 if (error != NO_ERROR)
640 {
641 serviceNode.setAttribute(OPERATION, ADD_USER);
642 GSXML.addError(result, getErrorTextString(error, lang));
643 return result;
644 }
645
646 //Check the given password
647 if ((error = checkPassword(newPassword)) != NO_ERROR)
648 {
649 serviceNode.setAttribute(OPERATION, ADD_USER);
650 GSXML.addError(result, getErrorTextString(error, lang));
651 return result;
652 }
653
654 newPassword = hashPassword(newPassword);
655
656 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
657 if (error != NO_ERROR)
658 {
659 serviceNode.setAttribute(OPERATION, ADD_USER);
660 GSXML.addError(result, getErrorTextString(error, lang));
661 }
662 else
663 {
664 addUserInformationToNode(null, serviceNode);
665 serviceNode.setAttribute(OPERATION, LIST_USERS);
666 }
667 return result;
668 }
669
670 if (op.equals(REGISTER)) {
671 // don't need any additional info
672 return result;
673 }
674 if (op.equals(PERFORM_REGISTER))
675 {
676 String newUsername = (String) paramMap.get(USERNAME_PARAM);
677 String newPassword = (String) paramMap.get(PASSWORD_PARAM);
678 String newEmail = (String) paramMap.get(EMAIL_PARAM);
679
680 //Check the given details
681 int error;
682 if (checkUserExists(newUsername)) {
683 error = ERROR_USER_ALREADY_EXISTS;
684 } else {
685 error = checkUsername(newUsername);
686 }
687 if (error == NO_ERROR) {
688 if ((error = checkPassword(newPassword)) == NO_ERROR) {
689 newPassword = hashPassword(newPassword);
690 if (_recaptchaOpList != null && _recaptchaOpList.contains(REGISTER)) {
691 String user_response = (String) paramMap.get(RECAPTCHA_RESPONSE_PARAM);
692 if ((error= verifyRecaptcha(_recaptchaSecretKey, user_response)) == NO_ERROR) {
693 error = addUser(newUsername, newPassword, "", "true", "", newEmail);
694 }
695 }
696 }
697 }
698
699 if (error != NO_ERROR)
700 {
701 serviceNode.setAttribute(OPERATION, REGISTER);
702 if (_recaptchaOpList != null && _recaptchaOpList.contains(REGISTER)) {
703 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
704 }
705 GSXML.addError(result, getErrorTextString(error, lang));
706 }
707 // otherwise everything hunky dory and we return result
708 return result;
709 }
710
711 // PERFORM_EDIT is caled when admin is running EditUser, and PERFORM_ACCOUNT_EDIT is called when a user is running AccountSettings to change their own details
712 if (op.equals(PERFORM_EDIT) || op.equals(PERFORM_ACCOUNT_EDIT)) {
713
714 String parent_op = EDIT_USER;
715 if (op.equals(PERFORM_ACCOUNT_EDIT)) {
716 parent_op = ACCOUNT_SETTINGS;
717 }
718 String previousUsername = (String) paramMap.get(PREV_USERNAME_PARAM);
719 String newUsername = (String) paramMap.get(NEW_USERNAME_PARAM);
720 int error;
721 // Has the user name been changed? Make sure it doesn't already exist and is a valid username
722 if (previousUsername == null) {
723 // we have ended up here by mistake (via s1.authpage which is no longer valid)
724 serviceNode.setAttribute(OPERATION, BLANK);
725 GSXML.addError(result, getErrorTextString(ERROR_SOMETHING_WRONG, lang));
726 return result;
727 }
728
729 if (!previousUsername.equals(newUsername)) {
730
731 error = NO_ERROR;
732 if (checkUserExists(newUsername)) {
733 error = ERROR_USER_ALREADY_EXISTS;
734 } else {
735 error = checkUsername(newUsername);
736 }
737 if (error != NO_ERROR) {
738 addUserInformationToNode(previousUsername, serviceNode);
739 serviceNode.setAttribute(OPERATION, parent_op);
740 GSXML.addError(result, getErrorTextString(error, lang));
741 return result;
742 }
743 }
744
745 // password checking
746 String newPassword;
747 if (op.equals(PERFORM_EDIT)) {
748 newPassword = (String) paramMap.get(PASSWORD_PARAM);
749 } else {
750 newPassword = (String) paramMap.get(NEW_PASSWORD_PARAM);
751 }
752 if (newPassword == null) {
753 // we are not changing the password
754 newPassword = retrieveDataForUser(previousUsername, PASSWORD);
755 } else {
756 // we need to check the old one
757 if (op.equals(PERFORM_ACCOUNT_EDIT)) {
758 // check that they entered their old password correctly
759 String prevPassword = retrieveDataForUser(previousUsername, PASSWORD);
760 String oldPassword = (String) paramMap.get(OLD_PASSWORD_PARAM);
761 oldPassword = hashPassword(oldPassword);
762 if (oldPassword == null || !oldPassword.equals(prevPassword)) {
763
764 addUserInformationToNode(previousUsername, serviceNode);
765 serviceNode.setAttribute(OPERATION, ACCOUNT_SETTINGS);
766 GSXML.addError(result, getErrorTextString(ERROR_INCORRECT_PASSWORD, lang), "INCORRECT_PASSWORD");
767 return result;
768 }
769 }
770 // need to make sure the new password is a valid password
771 if ((error = checkPassword(newPassword)) != NO_ERROR) {
772
773 addUserInformationToNode(previousUsername, serviceNode);
774 serviceNode.setAttribute(OPERATION, parent_op);
775 GSXML.addError(result, getErrorTextString(error, lang));
776 return result;
777 }
778 newPassword = hashPassword(newPassword);
779
780 }
781
782 // are we using recaptcha for AccountSettings or EditUser?
783 if (_recaptchaOpList != null && _recaptchaOpList.contains(parent_op)) {
784 String user_response = (String) paramMap.get(RECAPTCHA_RESPONSE_PARAM);
785 if ((error= verifyRecaptcha(_recaptchaSecretKey, user_response)) != NO_ERROR) {
786 addUserInformationToNode(previousUsername, serviceNode);
787 serviceNode.setAttribute(OPERATION, parent_op);
788 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
789 GSXML.addError(result, getErrorTextString(error, lang));
790 return result;
791 }
792 }
793
794 groups = null; // doesn't matter if local groups var keeps value in compactedGroups or expandedGroups form,
795 // as addUser() and addUserInformationToNode() will ensure use of expanded and compacted forms respectively
796 String status = null;
797 String comment = null;
798 String email = (String) paramMap.get(NEW_EMAIL_PARAM);
799 if (op.equals(PERFORM_EDIT)) {
800 groups = (String) paramMap.get(GROUPS_PARAM);
801 status = (String) paramMap.get(STATUS_PARAM);
802 comment = (String) paramMap.get(COMMENT_PARAM);
803
804 } else {
805 groups = retrieveDataForUser(previousUsername, EXPANDED_GROUPS);
806 status = retrieveDataForUser(previousUsername, STATUS);
807 comment = retrieveDataForUser(previousUsername, COMMENT);
808 }
809
810
811 error = removeUser(previousUsername);
812 if (error != NO_ERROR) {
813 addUserInformationToNode(previousUsername, serviceNode);
814 serviceNode.setAttribute(OPERATION, parent_op);
815 GSXML.addError(result, getErrorTextString(error, lang));
816 return result;
817 }
818
819 error = addUser(newUsername, newPassword, groups, status, comment, email);
820 if (error != NO_ERROR) {
821
822 // oh dear. we have removed previous data, but were unable to add new data. The user is now gone :-(
823 serviceNode.setAttribute(OPERATION, BLANK);
824 GSXML.addError(result, getErrorTextString(error, lang));
825 }
826 else {
827 if (op.equals(PERFORM_ACCOUNT_EDIT)) {
828 addUserInformationToNode(newUsername, serviceNode);
829 serviceNode.setAttribute(OPERATION, parent_op);
830 if (_recaptchaOpList != null && _recaptchaOpList.contains(parent_op)) {
831 serviceNode.setAttribute(RECAPTCHA_KEY, _recaptchaSiteKey);
832 }
833 GSXML.addError(result, getTextString("auth.success.account_settings", lang));
834
835 } else {
836
837 addUserInformationToNode(null, serviceNode);
838 serviceNode.setAttribute(OPERATION, LIST_USERS);
839 String [] args = {newUsername};
840 GSXML.addError(result, getTextString("auth.success.edit_user", lang, args));
841 }
842
843 }
844 return result;
845 }
846 if (op.equals(PERFORM_RETRIEVE_PASSWORD))
847 {
848 return result;
849 }
850 if (op.equals(PERFORM_CHANGE_PASSWORD))
851 {
852 serviceNode.setAttribute(OPERATION, PERFORM_CHANGE_PASSWORD);
853 String user_name = (String) paramMap.get(USERNAME_PARAM);
854 String oldPassword = (String) paramMap.get(OLD_PASSWORD_PARAM);
855 String newPassword = (String) paramMap.get(NEW_PASSWORD_PARAM);
856 if (user_name == null || oldPassword == null || newPassword == null)
857 {
858 GSXML.addError(result, getErrorTextString(ERROR_MISSING_PARAMS, lang));
859 return result;
860 }
861
862 String prevPassword = retrieveDataForUser(user_name, PASSWORD);
863 if (!hashPassword(oldPassword).equals(prevPassword))
864 {
865 addUserInformationToNode(user_name, serviceNode);
866 GSXML.addError(result, getErrorTextString(ERROR_INCORRECT_PASSWORD, lang), "INCORRECT_PASSWORD");
867 return result;
868 }
869
870 //Check the given password
871 int error;
872 if ((error = checkPassword(newPassword)) != NO_ERROR)
873 {
874 GSXML.addError(result, getErrorTextString(error, lang));
875 return result;
876 }
877
878 DerbyWrapper derbyWrapper = openDatabase();
879 String chpa_groups = retrieveDataForUser(user_name, EXPANDED_GROUPS); // userDB now stores expandedGroups, not compactedGroups
880 String chpa_comment = "password_changed_by_user";
881 String info = derbyWrapper.modifyUserInfo(user_name, hashPassword(newPassword), chpa_groups, null, chpa_comment, null);
882 derbyWrapper.closeDatabase();
883 if (info != "succeed")
884 {//see DerbyWrapper.modifyUserInfo
885 GSXML.addError(result, info);
886 return result;
887 }
888 return result;
889 }
890 if (op.equals(EDIT_USER))
891 {
892 String editUsername = (String) paramMap.get(USERNAME_PARAM);
893 int error = addUserInformationToNode(editUsername, serviceNode);
894 if (error != NO_ERROR)
895 {
896 GSXML.addError(result, getErrorTextString(error, lang));
897 }
898 return result;
899 }
900 if (op.equals(ACCOUNT_SETTINGS))
901 {
902 String editUsername = (String) paramMap.get(USERNAME_PARAM);
903
904 if (editUsername == null)
905 {
906 serviceNode.setAttribute(OPERATION, "");
907 GSXML.addError(result, getErrorTextString(ERROR_USERNAME_NOT_SPECIFIED, lang));
908 return result;
909 }
910
911 if (!editUsername.equals(username))
912 {
913 serviceNode.setAttribute(OPERATION, LOGIN);
914 GSXML.addError(result, getErrorTextString(ERROR_USER_NOT_AUTHORISED, lang));
915 return result;
916 }
917 int error = addUserInformationToNode(editUsername, serviceNode);
918 if (error != NO_ERROR)
919 {
920 GSXML.addError(result, getErrorTextString(error, lang));
921 }
922 return result;
923 }
924 if (op.equals(PERFORM_RESET_PASSWORD))
925 {
926 String passwordResetUser = (String) paramMap.get(USERNAME_PARAM);
927
928 String newPassword = UUID.randomUUID().toString();
929 newPassword = newPassword.substring(0, newPassword.indexOf("-"));
930
931 String email = retrieveDataForUser(passwordResetUser, EMAIL);
932 String from = "[email protected]";
933 String host = request.getAttribute("remoteAddress");
934
935 //TODO: FINISH THIS
936 return result;
937 }
938 if (op.equals(PERFORM_DELETE_USER))
939 {
940 String usernameToDelete = (String) paramMap.get(USERNAME_PARAM);
941 int error = removeUser(usernameToDelete);
942 if (error != NO_ERROR)
943 {
944 GSXML.addError(result, getErrorTextString(error, lang));
945 }
946 addUserInformationToNode(null, serviceNode);
947 serviceNode.setAttribute(OPERATION, LIST_USERS);
948 String[] args = {usernameToDelete};
949 GSXML.addError(result, getTextString("auth.success.delete_user", lang, args));
950 return result;
951 }
952
953 return result; // or should we return null, as we haven't recognised the operation??
954 }
955
956 public int checkUsernameAndPassword(String username, String password)
957 {
958 int uResult = checkUsername(username);
959 int pResult = checkPassword(password);
960
961 return (uResult != NO_ERROR ? uResult : (pResult != NO_ERROR ? pResult : NO_ERROR));
962 }
963
964 public int checkUsername(String username)
965 {
966 //Check the given user name
967 if ((username == null) || (username.length() < USERNAME_MIN_LENGTH) || (username.length() > USERNAME_MAX_LENGTH) || (!(Pattern.matches("[a-zA-Z0-9//_//.]+", username))))
968 {
969 return ERROR_INVALID_USERNAME;
970 }
971 return NO_ERROR;
972 }
973
974 public int checkPassword(String password)
975 {
976 //Check the given password
977 if (password == null)
978 {
979 return ERROR_PASSWORD_NOT_ENTERED;
980 }
981 else if (password.length() < PASSWORD_MIN_LENGTH)
982 {
983 return ERROR_PASSWORD_TOO_SHORT;
984 }
985 else if (password.length() > PASSWORD_MAX_LENGTH)
986 {
987 return ERROR_PASSWORD_TOO_LONG;
988 }
989 else if (!(Pattern.matches("[\\p{ASCII}]+", password)))
990 {
991 return ERROR_PASSWORD_USES_ILLEGAL_CHARACTERS;
992 }
993 return NO_ERROR;
994 }
995
996 public static String hashPassword(String password)
997 {
998 return DigestUtils.sha1Hex(password);
999 }
1000
1001 public static int verifyRecaptcha(String secret_key, String user_response) {
1002
1003 if (user_response == null || user_response.length() == 0) {
1004 return ERROR_CAPTCHA_MISSING;
1005 }
1006
1007 try{
1008
1009 URL obj = new URL("https://www.google.com/recaptcha/api/siteverify");
1010 HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
1011
1012 // add reuqest header
1013 con.setRequestMethod("POST");
1014 con.setRequestProperty("User-Agent", "Mozilla/5.0");
1015 con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
1016
1017 String postParams = "secret=" + secret_key + "&response="
1018 + user_response;
1019
1020 // Send post request
1021 con.setDoOutput(true);
1022 DataOutputStream wr = new DataOutputStream(con.getOutputStream());
1023 wr.writeBytes(postParams);
1024 wr.flush();
1025 wr.close();
1026
1027 int responseCode = con.getResponseCode();
1028 //System.out.println("\nSending 'POST' request to URL : https://www.google.com/recaptcha/api/siteverify");// + url);
1029 //System.out.println("Post parameters : " + postParams);
1030 //System.out.println("Response Code : " + responseCode);
1031
1032 BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
1033 String inputLine;
1034 StringBuffer response = new StringBuffer();
1035
1036 while ((inputLine = in.readLine()) != null) {
1037 response.append(inputLine);
1038 }
1039 in.close();
1040
1041 // print result
1042 //System.out.println(response.toString());
1043
1044 JSONObject json_obj = new JSONObject(response.toString());
1045 boolean res = json_obj.getBoolean("success");
1046 if (res) {
1047 return NO_ERROR;
1048 } else {
1049 return ERROR_CAPTCHA_FAILED;
1050 }
1051 }catch(Exception e){
1052 e.printStackTrace();
1053 return ERROR_CONNECTION_FAILED;
1054 }
1055
1056 }
1057 // This method can also be used for printing out the password in hex (in case
1058 // the password used the UTF-8 Charset), or the hex values in any unicode string.
1059 // From http://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
1060 public static String toHex(String arg)
1061 {
1062 try
1063 {
1064 return String.format("%x", new BigInteger(arg.getBytes("US-ASCII"))); // set to same charset as used by hashPassword
1065 }
1066 catch (Exception e)
1067 { // UnsupportedEncodingException
1068 e.printStackTrace();
1069 }
1070 return "Unable to print";
1071 }
1072
1073 private void checkAdminUserExists()
1074 {
1075 DerbyWrapper derbyWrapper = openDatabase();
1076 UserQueryResult userQueryResult = derbyWrapper.findUser(null, null);
1077 derbyWrapper.closeDatabase();
1078
1079 if (userQueryResult != null)
1080 {
1081 Vector userInfo = userQueryResult.getUserTerms();
1082
1083 boolean adminFound = false;
1084 for (int i = 0; i < userQueryResult.getSize(); i++)
1085 {
1086 // can call either getExpandedGroups() or getCompactedGroups() to check admin group is in there:
1087 if (((UserTermInfo) userInfo.get(i)).getCompactedGroups() != null && ((UserTermInfo) userInfo.get(i)).getCompactedGroups().matches(".*\\badministrator\\b.*"))
1088 {
1089 adminFound = true;
1090 }
1091 }
1092
1093 if (!adminFound)
1094 {
1095 addUser("admin", "admin", "administrator", "true", "Change the password for this account as soon as possible", "");
1096 }
1097 }
1098 }
1099
1100 private DerbyWrapper openDatabase()
1101 {
1102 // check the usersDb database, if it isn't existing, check the etc dir, create the etc dir if it isn't existing, then create the user database and add a "admin" user
1103 String usersDB_dir = GlobalProperties.getGSDL3Home() + File.separatorChar + "etc" + File.separatorChar + "usersDB";
1104 DerbyWrapper derbyWrapper = new DerbyWrapper(usersDB_dir);
1105 return derbyWrapper;
1106 }
1107
1108 private int addUserInformationToNode(String username, Element serviceNode)
1109 {
1110 DerbyWrapper derbyWrapper = openDatabase();
1111 UserQueryResult userQueryResult = derbyWrapper.findUser(username, null);
1112 derbyWrapper.closeDatabase();
1113
1114 if (userQueryResult != null)
1115 {
1116 Element user_node = getUserNodeList(serviceNode.getOwnerDocument(), userQueryResult);
1117 serviceNode.appendChild(user_node);
1118 return NO_ERROR;
1119 }
1120
1121 return ERROR_COULD_NOT_GET_USER_INFO;
1122 }
1123
1124 private int removeUser(String username)
1125 {
1126 if (username == null)
1127 {
1128 return ERROR_USERNAME_NOT_SPECIFIED;
1129 }
1130
1131 DerbyWrapper derbyWrapper = openDatabase();
1132 boolean success = derbyWrapper.deleteUser(username);
1133 derbyWrapper.closeDatabase();
1134
1135 if (success)
1136 {
1137 return NO_ERROR;
1138 }
1139
1140 return ERROR_REMOVING_USER;
1141 }
1142
1143 private int addUser(String newUsername, String newPassword, String newGroups, String newStatus, String newComment, String newEmail)
1144 {
1145 newGroups = newGroups.replaceAll(" ", "");
1146 // store only expandedGroups in DB now
1147 newGroups = UserTermInfo.expandGroups(newGroups);
1148
1149 //Check if the user already exists
1150 DerbyWrapper derbyWrapper = openDatabase();
1151 UserQueryResult userQueryResult = derbyWrapper.findUser(newUsername, null);
1152
1153 if (userQueryResult != null)
1154 {
1155 derbyWrapper.closeDatabase();
1156 return ERROR_USER_ALREADY_EXISTS;
1157 }
1158 else
1159 {
1160 boolean success = derbyWrapper.addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
1161 derbyWrapper.closeDatabase();
1162
1163 if (!success)
1164 {
1165 return ERROR_ADDING_USER;
1166 }
1167 }
1168
1169 return NO_ERROR;
1170 }
1171
1172 private boolean checkUserExists(String username)
1173 {
1174 boolean check_status = false;
1175
1176 DerbyWrapper derbyWrapper = openDatabase();
1177 try
1178 {
1179 UserQueryResult result = derbyWrapper.findUser(username);
1180
1181 if (result != null)
1182 {
1183 check_status = true;
1184 }
1185
1186 }
1187 catch (Exception ex)
1188 {
1189 // some error occurred accessing the database
1190 ex.printStackTrace();
1191 }
1192 derbyWrapper.closeDatabase();
1193
1194 return check_status;
1195 }
1196
1197 private String retrieveDataForUser(String username, String dataType)
1198 {
1199 openDatabase();
1200
1201 String data = null;
1202
1203 try
1204 {
1205 DerbyWrapper derbyWrapper = openDatabase();
1206 UserQueryResult result = derbyWrapper.findUser(username);
1207 derbyWrapper.closeDatabase();
1208 Vector userInfo = result.getUserTerms();
1209
1210 for (int i = 0; i < result.getSize(); i++)
1211 {
1212 if (dataType.equals(PASSWORD))
1213 {
1214 data = ((UserTermInfo) userInfo.get(i)).getPassword();
1215 break;
1216 }
1217 else if (dataType.equals(COMPACTED_GROUPS))
1218 {
1219 data = ((UserTermInfo) userInfo.get(i)).getCompactedGroups();
1220 break;
1221 }
1222 else if (dataType.equals(EXPANDED_GROUPS))
1223 {
1224 data = ((UserTermInfo) userInfo.get(i)).getExpandedGroups();
1225 break;
1226 }
1227 else if (dataType.equals(STATUS))
1228 {
1229 data = ((UserTermInfo) userInfo.get(i)).getAccountStatus();
1230 break;
1231 }
1232 else if (dataType.equals(COMMENT))
1233 {
1234 data = ((UserTermInfo) userInfo.get(i)).getComment();
1235 break;
1236 }
1237 else if (dataType.equals(EMAIL))
1238 {
1239 data = ((UserTermInfo) userInfo.get(i)).getEmail();
1240 break;
1241 }
1242 }
1243 }
1244 catch (Exception ex)
1245 {
1246 ex.printStackTrace();
1247 }
1248
1249 return data;
1250 }
1251
1252 private Element getUserNodeList(Document doc, UserQueryResult userQueryResult)
1253 {
1254 Element user_list_node = doc.createElement(GSXML.USER_NODE_ELEM + GSXML.LIST_MODIFIER);
1255
1256 Vector userInfo = userQueryResult.getUserTerms();
1257
1258 for (int i = 0; i < userQueryResult.getSize(); i++)
1259 {
1260 Element user_node = doc.createElement(GSXML.USER_NODE_ELEM);
1261 String username = ((UserTermInfo) userInfo.get(i)).getUsername();
1262 String compactedGroups = ((UserTermInfo) userInfo.get(i)).getCompactedGroups();
1263 // Since this is used for display in admin pages, get compacted (more similar to user-entered) groups
1264 // and not expanded groups, as getUserNodeList only used in addUserInformationToNode() which
1265 // allows displaying and modifying user info pages and authenticating admin user,
1266 // none of which requires expanded groups.
1267 String accountstatus = ((UserTermInfo) userInfo.get(i)).getAccountStatus();
1268 String comment = ((UserTermInfo) userInfo.get(i)).getComment();
1269 String email = ((UserTermInfo) userInfo.get(i)).getEmail();
1270 user_node.setAttribute(USERNAME, username);
1271 user_node.setAttribute(GROUPS, compactedGroups);
1272 user_node.setAttribute(STATUS, accountstatus);
1273 user_node.setAttribute(COMMENT, comment);
1274 user_node.setAttribute(EMAIL, email);
1275
1276 user_list_node.appendChild(user_node);
1277 }
1278 return user_list_node;
1279 }
1280
1281 private Element getCollectList(Document doc, String collect)
1282 {
1283 Element collect_list_node = doc.createElement(GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
1284 File[] collect_dir = (new File(collect)).listFiles();
1285 if (collect_dir != null && collect_dir.length > 0)
1286 {
1287 for (int i = 0; i < collect_dir.length; i++)
1288 {
1289 if (collect_dir[i].isDirectory() && (!collect_dir[i].getName().startsWith(".svn")))
1290 {
1291 Element collect_node = doc.createElement(GSXML.COLLECTION_ELEM);
1292 collect_node.setAttribute(GSXML.NAME_ATT, collect_dir[i].getName());
1293 collect_list_node.appendChild(collect_node);
1294 }
1295 }
1296 }
1297 return collect_list_node;
1298 }
1299
1300
1301 // main() method - calls hashPassword() on any String argument, printing this to stdout
1302 // This main() is invoked by gliserver.pl perl code to encrypt passwords identically to Java code.
1303 public static void main(String[] args)
1304 {
1305 if (args.length < 1)
1306 {
1307 System.err.println("Usage: Authentication <string to encrypt>");
1308 System.exit(-1);
1309 }
1310 // just hash the first argument
1311 String hash = Authentication.hashPassword(args[0]);
1312 System.out.println(hash);
1313 }
1314}
Note: See TracBrowser for help on using the repository browser.