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

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

Added an error type to help find this error in the XSL

File size: 30.4 KB
Line 
1package org.greenstone.gsdl3.service;
2
3import org.greenstone.gsdl3.util.GSXML;
4import org.greenstone.gsdl3.util.DerbyWrapper;
5import org.greenstone.gsdl3.util.UserQueryResult;
6import org.greenstone.gsdl3.util.UserTermInfo;
7
8import org.w3c.dom.Element;
9import org.w3c.dom.NodeList;
10
11import java.math.BigInteger;
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.UUID;
15import java.util.Vector;
16import java.security.MessageDigest;
17import java.sql.SQLException;
18import java.util.regex.Pattern;
19import java.io.File;
20
21import net.tanesha.recaptcha.ReCaptchaImpl;
22import net.tanesha.recaptcha.ReCaptchaResponse;
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 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 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)
415 {
416 ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
417 reCaptcha.setPrivateKey(_recaptchaPrivateKey);
418
419 String challenge = (String) paramMap.get("recaptcha_challenge_field");
420 String uResponse = (String) paramMap.get("recaptcha_response_field");
421
422 if (challenge == null || uResponse == null)
423 {
424 serviceNode.setAttribute("operation", REGISTER);
425 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_MISSING));
426 return result;
427 }
428
429 ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(request.getAttribute("remoteAddress"), challenge, uResponse);
430
431 if (!reCaptchaResponse.isValid())
432 {
433 serviceNode.setAttribute("operation", REGISTER);
434 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_CAPTCHA_DOES_NOT_MATCH));
435 return result;
436 }
437 }
438
439 error = addUser(newUsername, newPassword, "", "true", "", newEmail);
440 if (error != NO_ERROR)
441 {
442 serviceNode.setAttribute("operation", REGISTER);
443 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
444 }
445 }
446 else if (op.equals(PERFORM_EDIT))
447 {
448 String previousUsername = (String) paramMap.get("prevUsername");
449 String newUsername = (String) paramMap.get("newUsername");
450 String newPassword = (String) paramMap.get("password");
451 String newGroups = (String) paramMap.get("groups");
452 String newStatus = (String) paramMap.get("status");
453 String newComment = (String) paramMap.get("comment");
454 String newEmail = (String) paramMap.get("email");
455
456 //Check the given user name
457 int error;
458 if ((error = checkUsername(newUsername)) != NO_ERROR)
459 {
460 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
461 return result;
462 }
463
464 if (newPassword == null)
465 {
466 newPassword = retrieveDataForUser(previousUsername, "password");
467 }
468 else
469 {
470 //Check the given password
471 if ((error = checkPassword(newPassword)) != NO_ERROR)
472 {
473 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
474 return result;
475 }
476
477 newPassword = hashPassword(newPassword);
478 }
479
480 error = removeUser(previousUsername);
481 if (error != NO_ERROR)
482 {
483 if (error == ERROR_USERNAME_NOT_SPECIFIED)
484 {
485 addUserInformationToNode(null, serviceNode);
486 serviceNode.setAttribute("operation", LIST_USERS);
487 }
488 else
489 {
490 serviceNode.setAttribute("operation", EDIT_USER);
491 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
492 }
493 return result;
494 }
495
496 error = addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
497 if (error != NO_ERROR)
498 {
499 serviceNode.setAttribute("operation", EDIT_USER);
500 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
501 }
502 else
503 {
504 addUserInformationToNode(null, serviceNode);
505 serviceNode.setAttribute("operation", LIST_USERS);
506 }
507 }
508 else if (op.equals(PERFORM_ACCOUNT_EDIT))
509 {
510 String previousUsername = (String) paramMap.get("prevUsername");
511 String newUsername = (String) paramMap.get("newUsername");
512 String oldPassword = (String) paramMap.get("oldPassword");
513 String newPassword = (String) paramMap.get("newPassword");
514 String newEmail = (String) paramMap.get("newEmail");
515
516 //Make sure the user name does not already exist
517 if (!previousUsername.equals(newUsername) && checkUserExists(newUsername))
518 {
519 addUserInformationToNode(previousUsername, serviceNode);
520 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
521 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USER_ALREADY_EXISTS));
522 return result;
523 }
524
525 String prevPassword = retrieveDataForUser(previousUsername, "password");
526
527 if (newPassword != null)
528 {
529 oldPassword = hashPassword(oldPassword);
530
531 if (oldPassword == null || !oldPassword.equals(prevPassword))
532 {
533 addUserInformationToNode(previousUsername, serviceNode);
534 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
535 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_INCORRECT_PASSWORD), "Incorrect Password");
536 return result;
537 }
538
539 //Check the given password
540 int error;
541 if ((error = checkPassword(newPassword)) != NO_ERROR)
542 {
543 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
544 return result;
545 }
546
547 newPassword = hashPassword(newPassword);
548 }
549 else
550 {
551 newPassword = prevPassword;
552 }
553
554 //Check the given user name
555 int error;
556 if ((error = checkUsername(newUsername)) != NO_ERROR)
557 {
558 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
559 return result;
560 }
561
562 String prevGroups = retrieveDataForUser(previousUsername, "groups");
563 String prevStatus = retrieveDataForUser(previousUsername, "status");
564 String prevComment = retrieveDataForUser(previousUsername, "comment");
565
566 error = removeUser(previousUsername);
567 if (error != NO_ERROR)
568 {
569 if (error == ERROR_USERNAME_NOT_SPECIFIED)
570 {
571 addUserInformationToNode(null, serviceNode);
572 serviceNode.setAttribute("operation", LIST_USERS);
573 }
574 else
575 {
576 addUserInformationToNode(previousUsername, serviceNode);
577 serviceNode.setAttribute("operation", ACCOUNT_SETTINGS);
578 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
579 }
580 return result;
581 }
582
583 error = addUser(newUsername, newPassword, prevGroups, prevStatus, prevComment, newEmail);
584 if (error != NO_ERROR)
585 {
586 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
587 }
588
589 addUserInformationToNode(null, serviceNode);
590 serviceNode.setAttribute("operation", LIST_USERS);
591 }
592 else if (op.equals(EDIT_USER))
593 {
594 String editUsername = (String) paramMap.get("username");
595 int error = addUserInformationToNode(editUsername, serviceNode);
596 if (error != NO_ERROR)
597 {
598 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
599 }
600 }
601 else if (op.equals(ACCOUNT_SETTINGS))
602 {
603 String editUsername = (String) paramMap.get("username");
604
605 if (editUsername == null)
606 {
607 serviceNode.setAttribute("operation", "");
608 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_USERNAME_NOT_SPECIFIED));
609 return result;
610 }
611
612 if (!editUsername.equals(username))
613 {
614 serviceNode.setAttribute("operation", LOGIN);
615 GSXML.addError(this.doc, result, _errorMessageMap.get(ERROR_NOT_AUTHORISED));
616 return result;
617 }
618 int error = addUserInformationToNode(editUsername, serviceNode);
619 if (error != NO_ERROR)
620 {
621 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
622 }
623 }
624 else if (op.equals(PERFORM_RESET_PASSWORD))
625 {
626 String passwordResetUser = (String) paramMap.get("username");
627
628 String newPassword = UUID.randomUUID().toString();
629 newPassword = newPassword.substring(0, newPassword.indexOf("-"));
630
631 String email = retrieveDataForUser(passwordResetUser, "email");
632 String from = "[email protected]";
633 String host = request.getAttribute("remoteAddress");
634
635 //TODO: FINISH THIS
636 }
637 else if (op.equals(REGISTER))
638 {
639 if(_recaptchaPublicKey != null && _recaptchaPrivateKey != null)
640 {
641 Element recaptchaElem = this.doc.createElement("recaptcha");
642 recaptchaElem.setAttribute("publicKey", _recaptchaPublicKey);
643 recaptchaElem.setAttribute("privateKey", _recaptchaPrivateKey);
644 result.appendChild(recaptchaElem);
645 }
646 }
647 else if (op.equals(PERFORM_DELETE_USER))
648 {
649 String usernameToDelete = (String) paramMap.get("username");
650 int error = removeUser(usernameToDelete);
651 if (error != NO_ERROR)
652 {
653 GSXML.addError(this.doc, result, _errorMessageMap.get(error));
654 }
655 addUserInformationToNode(null, serviceNode);
656 serviceNode.setAttribute("operation", LIST_USERS);
657 }
658
659 return result;
660 }
661
662 public int checkUsernameAndPassword(String username, String password)
663 {
664 int uResult = checkUsername(username);
665 int pResult = checkPassword(password);
666
667 return (uResult != NO_ERROR ? uResult : (pResult != NO_ERROR ? pResult : NO_ERROR));
668 }
669
670 public int checkUsername(String username)
671 {
672 //Check the given user name
673 if ((username == null) || (username.length() < 2) || (username.length() > 30) || (!(Pattern.matches("[a-zA-Z0-9//_//.]+", username))))
674 {
675 return ERROR_INVALID_USERNAME;
676 }
677 return NO_ERROR;
678 }
679
680 public int checkPassword(String password)
681 {
682 //Check the given password
683 if ((password == null) || (password.length() < 3) || (password.length() > 8) || (!(Pattern.matches("[\\p{ASCII}]+", password))))
684 {
685 return ERROR_INVALID_PASSWORD;
686 }
687 return NO_ERROR;
688 }
689
690 public static String hashPassword(String password)
691 {
692 String hashedPassword = null;
693 try
694 {
695 MessageDigest digest = MessageDigest.getInstance("SHA-1");
696 digest.reset();
697 hashedPassword = new String(digest.digest(password.getBytes("US-ASCII"))); // toHex after using ASCII charset will result in acceptable length of hex string
698 hashedPassword = toHex(hashedPassword); // this conversion is required to avoid the strange error of login failure on some legal password strings
699 }
700 catch (Exception ex)
701 {
702 ex.printStackTrace();
703 }
704 return hashedPassword;
705 }
706
707
708
709 // This method can also be used for printing out the password in hex (in case
710 // the password used the UTF-8 Charset), or the hex values in any unicode string.
711 // From http://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
712 public static String toHex(String arg) {
713 try {
714 return String.format("%x", new BigInteger(arg.getBytes("US-ASCII"))); // set to same charset as used by hashPassword
715 } catch (Exception e) { // UnsupportedEncodingException
716 e.printStackTrace();
717 }
718 return "Unable to print";
719 }
720
721
722 private void checkAdminUserExists()
723 {
724 if (_derbyWrapper == null)
725 {
726 openDatabase();
727 }
728
729 UserQueryResult userQueryResult = _derbyWrapper.findUser(null, null);
730 closeDatabase();
731
732 if (userQueryResult != null)
733 {
734 Vector userInfo = userQueryResult.users;
735
736 boolean adminFound = false;
737 for (int i = 0; i < userQueryResult.getSize(); i++)
738 {
739 if (((UserTermInfo) userInfo.get(i)).groups != null && ((UserTermInfo) userInfo.get(i)).groups.matches(".*\\badministrator\\b.*"))
740 {
741 adminFound = true;
742 }
743 }
744
745 if (!adminFound)
746 {
747 addUser("admin", "admin", "administrator", "true", "Change the password for this account as soon as possible", "");
748 }
749 }
750
751 closeDatabase();
752 }
753
754 private boolean openDatabase()
755 {
756 _derbyWrapper = new DerbyWrapper();
757
758 // 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
759 String usersDB_dir = this.site_home + File.separatorChar + "etc" + File.separatorChar + "usersDB";
760 File usersDB_file = new File(usersDB_dir);
761 if (!usersDB_file.exists())
762 {
763 String etc_dir = this.site_home + File.separatorChar + "etc";
764 File etc_file = new File(etc_dir);
765 if (!etc_file.exists())
766 {
767 boolean success = etc_file.mkdir();
768 if (!success)
769 {
770 logger.error("Couldn't create the etc dir under " + this.site_home + ".");
771 return false;
772 }
773 }
774 _derbyWrapper.connectDatabase(usersDB_dir, true);
775 _derbyWrapper.createDatabase();
776 }
777 else
778 {
779 _derbyWrapper.connectDatabase(usersDB_dir, false);
780 }
781 return true;
782 }
783
784 private void closeDatabase()
785 {
786 if (_derbyWrapper != null)
787 {
788 _derbyWrapper.closeDatabase();
789 _derbyWrapper = null;
790 }
791 }
792
793 private int addUserInformationToNode(String username, Element serviceNode)
794 {
795 if (_derbyWrapper == null)
796 {
797 openDatabase();
798 }
799
800 UserQueryResult userQueryResult = _derbyWrapper.findUser(username, null);
801 closeDatabase();
802
803 if (userQueryResult != null)
804 {
805 Element user_node = getUserNode(userQueryResult);
806 serviceNode.appendChild(user_node);
807 closeDatabase();
808 return NO_ERROR;
809 }
810
811 closeDatabase();
812 return ERROR_COULD_NOT_GET_USER_INFO;
813 }
814
815 private int removeUser(String username)
816 {
817 if (username == null)
818 {
819 return ERROR_USERNAME_NOT_SPECIFIED;
820 }
821
822 if (_derbyWrapper == null)
823 {
824 openDatabase();
825 }
826
827 boolean success = _derbyWrapper.deleteUser(username);
828 closeDatabase();
829
830 if (success)
831 {
832 return NO_ERROR;
833 }
834
835 return ERROR_REMOVING_USER;
836 }
837
838 private int addUser(String newUsername, String newPassword, String newGroups, String newStatus, String newComment, String newEmail)
839 {
840 if (_derbyWrapper == null)
841 {
842 openDatabase();
843 }
844
845 newGroups = newGroups.replaceAll(" ", "");
846
847 //Check if the user already exists
848 UserQueryResult userQueryResult = _derbyWrapper.findUser(newUsername, null);
849 if (userQueryResult != null)
850 {
851 closeDatabase();
852 return ERROR_USER_ALREADY_EXISTS;
853 }
854 else
855 {
856 System.err.println("ADDING " + newUsername + " " + newPassword);
857 boolean success = _derbyWrapper.addUser(newUsername, newPassword, newGroups, newStatus, newComment, newEmail);
858 if (!success)
859 {
860 closeDatabase();
861 return ERROR_ADDING_USER;
862 }
863 }
864 closeDatabase();
865 return NO_ERROR;
866 }
867
868 private boolean checkUserExists(String username)
869 {
870 if (_derbyWrapper == null)
871 {
872 openDatabase();
873 }
874
875 try
876 {
877 UserQueryResult result = _derbyWrapper.findUser(username);
878
879 if (result != null)
880 {
881 return true;
882 }
883 else
884 {
885 return false;
886 }
887
888 }
889 catch (Exception ex)
890 {
891 return false;
892 }
893 finally
894 {
895 closeDatabase();
896 }
897 }
898
899 private String retrieveDataForUser(String username, String dataType)
900 {
901 if (_derbyWrapper == null)
902 {
903 openDatabase();
904 }
905
906 String password = null;
907
908 try
909 {
910 UserQueryResult result = _derbyWrapper.findUser(username);
911 Vector userInfo = result.users;
912
913 for (int i = 0; i < result.getSize(); i++)
914 {
915 if (dataType.equals("password"))
916 {
917 return ((UserTermInfo) userInfo.get(i)).password;
918 }
919 else if (dataType.equals("groups"))
920 {
921 return ((UserTermInfo) userInfo.get(i)).groups;
922 }
923 else if (dataType.equals("status"))
924 {
925 return ((UserTermInfo) userInfo.get(i)).accountstatus;
926 }
927 else if (dataType.equals("comment"))
928 {
929 return ((UserTermInfo) userInfo.get(i)).comment;
930 }
931 else if (dataType.equals("email"))
932 {
933 return ((UserTermInfo) userInfo.get(i)).email;
934 }
935 }
936 }
937 catch (Exception ex)
938 {
939 ex.printStackTrace();
940 }
941
942 closeDatabase();
943 return password;
944 }
945
946 private Element getUserNode(UserQueryResult userQueryResult)
947 {
948 Element user_list_node = this.doc.createElement(GSXML.USER_NODE_ELEM + "List");
949
950 Vector userInfo = userQueryResult.users;
951
952 for (int i = 0; i < userQueryResult.getSize(); i++)
953 {
954 Element user_node = this.doc.createElement(GSXML.USER_NODE_ELEM);
955 String username = ((UserTermInfo) userInfo.get(i)).username;
956 String groups = ((UserTermInfo) userInfo.get(i)).groups;
957 String accountstatus = ((UserTermInfo) userInfo.get(i)).accountstatus;
958 String comment = ((UserTermInfo) userInfo.get(i)).comment;
959 String email = ((UserTermInfo) userInfo.get(i)).email;
960 user_node.setAttribute("username", username);
961 user_node.setAttribute("groups", groups);
962 user_node.setAttribute("status", accountstatus);
963 user_node.setAttribute("comment", comment);
964 user_node.setAttribute("email", email);
965
966 user_list_node.appendChild(user_node);
967 }
968 return user_list_node;
969 }
970
971 private Element getCollectList(String collect)
972 {
973 Element collect_list_node = this.doc.createElement(GSXML.COLLECTION_ELEM + "List");
974 File[] collect_dir = (new File(collect)).listFiles();
975 if (collect_dir != null && collect_dir.length > 0)
976 {
977 for (int i = 0; i < collect_dir.length; i++)
978 {
979 if (collect_dir[i].isDirectory() && (!collect_dir[i].getName().startsWith(".svn")))
980 {
981 Element collect_node = this.doc.createElement(GSXML.COLLECTION_ELEM);
982 collect_node.setAttribute("name", collect_dir[i].getName());
983 collect_list_node.appendChild(collect_node);
984 }
985 }
986 }
987 return collect_list_node;
988 }
989}
Note: See TracBrowser for help on using the repository browser.