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

Last change on this file since 25725 was 25725, checked in by sjm84, 12 years ago

An attempt at fixing the registration problem for systems behind a firewall that does not let them access google services

File size: 31.0 KB
Line 
1package org.greenstone.gsdl3.service;
2
3import java.io.File;
4import java.io.Serializable;
5import java.math.BigInteger;
6import java.security.MessageDigest;
7import java.sql.SQLException;
8import java.util.ArrayList;
9import java.util.HashMap;
10import java.util.UUID;
11import java.util.Vector;
12import java.util.regex.Pattern;
13
14import net.tanesha.recaptcha.ReCaptchaImpl;
15import net.tanesha.recaptcha.ReCaptchaResponse;
16
17import org.greenstone.gsdl3.util.DerbyWrapper;
18import org.greenstone.gsdl3.util.GSXML;
19import org.greenstone.gsdl3.util.UserQueryResult;
20import org.greenstone.gsdl3.util.UserTermInfo;
21import org.w3c.dom.Element;
22import org.w3c.dom.NodeList;
23
24public class Authentication extends ServiceRack
25{
26 //Error codes
27 protected static final int NO_ERROR = 0;
28 protected static final int ERROR_REQUEST_HAS_NO_PARAM_LIST = -1;
29 protected static final int ERROR_NOT_LOGGED_IN = -2;
30 protected static final int ERROR_ADMIN_NOT_LOGGED_IN = -3;
31 protected static final int ERROR_COULD_NOT_GET_USER_INFO = -4;
32 protected static final int ERROR_USERNAME_NOT_SPECIFIED = -5;
33 protected static final int ERROR_REQUESTED_USER_NOT_FOUND = -6;
34 protected static final int ERROR_SQL_EXCEPTION = -7;
35 protected static final int ERROR_INVALID_USERNAME = -8;
36 protected static final int ERROR_INVALID_PASSWORD = -9;
37 protected static final int ERROR_INCORRECT_PASSWORD = -10;
38 protected static final int ERROR_USER_ALREADY_EXISTS = -11;
39 protected static final int ERROR_ADDING_USER = -12;
40 protected static final int ERROR_REMOVING_USER = -13;
41 protected static final int ERROR_CAPTCHA_DOES_NOT_MATCH = -14;
42 protected static final int ERROR_CAPTCHA_MISSING = -15;
43 protected static final int ERROR_NOT_AUTHORISED = -16;
44
45 protected static final HashMap<Integer, String> _errorMessageMap;
46 static
47 {
48 //Corresponding error messages
49 HashMap<Integer, String> errorMessageMap = new HashMap<Integer, String>();
50 errorMessageMap.put(ERROR_REQUEST_HAS_NO_PARAM_LIST, "The list of parameters for this request was empty.");
51 errorMessageMap.put(ERROR_NOT_LOGGED_IN, "You must be logged in to access this page.");
52 errorMessageMap.put(ERROR_ADMIN_NOT_LOGGED_IN, "You must be logged in as an administrator to access this page.");
53 errorMessageMap.put(ERROR_COULD_NOT_GET_USER_INFO, "There was a error getting the user information.");
54 errorMessageMap.put(ERROR_USERNAME_NOT_SPECIFIED, "No username was specified.");
55 errorMessageMap.put(ERROR_REQUESTED_USER_NOT_FOUND, "The requested user was not found in the database.");
56 errorMessageMap.put(ERROR_SQL_EXCEPTION, "There was an SQL exception while accessing the database.");
57 errorMessageMap.put(ERROR_INVALID_USERNAME, "The username specified was invalid.");
58 errorMessageMap.put(ERROR_INVALID_PASSWORD, "The password specified was invalid.");
59 errorMessageMap.put(ERROR_INCORRECT_PASSWORD, "The password specified was incorrect.");
60 errorMessageMap.put(ERROR_USER_ALREADY_EXISTS, "This user already exists and therefore cannot be added.");
61 errorMessageMap.put(ERROR_ADDING_USER, "There was an error adding this user to the database.");
62 errorMessageMap.put(ERROR_REMOVING_USER, "There was an error removing this user from the database.");
63 errorMessageMap.put(ERROR_CAPTCHA_DOES_NOT_MATCH, "The words you entered did not match the image, please try again.");
64 errorMessageMap.put(ERROR_CAPTCHA_MISSING, "The information from the captcha is missing.");
65 errorMessageMap.put(ERROR_NOT_AUTHORISED, "You are not authorised to access this page.");
66
67 _errorMessageMap = errorMessageMap;
68 }
69
70 //Admin-required operations
71 protected static final String LIST_USERS = "ListUsers";
72 protected static final String PERFORM_ADD = "PerformAdd";
73 protected static final String PERFORM_EDIT = "PerformEdit";
74 protected static final String ADD_USER = "AddUser";
75 protected static final String EDIT_USER = "EditUser";
76 protected static final String PERFORM_DELETE_USER = "PerformDeleteUser";
77
78 protected static final ArrayList<String> _adminOpList;
79 static
80 {
81 ArrayList<String> opList = new ArrayList<String>();
82 opList.add(LIST_USERS);
83 opList.add(PERFORM_ADD);
84 opList.add(PERFORM_EDIT);
85 opList.add(EDIT_USER);
86 opList.add(PERFORM_DELETE_USER);
87
88 _adminOpList = opList;
89 }
90
91 //User-required operations
92 protected static final String ACCOUNT_SETTINGS = "AccountSettings";
93 protected static final String PERFORM_ACCOUNT_EDIT = "PerformAccEdit";
94 protected static final String PERFORM_RESET_PASSWORD = "PerformResetPassword";
95 protected static final ArrayList<String> _userOpList;
96 static
97 {
98 ArrayList<String> opList = new ArrayList<String>();
99 opList.add(ACCOUNT_SETTINGS);
100 opList.add(PERFORM_ACCOUNT_EDIT);
101 opList.add(PERFORM_RESET_PASSWORD);
102 opList.addAll(_adminOpList);
103 _userOpList = opList;
104 }
105
106 //Other operations
107 protected static final String REGISTER = "Register";
108 protected static final String PERFORM_REGISTER = "PerformRegister";
109 protected static final String LOGIN = "Login";
110
111 //the services on offer
112 protected static final String AUTHENTICATION_SERVICE = "Authentication";
113 protected static final String GET_USER_INFORMATION_SERVICE = "GetUserInformation";
114
115 protected DerbyWrapper _derbyWrapper = null;
116
117 protected String _recaptchaPrivateKey = null;
118 protected String _recaptchaPublicKey = null;
119
120 /** constructor */
121 public Authentication()
122 {
123 }
124
125 public boolean configure(Element info, Element extra_info)
126 {
127 logger.info("Configuring Authentication...");
128 this.config_info = info;
129
130 // set up Authentication service info - for now just has name and type
131 Element authentication_service = this.doc.createElement(GSXML.SERVICE_ELEM);
132 authentication_service.setAttribute(GSXML.TYPE_ATT, "authen");
133 authentication_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
134 this.short_service_info.appendChild(authentication_service);
135
136 // set up Authentication service info - for now just has name and type
137 Element getUserInformation_service = this.doc.createElement(GSXML.SERVICE_ELEM);
138 getUserInformation_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
139 getUserInformation_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
140 this.short_service_info.appendChild(getUserInformation_service);
141
142 NodeList recaptchaElems = info.getElementsByTagName("recaptcha");
143
144 for (int i = 0; i < recaptchaElems.getLength(); i++)
145 {
146 Element currentElem = (Element) recaptchaElems.item(i);
147 if (currentElem.getAttribute(GSXML.NAME_ATT) != null && currentElem.getAttribute(GSXML.NAME_ATT).equals("public_key"))
148 {
149 if (currentElem.getAttribute(GSXML.VALUE_ATT) != null)
150 {
151 _recaptchaPublicKey = currentElem.getAttribute(GSXML.VALUE_ATT);
152 }
153 }
154 else if (currentElem.getAttribute(GSXML.NAME_ATT) != null && currentElem.getAttribute(GSXML.NAME_ATT).equals("private_key"))
155 {
156 if (currentElem.getAttribute(GSXML.VALUE_ATT) != null)
157 {
158 _recaptchaPrivateKey = currentElem.getAttribute(GSXML.VALUE_ATT);
159 }
160 }
161 }
162
163 return true;
164 }
165
166 protected Element getServiceDescription(String service_id, String lang, String subset)
167 {
168
169 Element authen_service = this.doc.createElement(GSXML.SERVICE_ELEM);
170
171 if (service_id.equals(AUTHENTICATION_SERVICE))
172 {
173 authen_service.setAttribute(GSXML.TYPE_ATT, "authen");
174 authen_service.setAttribute(GSXML.NAME_ATT, AUTHENTICATION_SERVICE);
175 }
176 else if (service_id.equals(GET_USER_INFORMATION_SERVICE))
177 {
178 authen_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
179 authen_service.setAttribute(GSXML.NAME_ATT, GET_USER_INFORMATION_SERVICE);
180 }
181 else
182 {
183 return null;
184 }
185
186 if (service_id.equals(AUTHENTICATION_SERVICE) && (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER)))
187 {
188 authen_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(service_id, lang)));
189 authen_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(service_id, lang)));
190 }
191 return authen_service;
192 }
193
194 protected String getServiceName(String service_id, String lang)
195 {
196 return getTextString(service_id + ".name", lang);
197 }
198
199 protected String getServiceSubmit(String service_id, String lang)
200 {
201 return getTextString(service_id + ".submit", lang);
202 }
203
204 protected String getServiceDescription(String service_id, String lang)
205 {
206 return getTextString(service_id + ".description", lang);
207 }
208
209 protected void addCustomParams(String service, Element param_list, String lang)
210 {
211 }
212
213 protected void createParameter(String name, Element param_list, String lang)
214 {
215 }
216
217 protected Element processGetUserInformation(Element request)
218 {
219 // Create a new (empty) result message
220 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
221
222 result.setAttribute(GSXML.FROM_ATT, GET_USER_INFORMATION_SERVICE);
223 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
224
225 Element paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
226 if (paramList == null)
227 {
228 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUEST_HAS_NO_PARAM_LIST));
229 return result;
230 }
231
232 HashMap<String, Serializable> params = GSXML.extractParams(paramList, true);
233
234 String username = (String) params.get("username");
235
236 if (username == null)
237 {
238 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USERNAME_NOT_SPECIFIED));
239 return result;
240 }
241
242 DerbyWrapper dbWrapper = new DerbyWrapper();
243
244 String usersDB_dir = this.site_home + File.separatorChar + "etc" + File.separatorChar + "usersDB";
245 dbWrapper.connectDatabase(usersDB_dir, true);
246
247 UserQueryResult userQueryResult;
248 try
249 {
250 userQueryResult = dbWrapper.findUser(username);
251 Vector<UserTermInfo> terms = userQueryResult.getUserTerms();
252
253 if (terms.size() == 0)
254 {
255 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUESTED_USER_NOT_FOUND));
256 return result;
257 }
258
259 UserTermInfo userInfo = terms.get(0);
260 Element userInfoList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
261 result.appendChild(userInfoList);
262
263 Element usernameField = GSXML.createParameter(this.doc, "username", userInfo.username);
264 Element passwordField = GSXML.createParameter(this.doc, "password", userInfo.password);
265 Element groupsField = GSXML.createParameter(this.doc, "groups", userInfo.groups);
266 Element accountStatusField = GSXML.createParameter(this.doc, "accountstatus", userInfo.accountstatus);
267 Element commentField = GSXML.createParameter(this.doc, "comment", userInfo.comment);
268
269 userInfoList.appendChild(usernameField);
270 userInfoList.appendChild(passwordField);
271 userInfoList.appendChild(groupsField);
272 userInfoList.appendChild(accountStatusField);
273 userInfoList.appendChild(commentField);
274 }
275 catch (SQLException ex)
276 {
277 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_SQL_EXCEPTION));
278 ex.printStackTrace();
279 }
280
281 return result;
282 }
283
284 protected Element processAuthentication(Element request)
285 {
286 checkAdminUserExists();
287
288 // Create a new (empty) result message
289 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
290 result.setAttribute(GSXML.FROM_ATT, AUTHENTICATION_SERVICE);
291 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
292
293 // Create an Authentication node put into the result
294 Element authenNode = this.doc.createElement(GSXML.AUTHEN_NODE_ELEM);
295 result.appendChild(authenNode);
296 result.appendChild(getCollectList(this.site_home + File.separatorChar + "collect"));
297
298 // Create a service node added into the Authentication node
299 Element serviceNode = this.doc.createElement(GSXML.SERVICE_ELEM);
300 authenNode.appendChild(serviceNode);
301
302 // Get the parameters of the request
303 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
304 if (param_list == null)
305 {
306 serviceNode.setAttribute("operation", LOGIN);
307 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_REQUEST_HAS_NO_PARAM_LIST));
308 return result; // Return the empty result
309 }
310 HashMap<String, Serializable> paramMap = GSXML.extractParams(param_list, false);
311 String op = (String) paramMap.get("authpage");
312 serviceNode.setAttribute("operation", op);
313
314 String username = null;
315 String groups = null;
316
317 Element userInformation = (Element) GSXML.getChildByTagName(request, GSXML.USER_INFORMATION_ELEM);
318 if (userInformation == null && _userOpList.contains(op))
319 {
320 serviceNode.setAttribute("operation", LOGIN);
321 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_LOGGED_IN));
322 return result;
323 }
324
325 if (userInformation != null)
326 {
327 username = userInformation.getAttribute(GSXML.USERNAME_ATT);
328 groups = userInformation.getAttribute(GSXML.GROUPS_ATT);
329 }
330
331 if (username == null && _userOpList.contains(op))
332 {
333 serviceNode.setAttribute("operation", LOGIN);
334 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_LOGGED_IN));
335 return result;
336 }
337
338 if (_adminOpList.contains(op) && (groups == null || !groups.matches(".*\\badministrator\\b.*")))
339 {
340 serviceNode.setAttribute("operation", LOGIN);
341 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_ADMIN_NOT_LOGGED_IN));
342 return result;
343 }
344
345 if (op.equals(LIST_USERS))
346 {
347 int error = addUserInformationToNode(null, serviceNode);
348 if (error != NO_ERROR)
349 {
350 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
351 }
352 }
353 else if (op.equals(PERFORM_ADD))
354 {
355 String newUsername = (String) paramMap.get("username");
356 String newPassword = (String) paramMap.get("password");
357 String newGroups = (String) paramMap.get("groups");
358 String newStatus = (String) paramMap.get("status");
359 String newComment = (String) paramMap.get("comment");
360 String newEmail = (String) paramMap.get("email");
361
362 //Check the given user name
363 int error;
364 if ((error = checkUsername(newUsername)) != NO_ERROR)
365 {
366 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
367 return result;
368 }
369
370 //Check the given password
371 if ((error = checkPassword(newPassword)) != NO_ERROR)
372 {
373 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
374 return result;
375 }
376
377 newPassword = hashPassword(newPassword);
378
379 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
380 if (error != NO_ERROR)
381 {
382 serviceNode.setAttribute("operation", ADD_USER);
383 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
384 }
385 else
386 {
387 addUserInformationToNode(null, serviceNode);
388 serviceNode.setAttribute("operation", LIST_USERS);
389 }
390 }
391 else if (op.equals(PERFORM_REGISTER))
392 {
393 String newUsername = (String) paramMap.get("username");
394 String newPassword = (String) paramMap.get("password");
395 String newEmail = (String) paramMap.get("email");
396
397 //Check the given user name
398 int error;
399 if ((error = checkUsername(newUsername)) != NO_ERROR)
400 {
401 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
402 return result;
403 }
404
405 //Check the given password
406 if ((error = checkPassword(newPassword)) != NO_ERROR)
407 {
408 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
409 return result;
410 }
411
412 newPassword = hashPassword(newPassword);
413
414 if (_recaptchaPrivateKey != null && _recaptchaPrivateKey.length() > 0)
415 {
416 ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
417 reCaptcha.setPrivateKey(_recaptchaPrivateKey);
418
419 try
420 {
421 //If this line throws an exception then we'll assume the user has problems with their firewall
422 reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), "", "");
423
424 String challenge = (String) paramMap.get("recaptcha_challenge_field");
425 String uResponse = (String) paramMap.get("recaptcha_response_field");
426
427 if (challenge == null || uResponse == null)
428 {
429 serviceNode.setAttribute("operation", REGISTER);
430 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_MISSING));
431 return result;
432 }
433
434 ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), challenge, uResponse);
435
436 if (!reCaptchaResponse.isValid())
437 {
438 serviceNode.setAttribute("operation", REGISTER);
439 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_DOES_NOT_MATCH));
440 return result;
441 }
442 }
443 catch (Exception ex)
444 {
445 }
446 }
447
448 error = addUser(newUsername, newPassword, "", "true", "", newEmail);
449 if (error != NO_ERROR)
450 {
451 serviceNode.setAttribute("operation", REGISTER);
452 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
453 }
454 }
455 else if (op.equals(PERFORM_EDIT))
456 {
457 String previousUsername = (String) paramMap.get("prevUsername");
458 String newUsername = (String) paramMap.get("newUsername");
459 String newPassword = (String) paramMap.get("password");
460 String newGroups = (String) paramMap.get("groups");
461 String newStatus = (String) paramMap.get("status");
462 String newComment = (String) paramMap.get("comment");
463 String newEmail = (String) paramMap.get("email");
464
465 //Check the given user name
466 int error;
467 if ((error = checkUsername(newUsername)) != NO_ERROR)
468 {
469 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
470 return result;
471 }
472
473 if (newPassword == null)
474 {
475 newPassword = retrieveDataForUser(previousUsername, "password");
476 }
477 else
478 {
479 //Check the given password
480 if ((error = checkPassword(newPassword)) != NO_ERROR)
481 {
482 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
483 return result;
484 }
485
486 newPassword = hashPassword(newPassword);
487 }
488
489 error = removeUser(previousUsername);
490 if (error != NO_ERROR)
491 {
492 if (error == ERROR_USERNAME_NOT_SPECIFIED)
493 {
494 addUserInformationToNode(null, serviceNode);
495 serviceNode.setAttribute("operation", LIST_USERS);
496 }
497 else
498 {
499 serviceNode.setAttribute("operation", EDIT_USER);
500 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
501 }
502 return result;
503 }
504
505 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
506 if (error != NO_ERROR)
507 {
508 serviceNode.setAttribute("operation", EDIT_USER);
509 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
510 }
511 else
512 {
513 addUserInformationToNode(null, serviceNode);
514 serviceNode.setAttribute("operation", LIST_USERS);
515 }
516 }
517 else if (op.equals(PERFORM_ACCOUNT_EDIT))
518 {
519 String previousUsername = (String) paramMap.get("prevUsername");
520 String newUsername = (String) paramMap.get("newUsername");
521 String oldPassword = (String) paramMap.get("oldPassword");
522 String newPassword = (String) paramMap.get("newPassword");
523 String newEmail = (String) paramMap.get("newEmail");
524
525 //Make sure the user name does not already exist
526 if (!previousUsername.equals(newUsername) && checkUserExists(newUsername))
527 {
528 addUserInformationToNode(previousUsername, serviceNode);
529 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
530 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USER_ALREADY_EXISTS));
531 return result;
532 }
533
534 String prevPassword = retrieveDataForUser(previousUsername, "password");
535
536 if (newPassword != null)
537 {
538 oldPassword = hashPassword(oldPassword);
539
540 if (oldPassword == null || !oldPassword.equals(prevPassword))
541 {
542 addUserInformationToNode(previousUsername, serviceNode);
543 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
544 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_INCORRECT_PASSWORD), "Incorrect Password");
545 return result;
546 }
547
548 //Check the given password
549 int error;
550 if ((error = checkPassword(newPassword)) != NO_ERROR)
551 {
552 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
553 return result;
554 }
555
556 newPassword = hashPassword(newPassword);
557 }
558 else
559 {
560 newPassword = prevPassword;
561 }
562
563 //Check the given user name
564 int error;
565 if ((error = checkUsername(newUsername)) != NO_ERROR)
566 {
567 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
568 return result;
569 }
570
571 String prevGroups = retrieveDataForUser(previousUsername, "groups");
572 String prevStatus = retrieveDataForUser(previousUsername, "status");
573 String prevComment = retrieveDataForUser(previousUsername, "comment");
574
575 error = removeUser(previousUsername);
576 if (error != NO_ERROR)
577 {
578 if (error == ERROR_USERNAME_NOT_SPECIFIED)
579 {
580 addUserInformationToNode(null, serviceNode);
581 serviceNode.setAttribute("operation", LIST_USERS);
582 }
583 else
584 {
585 addUserInformationToNode(previousUsername, serviceNode);
586 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
587 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
588 }
589 return result;
590 }
591
592 error = addUser(newUsername, newPassword, prevGroups, prevStatus, prevComment, newEmail);
593 if (error != NO_ERROR)
594 {
595 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
596 }
597
598 addUserInformationToNode(null, serviceNode);
599 serviceNode.setAttribute("operation", LIST_USERS);
600 }
601 else if (op.equals(EDIT_USER))
602 {
603 String editUsername = (String) paramMap.get("username");
604 int error = addUserInformationToNode(editUsername, serviceNode);
605 if (error != NO_ERROR)
606 {
607 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
608 }
609 }
610 else if (op.equals(ACCOUNT_SETTINGS))
611 {
612 String editUsername = (String) paramMap.get("username");
613
614 if (editUsername == null)
615 {
616 serviceNode.setAttribute("operation", "");
617 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USERNAME_NOT_SPECIFIED));
618 return result;
619 }
620
621 if (!editUsername.equals(username))
622 {
623 serviceNode.setAttribute("operation", LOGIN);
624 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_AUTHORISED));
625 return result;
626 }
627 int error = addUserInformationToNode(editUsername, serviceNode);
628 if (error != NO_ERROR)
629 {
630 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
631 }
632 }
633 else if (op.equals(PERFORM_RESET_PASSWORD))
634 {
635 String passwordResetUser = (String) paramMap.get("username");
636
637 String newPassword = UUID.randomUUID().toString();
638 newPassword = newPassword.substring(0, newPassword.indexOf("-"));
639
640 String email = retrieveDataForUser(passwordResetUser, "email");
641 String from = "[email protected]";
642 String host = request.getAttribute("remoteAddress");
643
644 //TODO: FINISH THIS
645 }
646 else if (op.equals(REGISTER))
647 {
648 if (_recaptchaPrivateKey != null && _recaptchaPrivateKey.length() > 0)
649 {
650 try
651 {
652 ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
653 reCaptcha.setPrivateKey(_recaptchaPrivateKey);
654 reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), "", "");
655 }
656 catch (Exception ex)
657 {
658 return result;
659 }
660 }
661
662 if (_recaptchaPublicKey != null && _recaptchaPrivateKey != null)
663 {
664 Element recaptchaElem = this.doc.createElement("recaptcha");
665 recaptchaElem.setAttribute("publicKey", _recaptchaPublicKey);
666 recaptchaElem.setAttribute("privateKey", _recaptchaPrivateKey);
667 result.appendChild(recaptchaElem);
668 }
669 }
670 else if (op.equals(PERFORM_DELETE_USER))
671 {
672 String usernameToDelete = (String) paramMap.get("username");
673 int error = removeUser(usernameToDelete);
674 if (error != NO_ERROR)
675 {
676 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
677 }
678 addUserInformationToNode(null, serviceNode);
679 serviceNode.setAttribute("operation", LIST_USERS);
680 }
681
682 return result;
683 }
684
685 public int checkUsernameAndPassword(String username, String password)
686 {
687 int uResult = checkUsername(username);
688 int pResult = checkPassword(password);
689
690 return (uResult != NO_ERROR ? uResult : (pResult != NO_ERROR ? pResult : NO_ERROR));
691 }
692
693 public int checkUsername(String username)
694 {
695 //Check the given user name
696 if ((username == null) || (username.length() < 2) || (username.length() > 30) || (!(Pattern.matches("[a-zA-Z0-9//_//.]+", username))))
697 {
698 return ERROR_INVALID_USERNAME;
699 }
700 return NO_ERROR;
701 }
702
703 public int checkPassword(String password)
704 {
705 //Check the given password
706 if ((password == null) || (password.length() < 3) || (password.length() > 8) || (!(Pattern.matches("[\\p{ASCII}]+", password))))
707 {
708 return ERROR_INVALID_PASSWORD;
709 }
710 return NO_ERROR;
711 }
712
713 public static String hashPassword(String password)
714 {
715 String hashedPassword = null;
716 try
717 {
718 MessageDigest digest = MessageDigest.getInstance("SHA-1");
719 digest.reset();
720 hashedPassword = new String(digest.digest(password.getBytes("US-ASCII"))); // toHex after using ASCII charset will result in acceptable length of hex string
721 hashedPassword = toHex(hashedPassword); // this conversion is required to avoid the strange error of login failure on some legal password strings
722 }
723 catch (Exception ex)
724 {
725 ex.printStackTrace();
726 }
727 return hashedPassword;
728 }
729
730 // This method can also be used for printing out the password in hex (in case
731 // the password used the UTF-8 Charset), or the hex values in any unicode string.
732 // From http://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
733 public static String toHex(String arg)
734 {
735 try
736 {
737 return String.format("%x", new BigInteger(arg.getBytes("US-ASCII"))); // set to same charset as used by hashPassword
738 }
739 catch (Exception e)
740 { // UnsupportedEncodingException
741 e.printStackTrace();
742 }
743 return "Unable to print";
744 }
745
746 private void checkAdminUserExists()
747 {
748 if (_derbyWrapper == null)
749 {
750 openDatabase();
751 }
752
753 UserQueryResult userQueryResult = _derbyWrapper.findUser(null, null);
754 closeDatabase();
755
756 if (userQueryResult != null)
757 {
758 Vector userInfo = userQueryResult.users;
759
760 boolean adminFound = false;
761 for (int i = 0; i < userQueryResult.getSize(); i++)
762 {
763 if (((UserTermInfo) userInfo.get(i)).groups != null && ((UserTermInfo) userInfo.get(i)).groups.matches(".*\\badministrator\\b.*"))
764 {
765 adminFound = true;
766 }
767 }
768
769 if (!adminFound)
770 {
771 addUser("admin", "admin", "administrator", "true", "Change the password for this account as soon as possible", "");
772 }
773 }
774
775 closeDatabase();
776 }
777
778 private boolean openDatabase()
779 {
780 _derbyWrapper = new DerbyWrapper();
781
782 // 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
783 String usersDB_dir = this.site_home + File.separatorChar + "etc" + File.separatorChar + "usersDB";
784 File usersDB_file = new File(usersDB_dir);
785 if (!usersDB_file.exists())
786 {
787 String etc_dir = this.site_home + File.separatorChar + "etc";
788 File etc_file = new File(etc_dir);
789 if (!etc_file.exists())
790 {
791 boolean success = etc_file.mkdir();
792 if (!success)
793 {
794 logger.error("Couldn't create the etc dir under " + this.site_home + ".");
795 return false;
796 }
797 }
798 _derbyWrapper.connectDatabase(usersDB_dir, true);
799 _derbyWrapper.createDatabase();
800 }
801 else
802 {
803 _derbyWrapper.connectDatabase(usersDB_dir, false);
804 }
805 return true;
806 }
807
808 private void closeDatabase()
809 {
810 if (_derbyWrapper != null)
811 {
812 _derbyWrapper.closeDatabase();
813 _derbyWrapper = null;
814 }
815 }
816
817 private int addUserInformationToNode(String username, Element serviceNode)
818 {
819 if (_derbyWrapper == null)
820 {
821 openDatabase();
822 }
823
824 UserQueryResult userQueryResult = _derbyWrapper.findUser(username, null);
825 closeDatabase();
826
827 if (userQueryResult != null)
828 {
829 Element user_node = getUserNode(userQueryResult);
830 serviceNode.appendChild(user_node);
831 closeDatabase();
832 return NO_ERROR;
833 }
834
835 closeDatabase();
836 return ERROR_COULD_NOT_GET_USER_INFO;
837 }
838
839 private int removeUser(String username)
840 {
841 if (username == null)
842 {
843 return ERROR_USERNAME_NOT_SPECIFIED;
844 }
845
846 if (_derbyWrapper == null)
847 {
848 openDatabase();
849 }
850
851 boolean success = _derbyWrapper.deleteUser(username);
852 closeDatabase();
853
854 if (success)
855 {
856 return NO_ERROR;
857 }
858
859 return ERROR_REMOVING_USER;
860 }
861
862 private int addUser(String newUsername, String newPassword, String newGroups, String newStatus, String newComment, String newEmail)
863 {
864 if (_derbyWrapper == null)
865 {
866 openDatabase();
867 }
868
869 newGroups = newGroups.replaceAll(" ", "");
870
871 //Check if the user already exists
872 UserQueryResult userQueryResult = _derbyWrapper.findUser(newUsername, null);
873 if (userQueryResult != null)
874 {
875 closeDatabase();
876 return ERROR_USER_ALREADY_EXISTS;
877 }
878 else
879 {
880 System.err.println("ADDING " + newUsername + " " + newPassword);
881 boolean success = _derbyWrapper.addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
882 if (!success)
883 {
884 closeDatabase();
885 return ERROR_ADDING_USER;
886 }
887 }
888 closeDatabase();
889 return NO_ERROR;
890 }
891
892 private boolean checkUserExists(String username)
893 {
894 if (_derbyWrapper == null)
895 {
896 openDatabase();
897 }
898
899 try
900 {
901 UserQueryResult result = _derbyWrapper.findUser(username);
902
903 if (result != null)
904 {
905 return true;
906 }
907 else
908 {
909 return false;
910 }
911
912 }
913 catch (Exception ex)
914 {
915 return false;
916 }
917 finally
918 {
919 closeDatabase();
920 }
921 }
922
923 private String retrieveDataForUser(String username, String dataType)
924 {
925 if (_derbyWrapper == null)
926 {
927 openDatabase();
928 }
929
930 String password = null;
931
932 try
933 {
934 UserQueryResult result = _derbyWrapper.findUser(username);
935 Vector userInfo = result.users;
936
937 for (int i = 0; i < result.getSize(); i++)
938 {
939 if (dataType.equals("password"))
940 {
941 return ((UserTermInfo) userInfo.get(i)).password;
942 }
943 else if (dataType.equals("groups"))
944 {
945 return ((UserTermInfo) userInfo.get(i)).groups;
946 }
947 else if (dataType.equals("status"))
948 {
949 return ((UserTermInfo) userInfo.get(i)).accountstatus;
950 }
951 else if (dataType.equals("comment"))
952 {
953 return ((UserTermInfo) userInfo.get(i)).comment;
954 }
955 else if (dataType.equals("email"))
956 {
957 return ((UserTermInfo) userInfo.get(i)).email;
958 }
959 }
960 }
961 catch (Exception ex)
962 {
963 ex.printStackTrace();
964 }
965
966 closeDatabase();
967 return password;
968 }
969
970 private Element getUserNode(UserQueryResult userQueryResult)
971 {
972 Element user_list_node = this.doc.createElement(GSXML.USER_NODE_ELEM + "List");
973
974 Vector userInfo = userQueryResult.users;
975
976 for (int i = 0; i < userQueryResult.getSize(); i++)
977 {
978 Element user_node = this.doc.createElement(GSXML.USER_NODE_ELEM);
979 String username = ((UserTermInfo) userInfo.get(i)).username;
980 String groups = ((UserTermInfo) userInfo.get(i)).groups;
981 String accountstatus = ((UserTermInfo) userInfo.get(i)).accountstatus;
982 String comment = ((UserTermInfo) userInfo.get(i)).comment;
983 String email = ((UserTermInfo) userInfo.get(i)).email;
984 user_node.setAttribute("username", username);
985 user_node.setAttribute("groups", groups);
986 user_node.setAttribute("status", accountstatus);
987 user_node.setAttribute("comment", comment);
988 user_node.setAttribute("email", email);
989
990 user_list_node.appendChild(user_node);
991 }
992 return user_list_node;
993 }
994
995 private Element getCollectList(String collect)
996 {
997 Element collect_list_node = this.doc.createElement(GSXML.COLLECTION_ELEM + "List");
998 File[] collect_dir = (new File(collect)).listFiles();
999 if (collect_dir != null && collect_dir.length > 0)
1000 {
1001 for (int i = 0; i < collect_dir.length; i++)
1002 {
1003 if (collect_dir[i].isDirectory() && (!collect_dir[i].getName().startsWith(".svn")))
1004 {
1005 Element collect_node = this.doc.createElement(GSXML.COLLECTION_ELEM);
1006 collect_node.setAttribute("name", collect_dir[i].getName());
1007 collect_list_node.appendChild(collect_node);
1008 }
1009 }
1010 }
1011 return collect_list_node;
1012 }
1013}
Note: See TracBrowser for help on using the repository browser.